singularity-forge/docs/dev/drafts/sf-ace-patterns.md
Mikael Hugo 288a2a5fd7 docs(sf-ace): park SF→ACE pattern reference under docs/dev/drafts/
Promotes the .draft stub into a fuller 183-line reference covering six
SF patterns (Preferences, PDD, UOK Gates, Notifications, Skills-as-
Contracts, Idempotency) with SF source paths and ACE adoption notes.

Filed under docs/dev/drafts/ with a STATUS: Draft header — no active
consumer yet. SF's own priorities take precedence until ACE Coder
maintainers pull on convergence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 21:30:34 +02:00

12 KiB

SF → ACE Coder Pattern Reference

Status: Draft — no active consumer. Parked here for when ACE Coder maintainers pull on convergence; SF's own priorities take precedence until then.

Purpose: Document six proven SF patterns that ACE Coder can adopt to stay conceptually compatible without collapsing the Forge/ACE split. Each pattern includes its SF implementation, the value it protects, and a concrete adoption path for ACE.

Consumer: ACE Coder maintainers and SF architects evaluating convergence points.


1. Preferences

What It Is

A layered, mergeable preference system that combines global user settings, project-level overrides, profile defaults, and mode defaults into a single effective configuration. SF preferences are stored as pure YAML (preferences.yaml) — no frontmatter markers — and support worktree-aware resolution so that linked worktrees read from the main worktree's project prefs.

SF Implementation

  • Source: src/resources/extensions/sf/preferences.js
  • Key behaviors:
    • Global (~/.sf/preferences.yaml) + project (.sf/preferences.yaml) merge with project winning.
    • Token profiles (budget, speed, quality) inject low-priority defaults for models and phase skips.
    • Mode defaults (solo vs team) set context thresholds, timeouts, and parallel agent limits.
    • Worktree-aware projectPrefsRoot() resolves the main worktree when running inside a git worktree.
  • Validation: preferences-validation.js enforces schema and emits warnings for deprecated fields.

ACE Adoption Path

  1. Adopt a two-layer (global + workspace) YAML preference file with explicit merge semantics.
  2. Introduce mode profiles (solo/team) that set safe defaults for context limits, timeouts, and parallelism.
  3. Add validation at load time so bad prefs fail fast with a clear warning rather than silent misbehavior.
  4. Keep preferences as pure data; avoid embedding logic (e.g., callback hooks) inside the preference file itself.

Cross-References

  • docs/SPEC_FIRST_TDD.md — Iron Law on preference-driven run control.
  • docs/adr/0000-purpose-to-software-compiler.md — Run-control policy derived from confidence, risk, and reversibility.

2. PDD (Purpose-Driven Development)

What It Is

Before any non-trivial implementation, SF requires eight structured fields — the PDD — that answer why the behavior exists, who uses it, and what breaks if it is wrong. PDD is the gate that blocks implementation until purpose is clear.

SF Implementation

  • Spec: docs/SPEC_FIRST_TDD.md and docs/adr/0000-purpose-to-software-compiler.md
  • Key fields:
    1. Purpose — why this behavior exists.
    2. Consumer — who calls it in production.
    3. Contract — observable behavior boundary.
    4. Failure Boundary — failures that must be contained or surfaced.
    5. Evidence — proof gathered so far.
    6. Non-Goals — what is intentionally not solved here.
    7. Invariants — rules that remain true across iterations.
    8. Assumptions — uncertain facts and how to falsify them.
  • Enforcement: Doctor checks reject malformed planning artifacts. Exported symbols must carry a JSDoc Purpose: line.

ACE Adoption Path

  1. Add a PDD gate to the planning phase (before coding starts) that requires at least Purpose, Consumer, Contract, and Evidence.
  2. Require every exported function to open with a JSDoc block containing Purpose: and Consumer:.
  3. Treat tests as the spec — write the failing test for the correct behavior before fixing a bug.
  4. Use the PDD fields as the schema for autonomous checkpoints so the solver can verify intent was preserved.

Cross-References

  • docs/adr/0000-purpose-to-software-compiler.md — Canonical PDD/TDD gate definition.
  • docs/adr/0077-spec-runtime-evidence-schema-separation.md — Separating spec (immutable intent) from runtime (mutable state) and evidence (audit trail).

3. UOK Gates

What It Is

A structured, extensible post-unit verification pipeline. Every gate implements a uniform execution contract, emits durable audit events, and respects a per-failure-class retry matrix. Gates run in parallel where possible and are protected by circuit breakers.

SF Implementation

  • Source: src/resources/extensions/sf/uok/gate-runner.js
  • Key behaviors:
    • UokGateRunner registers gates by id and validates them with contracts.js.
    • GateResult is a sealed union: outcome (pass | fail | retry | manual-attention), failureClass, rationale, optional findings and recommendation.
    • Retry matrix: timeout gets 2 retries; execution/artifact/verification/git get 1; policy/input/manual-attention get 0.
    • Circuit breaker per gate: closedopen after failure threshold, cooldown with exponential backoff, then half-open.
    • Durable audit: every gate run is persisted to SQLite (gate_runs) and emitted as a trace event.
  • Implemented gates: SecurityGate, CostGuardGate, OutcomeLearningGate, MultiPackageGate, ChaosMonkey (opt-in).

ACE Adoption Path

  1. Replace ad-hoc post-task checks with a gate registry that accepts new gates as single files + a registration line.
  2. Standardize gate output to outcome + failureClass + rationale so downstream automation can act on it.
  3. Add a retry matrix per failure class rather than hard-coding retries per check.
  4. Introduce circuit breakers on expensive or flaky gates so one bad gate does not stall the entire pipeline.

