singularity-forge/docs/exec-plans/tech-debt-tracker.md
2026-05-02 17:51:38 +02:00

4.5 KiB

Tech Debt Tracker

Notification event classification — text matching only

Impact: src/headless-events.ts classifies events (blocked, milestone-ready, auto-stopped) by regex against stderr text. Fragile: any wording change in a notification breaks classification silently.

Proposed fix: Implement structured source/kind/blocking metadata per notification-event-model.md. Update headless event parser to use typed fields.

Verification: Remove string-match classifiers; confirm headless exit-code logic still triggers correctly via integration test.

Tracked in: active/index.md — Notification Event Model


MCP workflow mutations — read-only only

Impact: External providers (Claude Code CLI, remote orchestrators) that route through MCP can query SF state but cannot advance it. sf_task_complete, sf_plan_milestone, etc. are in-process only.

Proposed fix: Extract shared handlers from native tools; expose over MCP server (ADR-008 Phase 1).

Verification: Claude Code provider session completes a task via MCP sf_task_complete and produces identical STATE.md outcome.

Tracked in: active/index.md — ADR-008 Phase 1 · ADR-008


No ADR template or generation recipes

Impact: Every ADR is hand-authored from scratch. No enforced schema means some ADRs omit falsifiers, status dates, or sequencing. No just adr recipe means the numbering is manual.

Proposed fix: Add docs/dev/ADR-TEMPLATE.md with required sections (Status, Date, Context, Options, Decision, Consequences, Falsifiers, Verification). Add just adr <number> <slug> recipe that stamps the template.

Verification: just adr 019 my-decision produces docs/dev/ADR-019-my-decision.md with all required section headings.


Parallel milestone state locking — file-based, ad-hoc

Impact: Concurrent milestone execution uses ad-hoc file locks on STATE.md and roadmap.md. Race condition possible under heavy parallelism; not blocking for serial execution (current default).

Proposed fix: SQLite database in .sf/sf.db with atomic transactions for all state mutations. Deferred to ADR-018 Phase 1+.

Verification: Two milestone workers simultaneously completing tasks produce consistent STATE.md with no lost updates.

Tracked in: ADR-018 sequencing stage 1.


write-gate BASH_READ_ONLY_RE — monolithic regex

Location: src/resources/extensions/sf/bootstrap/write-gate.ts

Impact: 30+ command patterns are encoded in a single 900-character regex. Adding a new safe command requires editing the regex inline, with no unit coverage per command. Risk of subtle regex alternation bugs.

Proposed fix: Replace with a data-driven allowlist (array of patterns with names and comments) that the gate compiles at startup. Each entry is individually testable.

Verification: write-gate.test.ts achieves per-command coverage without a single monolithic regex match test.


ADR-018 runtime — harness profiler not yet wired

Impact: repo-profiler.ts exists but is not called during any autonomous dispatch phase. The harness evolution system (ADR-018) exists only as design documentation; no runtime behavior has shipped.

Proposed fix: Wire buildRepoProfile() call into the pre-dispatch phase (Phase 1). Record result in .sf/sf.db.

Verification: After any planning milestone, .sf/sf.db contains a repo_profiles row for the current session.

Tracked in: active/index.md — ADR-018 Phase 1


Memory subsystem extraction into swappable sub-extension

Location: src/resources/extensions/sf/memory-store.ts, src/resources/extensions/sf/memory-extractor.ts, src/resources/extensions/sf/memory-relations.ts, src/resources/extensions/sf/memory-sleeper.ts

Impact: SF's memory subsystem (separate from singularity-memory, which serves hermes/ACE) is coupled directly into SF core. Plugging in a different backend — e.g. a vchord-in-docker container for local vector search — is harder than it needs to be.

Proposed fix: Extract the four files above into a sub-extension at src/resources/extensions/sf-memory/ behind a small backend interface, so SF can swap implementations without touching core.

When to do it: Defer until a real backend-swap requirement appears (e.g. SF actually needs vector search). Not blocking.

Estimated effort: Small — these files have clean module boundaries already.