diff --git a/.sf/REQUIREMENTS.md b/.sf/REQUIREMENTS.md index 827a6765d..8c47e0c10 100644 --- a/.sf/REQUIREMENTS.md +++ b/.sf/REQUIREMENTS.md @@ -942,3 +942,47 @@ ADR-0000 declares SF a **purpose-to-software compiler**. R036–R040 codify that - Supporting slices: M039/S07, M048/S05 - Validation: unmapped - Notes: Operator's codex tool stays available unchanged — R075 is the SF-internal capability that runs without operator. Model-router exclusion rule: skip worker model + same vendor family. Self-feedback shape: `kind='adversarial-finding'`, severity from review verdict, occurredIn anchors review target. R066 firewall consumes high-severity findings as a quarantine signal. Budget governance: per-cycle token cap (e.g. 5% of unit token budget) + per-week cap (e.g. 100 reviews) configurable via preferences. System-lane task (R057) so reviews run concurrent with unit execution rather than serial. Sibling to R053 (repeated self-feedback kind detector) — when same finding kind recurs N times, escalates to operator notification. + +### R087 — Typed PDD Contracts via engine-types.js +- Class: capability +- Status: active +- Description: Per ADR-0000, the 8 PDD fields (Purpose, Consumer, Contract, FailureBoundary, Evidence, NonGoals, Invariants, Assumptions) and the 7-dimension RunControlPolicy (confidence, risk, reversibility, blastRadius, cost, legal, customerImpact) become TypeScript interfaces in engine-types.js (currently empty stub: export {};). Per ADR-0075, GateResult shape is also exported from engine-types.js. All engine/policy/validator/planner code imports these typed contracts as the canonical leaf-node — turns ADR-0000 prose into compile-time contracts. plan-milestone/plan-slice/plan-task tool handlers validate input against PDDFields; UokGateRunner consumes GateResult; routing policy reads RunControlPolicy. +- Why it matters: ADR-0000 specifies the 8 PDD fields + run-control policy but they exist only in prose. Codex doctrine review 2026-05-17: "PDD eight-field gate not enforced by plan-milestone or plan-slice." R036-R040 (M030) cover data-level anchoring; R087 adds the typed schema fix at the code level. Pairs with R086 (dormant code triage) since engine-types.js IS one of the dormant files M058 wires in. +- Source: codex-doctrine-review-2026-05-17 + supervisor-deep-audit-2026-05-17 +- Primary owning slice: M058/S05 +- Supporting slices: M030/S01 +- Validation: unmapped +- Notes: engine-types.js header explicitly says "All engine/policy interfaces depend on these types." File is purpose-built for this content; stub never filled. M030 R036 purposeAnchor data-level enforcement gets stronger when backed by typed PDDFields. Compile-time at import boundary; runtime at tool input boundary. + +### R088 — Pre-Removal Test-Import Safety Gate +- Class: capability +- Status: active +- Description: UokGate per ADR-0075 (type=policy, id=removal-safety) that fires BEFORE any file removal proposed by the autonomous loop or triggered by R086 dormant-code triage. Greps tests/* for static + dynamic-import references; scans file content for external-integration env-var signatures (TWILIO_, ELEVENLABS_, STRIPE_, DISCORD_, SENDGRID_, etc.). Returns outcome=manual-attention with cited test paths or env-var matches when found. +- Why it matters: Operator-supervisor 2026-05-17 removed web/app/api/voice/ that turned out to be Twilio IVR on-call infrastructure with src/tests/integration/web-voice-ivr-contract.test.ts as paired contract test. R086 dormant-code-triage catches after removal; R088 prevents BEFORE. Without R088, autonomous removal repeats the same operator mistake at scale. +- Source: operator-supervisor-mistake-recovered-2026-05-17 +- Primary owning slice: M058/S12 +- Supporting slices: M048/S05 +- Validation: unmapped +- Notes: Sibling to R082 (drift detector UokGate). M048/S05 (smoke-fixture + last-green ledger) catches destructive autonomous changes in general; R088 specifically guards removal-safety. + +### R089 — Migrate Voice IVR On-Call Infra to Central Cloud Ops +- Class: capability +- Status: active +- Description: Migrate web/app/api/voice/ + voice/prompt/ routes + src/tests/integration/web-voice-ivr-contract.test.ts (Twilio IVR + ElevenLabs voice synthesis + on-call paging) out of SF to central cloud-ops repo/service. SF is per-project autonomous compiler (ADR-0000); operator-paging infra is org-level. Migrate first, verify cloud-ops endpoint, then remove from SF (gated by R088 pre-removal safety gate). +- Why it matters: Current placement in SF is historical drift. Voice infrastructure does not belong in a per-project compiler codebase. Migration to the right home + removal from SF is the correct fix. +- Source: operator-direction-2026-05-17 +- Primary owning slice: M058/S13 +- Supporting slices: M058/S14 +- Validation: unmapped +- Notes: Files: web/app/api/voice/route.ts, web/app/api/voice/prompt/route.ts, src/tests/integration/web-voice-ivr-contract.test.ts, related env-var docs (TWILIO_, ELEVENLABS_). Removal from SF gated by R089/S13 (migration done) AND R088 (pre-removal safety gate green). + +### R090 — Planning-Execute Lane Split +- Class: capability +- Status: active +- Description: Two concurrent lanes in the autonomous dispatcher: PLANNING (discuss/plan/research/reassess for ANY milestone, writes only to .sf/+DB, file-conflict-free) and EXECUTE (execute-task + complete-*, exclusive worktree, N=1). Planning queue stays ahead so execute never waits on plan gating. Subset of R046 (full multi-unit lanes via M033); much smaller blast radius, ships much earlier. +- Why it matters: Today execute waits ~10-20 min for next plan-slice to finish before starting next execute. Splitting lanes ~2x throughput on planning-heavy slices. Safer than R046 full parallel; only planning runs concurrent with execute, never two executes. +- Source: operator-direction-2026-05-17 +- Primary owning slice: M059/S01 +- Supporting slices: M059/S02, M059/S03 +- Validation: unmapped +- Notes: Planning writes bounded to .sf/{sf.db, runtime/, milestones/}; never source. Permission-profile enforces. R082 drift detector watches the boundary. M033/R046 eventually generalizes; R090 is the safe near-term cut. diff --git a/docs/SPEC_FIRST_TDD.md b/docs/SPEC_FIRST_TDD.md index c9408ed82..81b28e426 100644 --- a/docs/SPEC_FIRST_TDD.md +++ b/docs/SPEC_FIRST_TDD.md @@ -276,4 +276,4 @@ If a task cannot be described this way, it is underspecified. - GitHub Spec Kit — spec-first authoring patterns. - Ousterhout, *A Philosophy of Software Design* — deep modules, contract pattern. - Trail of Bits — anti-rationalisation rules. -- ACE — original Iron Law / Purpose Gate framing this doc adapts. +- Iron Law / Purpose Gate framing — concept adapted from external prior art (originally an ACE concept; preserved here as SF doctrine independent of ACE runtime). diff --git a/docs/dev/ADR-014-singularity-knowledge-and-agent-platform.md b/docs/dev/ADR-014-singularity-knowledge-and-agent-platform.md index 7ce82970d..a5c5a7e72 100644 --- a/docs/dev/ADR-014-singularity-knowledge-and-agent-platform.md +++ b/docs/dev/ADR-014-singularity-knowledge-and-agent-platform.md @@ -1,7 +1,7 @@ # ADR-014: Singularity Knowledge + Agent Platform stack **Date**: 2026-04-29 -**Status:** proposed (deferred; Phase 4 cancelled per ADR-019). No active implementation work; future federation work uses Singularity Memory primitive per ADR-012. +**Status:** proposed (deferred; Phase 4 cancelled per ADR-019). No active implementation work; future federation work uses Singularity Memory primitive per ADR-012; SF-first amendment 2026-05-17 — see R084 **Revised**: 2026-05-02 — Phase 4 cancelled, see [ADR-019](./ADR-019-workspace-vm-convergence.md) ## Context @@ -104,6 +104,8 @@ Phase 4 was originally planned as a "central persistent-agent runtime" built on **What replaced it:** Persistent agents now live as **Firecracker VM snapshots managed by ACE**'s orchestration layer. A "persistent agent" is a named VM snapshot: restore it, and the agent wakes with its full memory and context intact. singularity-memory's scope is now strictly the knowledge layer (Phases 0–3). See ADR-019 § "ADR-014 Phase 4 is reassigned" for the authoritative statement. +> **2026-05-17 amendment — SF-first.** ACE is not currently operational; SF runs standalone. The Phase 4 reassignment to ACE's Firecracker VMs is suspended. Persistent-agent capability (code-reviewer, memory-curator, security-auditor, build-watch) re-homes in SF per R084 (Persistent Agent Runtime in SF). When ACE becomes operational, the original reassignment can be revisited. + ### Historical: Original Phase 4 Plan > *The content below is the original Phase 4 design, preserved as a historical record. It is **not** the current plan.* diff --git a/docs/dev/ADR-019-workspace-vm-convergence.md b/docs/dev/ADR-019-workspace-vm-convergence.md index 9e5c3d3e9..fc2d228f7 100644 --- a/docs/dev/ADR-019-workspace-vm-convergence.md +++ b/docs/dev/ADR-019-workspace-vm-convergence.md @@ -1,6 +1,8 @@ # ADR-019: Workspace VM Convergence Architecture -**Status:** Proposed +> **2026-05-17 reframe — SF-first.** ACE exists as a peer project but is not currently operational. SF must work standalone. The convergence described here is forward-looking; SF's near-term roadmap does NOT depend on ACE being available. Phase 4 persistent-agent reassignment to ACE (originally written here) is suspended — persistent-agent capability is re-homed in SF per R084 (Persistent Agent Runtime in SF). When ACE becomes operational, this ADR's convergence path can be reactivated. + +**Status:** Proposed — convergence forward-looking; SF-first per 2026-05-17 banner **Date:** 2026-05-01 **Revised:** 2026-05-02 — wire-format scope superseded by ADR-020 **Deciders:** Mikael Hugo diff --git a/docs/dev/ADR-020-internal-wire-architecture.md b/docs/dev/ADR-020-internal-wire-architecture.md index 62bb8d962..3d23f0fda 100644 --- a/docs/dev/ADR-020-internal-wire-architecture.md +++ b/docs/dev/ADR-020-internal-wire-architecture.md @@ -9,6 +9,8 @@ ## Context +> **2026-05-17 note — SF-first.** ACE is not currently operational. The wire-format table rows that touch ACE (ACE host → ACE tools, ACE host → singularity-memory, SF → ACE worker, ACE worker VM → host, Claude Code → ACE) describe the forward-looking architecture and are not active. SF's current internal wire is @singularity-forge/rpc-client (stdio JSON-RPC) for SF↔SF child processes; first-party SF→singularity-memory remains gRPC when wired. ACE rows reactivate when ACE becomes operational. + The first-party services that make up the singularity stack — SF (`singularity-forge`), ACE (`ace-coder`), `singularity-memory`, and the future `singularity-*` services — need a wire format for talking to each @@ -89,15 +91,15 @@ other services — it does not expose a gRPC API of its own. This is the canonical reference for which wire goes where. -| Caller | Callee | Wire | Why | -|--------|--------|------|-----| -| ACE host → ACE tools | in-process Python imports | function call | type-safe, zero overhead | -| ACE host → singularity-memory | typed Python client (gen from Go API) | HTTP/gRPC | typed, fast, refactorable | -| SF → singularity-memory | typed TS client (gen from Go API) | HTTP/gRPC | same, in TS | -| SF → ACE worker | existing JSON-RPC stdio (`rpc-client`) | stdio JSON-RPC | already in production, language-agnostic | -| ACE worker VM → host | direct gRPC over tailnet | gRPC | typed, low-latency | -| Claude Code / Cursor → singularity-memory | MCP façade | MCP | external tool, no shared types | -| Claude Code → ACE | MCP façade (temporary) | MCP | external coder helping build, until self-hosting | +| Caller | Callee | Wire | Why | Status | +|--------|--------|------|-----|--------| +| ACE host → ACE tools | in-process Python imports | function call | type-safe, zero overhead | Future (ACE not operational) | +| ACE host → singularity-memory | typed Python client (gen from Go API) | HTTP/gRPC | typed, fast, refactorable | Future (ACE not operational) | +| SF → singularity-memory | typed TS client (gen from Go API) | HTTP/gRPC | same, in TS | Active | +| SF → ACE worker | existing JSON-RPC stdio (`rpc-client`) | stdio JSON-RPC | already in production, language-agnostic | Future (ACE not operational) | +| ACE worker VM → host | direct gRPC over tailnet | gRPC | typed, low-latency | Future (ACE not operational) | +| Claude Code / Cursor → singularity-memory | MCP façade | MCP | external tool, no shared types | Active | +| Claude Code → ACE | MCP façade (temporary) | MCP | external coder helping build, until self-hosting | Future (ACE not operational) | --- diff --git a/docs/dev/drafts/sf-ace-patterns.md b/docs/dev/drafts/sf-ace-patterns.md index 2baf125a4..7d6cf5a34 100644 --- a/docs/dev/drafts/sf-ace-patterns.md +++ b/docs/dev/drafts/sf-ace-patterns.md @@ -1,6 +1,6 @@ # 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. +**Status:** Draft — no active consumer. Parked here for when ACE Coder maintainers pull on convergence; SF's own priorities take precedence until then. SF-first reaffirmed 2026-05-17 (ACE not currently operational). **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. diff --git a/docs/records/2026-05-07-cli-agent-code-survey.md b/docs/records/2026-05-07-cli-agent-code-survey.md index bfd63e3df..b45aec860 100644 --- a/docs/records/2026-05-07-cli-agent-code-survey.md +++ b/docs/records/2026-05-07-cli-agent-code-survey.md @@ -1,5 +1,7 @@ # SF + ACE Full-Stack Reference Survey — 2026-05-07 +> **Historical record — annotated 2026-05-17.** This survey assumed ACE was operational at the time of writing. Per 2026-05-17 operator decision, SF runs standalone; ACE is not currently operational. Survey content is preserved as historical context; do not treat its ACE references as current architecture. + This record compares local coding-agent, orchestration, retrieval, model, and platform-engineering references under `/home/mhugo/code/` plus selected indexed public references against the intended SF+ACE full-stack flow. It is planning diff --git a/docs/records/2026-05-07-strategy-alignment.md b/docs/records/2026-05-07-strategy-alignment.md index ca0610709..c535d5b95 100644 --- a/docs/records/2026-05-07-strategy-alignment.md +++ b/docs/records/2026-05-07-strategy-alignment.md @@ -1,5 +1,7 @@ # Strategy Alignment — 2026-05-07 +> **Historical record — annotated 2026-05-17.** This survey assumed ACE was operational at the time of writing. Per 2026-05-17 operator decision, SF runs standalone; ACE is not currently operational. Survey content is preserved as historical context; do not treat its ACE references as current architecture. + Aligned the top-level SF docs and roadmap framing around the current architecture and end goal. ## Canonical direction diff --git a/docs/records/index.md b/docs/records/index.md index af0cb8e6c..3014df4f5 100644 --- a/docs/records/index.md +++ b/docs/records/index.md @@ -7,5 +7,5 @@ Repo-memory audits, decision ledgers, context-gardening notes, and records-keepe | Date | Note | Summary | |------|------|---------| | 2026-05-01 | [repo-vcs and notifications](./2026-05-01-repo-vcs-and-notifications.md) | repo-vcs skill landed; notification specs drafted; JSDoc annotations added; placeholder docs filled | -| 2026-05-07 | [SF + ACE full-stack reference survey](./2026-05-07-cli-agent-code-survey.md) | repo-wise map of coding agents, spec systems, orchestration systems, retrieval tools, model references, and platform/golden-path systems; priority pulls are execution permissions, typed machine events, DB-first state, generated human exports, trust gating, orchestration, cumulative diffs, eval pipelines, and MCP-client-only lifecycle hardening | +| 2026-05-07 | [SF + ACE full-stack reference survey](./2026-05-07-cli-agent-code-survey.md) | repo-wise map of coding agents, spec systems, orchestration systems, retrieval tools, model references, and platform/golden-path systems; priority pulls are execution permissions, typed machine events, DB-first state, generated human exports, trust gating, orchestration, cumulative diffs, eval pipelines, and MCP-client-only lifecycle hardening (historical; ACE not operational, SF-first per 2026-05-17) | | 2026-05-07 | [strategy alignment](./2026-05-07-strategy-alignment.md) | aligned top-level docs and roadmap framing around Forge as product, UOK as kernel, and external CLIs as sharpening inputs | diff --git a/src/resources/extensions/sf/roadmap-mutations.js b/src/resources/extensions/sf/roadmap-mutations.js deleted file mode 100644 index 15ee3de1b..000000000 --- a/src/resources/extensions/sf/roadmap-mutations.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Roadmap Mutations — shared utilities for modifying roadmap checkbox state. - * - * Extracts the duplicated "flip slice checkbox" pattern that existed in - * doctor.ts, mechanical-completion.ts, and auto-recovery.ts. - */ -import { readFileSync } from "node:fs"; -import { atomicWriteSync } from "./atomic-write.js"; -import { clearParseCache } from "./files.js"; -import { resolveMilestoneFile } from "./paths.js"; -/** - * Mark a slice as done ([x]) in the milestone roadmap. - * Idempotent — no-op if already checked or if the slice isn't found. - * - * @returns true if the roadmap was modified, false if no change was needed - */ -export function markSliceDoneInRoadmap(basePath, mid, sid) { - const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP"); - if (!roadmapFile) return false; - let content; - try { - content = readFileSync(roadmapFile, "utf-8"); - } catch { - return false; - } - // Try checkbox format first: "- [ ] **S01: Title**" - let updated = content.replace( - new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${sid}:`, "m"), - `$1[x] **${sid}:`, - ); - // If checkbox format didn't match, try prose format: "## S01: Title" -> "## S01: \u2713 Title" - if (updated === content) { - updated = content.replace( - new RegExp( - `^(#{1,4}\\s+(?:\\*{0,2})(?:Slice\\s+)?${sid}\\*{0,2}[:\\s.\\u2014\\u2013-]+\\s*)(.+)`, - "m", - ), - (match, prefix, title) => { - // Already marked done — no-op - if ( - /^[\u2713\u2705]/.test(title) || - /[\u2705]\s*$/.test(title) || - /\(Complete\)\s*$/i.test(title) - ) - return match; - return `${prefix}\u2713 ${title}`; - }, - ); - } - if (updated === content) return false; - atomicWriteSync(roadmapFile, updated); - clearParseCache(); - return true; -} -/** - * Mark a slice as not done ([ ]) in the milestone roadmap. - * Idempotent — no-op if already unchecked or if the slice isn't found. - * - * @returns true if the roadmap was modified, false if no change was needed - */ -export function markSliceUndoneInRoadmap(basePath, mid, sid) { - const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP"); - if (!roadmapFile) return false; - let content; - try { - content = readFileSync(roadmapFile, "utf-8"); - } catch { - return false; - } - const updated = content.replace( - new RegExp(`^(\\s*-\\s+)\\[x\\]\\s+\\*\\*${sid}:`, "m"), - `$1[ ] **${sid}:`, - ); - if (updated === content) return false; - atomicWriteSync(roadmapFile, updated); - clearParseCache(); - return true; -} -/** - * Mark a task as done ([x]) in the slice plan. - * Idempotent — no-op if already checked or if the task isn't found. - * - * @returns true if the plan was modified, false if no change was needed - */ -export function markTaskDoneInPlan(_basePath, planPath, tid) { - let content; - try { - content = readFileSync(planPath, "utf-8"); - } catch { - return false; - } - const updated = content.replace( - new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${tid}:`, "m"), - `$1[x] **${tid}:`, - ); - if (updated === content) return false; - atomicWriteSync(planPath, updated); - clearParseCache(); - return true; -} -/** - * Mark a task as not done ([ ]) in the slice plan. - * Idempotent — no-op if already unchecked or if the task isn't found. - * - * @returns true if the plan was modified, false if no change was needed - */ -export function markTaskUndoneInPlan(_basePath, planPath, tid) { - let content; - try { - content = readFileSync(planPath, "utf-8"); - } catch { - return false; - } - const updated = content.replace( - new RegExp(`^(\\s*-\\s+)\\[x\\]\\s+\\*\\*${tid}:`, "mi"), - `$1[ ] **${tid}:`, - ); - if (updated === content) return false; - atomicWriteSync(planPath, updated); - clearParseCache(); - return true; -}