Cross-References

  • docs/adr/0075-uok-gate-architecture.md — Full gate contract, retry matrix, and circuit-breaker design.
  • docs/adr/0076-uok-memory-integration.md — Gate failures enriched with historical memory context.

4. Notifications

What It Is

A durable, classified notification store that survives context resets and session restarts. Notifications carry noticeKind metadata (system_notice, tool_notice, blocking_notice, user_visible) so renderers can group and style them without parsing message text. Deduplication uses dedupe_key with a time window, and noisy status patterns are suppressed.

SF Implementation

  • Source: src/resources/extensions/sf/notification-store.js and notification-overlay.js
  • Key behaviors:
    • Persisted to .sf/notifications.jsonl with a schema version and a max-entry rotation cap (500).
    • NOTICE_KIND classification separates automated workflow notices from user-visible messages.
    • Deduplication: rows with the same dedupe_key within DURABLE_DEDUP_WINDOW_MS merge into one row with repeatCount.
    • Actionable kinds (action_required, approval_request, blocker, error, terminal) never merge.
    • Overlay: scrollable history panel with severity filtering, toggled via Ctrl+Alt+N.

ACE Adoption Path

  1. Add a noticeKind field to all notification events so the UI can distinguish system chatter from user-facing messages.
  2. Persist notifications to disk (JSONL or SQLite) so they survive restarts and can be reviewed later.
  3. Implement deduplication with dedupe_key rather than string matching to avoid spam.
  4. Never render automated notices as if the user typed them.

Cross-References

  • docs/product-specs/notification-source-hygiene.md — Source classification and trust preservation.
  • docs/adr/0002-sf-schedule-pull-based.md — Why SF avoids background notification daemons.

5. Skills-as-Contracts

What It Is

SF skills are markdown files with YAML frontmatter that act as invocation contracts. The frontmatter declares permission profiles, side-effect awareness, and invocation policy so the loader can enforce safety without loading the full skill body into model context.

SF Implementation

  • Source: src/resources/extensions/sf/skills/frontmatter.js
  • Key behaviors:
    • Required fields: name, description.
    • SF-specific optional fields: user-invocable, model-invocable, side-effects, permission-profile (restricted | normal | trusted | unrestricted), triggers, max-activations, locked.
    • buildSkillRecord normalizes frontmatter into a typed record with safe defaults (e.g., permissionProfile defaults to normal).
    • validateSkillFrontmatter rejects invalid permission profiles.
  • Skill loading: preferences-skills.js resolves skill references against the effective preference policy (always_use_skills, prefer_skills, avoid_skills, skill_rules).

ACE Adoption Path

  1. Require every skill/tool to declare its permission-profile and side-effects in frontmatter.
  2. Gate skill invocation on the profile: restricted skills require explicit user approval; unrestricted skills run automatically.
  3. Use the skill record as the contract: if the frontmatter says side-effects: none, the skill must not write to disk or mutate state.
  4. Add a skill preference layer so users can always_use, prefer, or avoid specific skills without editing prompts.

Cross-References

  • docs/adr/0000-purpose-to-software-compiler.md — Skills are contracts, not prompts.
  • docs/SPEC_FIRST_TDD.md — JSDoc purpose convention (same contract discipline applied to code).

6. Idempotency

What It Is

Every durable write path in SF is designed to be safe to call multiple times. DB operations use upserts, runtime record writes are versioned, and crash recovery assumes the last operation may have partially succeeded.

SF Implementation

  • Source: src/resources/extensions/sf/uok/unit-runtime.js (runtime records), src/resources/extensions/sf/db-writer.js (DB upserts)
  • Key behaviors:
    • writeUnitRuntimeRecord merges with previous state on disk rather than blindly overwriting; recoveryAttempts/retryCount are coalesced safely.
    • reconcileDurableCompleteUnitRuntimeRecords and reconcileStaleCompleteSliceRecords clear runtime records only when durable artifacts (DB + SUMMARY.md) prove completion, preventing double-recovery.
    • DB writer uses upsertRequirement, upsertDecision, upsertTaskPlanning — safe to retry.
    • clearRunawayRecoveredRuntimeRecords is idempotent: clearing an already-cleared record is a no-op.
  • Tests: tests/crash-recovery.test.ts validates "prevents double-recovery (idempotent)"; tests/uok-scheduler.test.mjs validates token cancellation idempotency.

ACE Adoption Path

  1. Make all state-transition writes upserts or conditional updates rather than blind INSERT/DELETE.
  2. Version runtime records so partial writes can be detected and resumed safely.
  3. In crash recovery, verify durable artifacts (files, DB rows) before assuming the previous attempt failed.
  4. Add adversarial tests that call the same write path twice and assert the second call is a no-op or produces the same result.

Cross-References

  • docs/adr/0077-spec-runtime-evidence-schema-separation.md — Spec immutability + runtime mutability separation.
  • docs/adr/0079-autonomous-solver-executor-separation.md — Solver pass is a separate, retry-safe observer.

Summary Table

Pattern SF Source ACE Adoption Priority Key ADR
Preferences preferences.js High ADR-0000
PDD SPEC_FIRST_TDD.md Critical ADR-0000, ADR-0077
UOK Gates uok/gate-runner.js Medium ADR-0075, ADR-0076
Notifications notification-store.js Medium Notification Hygiene Spec
Skills-as-Contracts skills/frontmatter.js High ADR-0000
Idempotency uok/unit-runtime.js, db-writer.js Critical ADR-0077, ADR-0079

This document is a convergence artifact. It does not mandate ACE adoption; it documents proven patterns so both systems can share vocabulary and reduce integration friction.