Addresses self-feedback entry sf-mp4uzvcd-pazg6v
(architecture-defect:no-reflection-layer-over-self-feedback-corpus): SF
detected symptoms and triaged individual entries but had no layer that
reasoned about the corpus to recognize recurring structural patterns.
The same architectural pressure expressed itself across multiple entries
with different exact-kind strings; nothing escalated the pattern to a
class. The cognitive work fell on the operator.
This commit ships Phase 1A — the data-assembly + prompt half of the
reflection layer + an operator-driven entry point. Phase 1B (LLM dispatch
via the autonomous loop as a real unit type) lands once
sf-mp4rxkwb-l4baga (triage-not-a-first-class-unit-type) is in.
Files:
- src/resources/extensions/sf/reflection.js (new)
- assembleReflectionCorpus(basePath): bundles open + recent-resolved
self-feedback (full json), last 50 commits via git log, milestone +
slice + task state, all milestone validation verdicts, and prior
reflection report into one struct. Returns null on prerequisite
failure (DB closed) so callers downgrade gracefully.
- renderReflectionCorpusBrief(corpus): renders the corpus into a
markdown brief the LLM consumes in one turn.
- writeReflectionReport(basePath, content): persists to
.sf/reflection/<timestamp>-report.md so next pass detects "what
changed since last reflection."
- src/resources/extensions/sf/prompts/reflection-pass.md (new)
- {{include:working-directory}} prefix.
- Reasoning order: cluster by structural shape (not exact kind),
identify recurring patterns, identify commit/ledger gaps, identify
stale validation drift, identify the deepest architectural concern,
compare against prior report.
- Output contract: structured markdown report with named sections,
terminator REFLECTION_COMPLETE for clean-finish detection.
- Constraints: don't fix anything (reflection layer not executor),
don't resolve entries without commit-SHA evidence, don't invent IDs.
- src/headless-reflect.ts (new) — sf headless reflect [--json]
- Pre-opens the project DB via auto-start.openProjectDbIfPresent
(one-shot bypass path doesn't run the full SF agent bootstrap).
- Default: emits the rendered prompt brief (template + corpus) for
operators to pipe into any model. Lets the corpus-assembly layer
ship and validate before the LLM-dispatch layer is wired.
- --json: emits raw corpus snapshot for tooling.
- src/headless.ts: registers the new "reflect" command after the
existing usage block.
- src/help-text.ts: documents it in the headless command list.
- src/resources/extensions/sf/tests/reflection.test.mjs (new, 9 tests):
null-when-DB-closed; collects open + recent-resolved; excludes >30d
resolutions; captures milestone/slice/task tree; captures validation
verdicts; commits returned as array (best-effort tmpdir is ok); brief
renders all major sections; entry IDs/severity/kind appear in brief;
writeReflectionReport round-trips through assembleReflectionCorpus's
previousReport read.
Live smoke verified: sf headless reflect against the real .sf/sf.db
returns 15 open + 23 recent-resolved entries, 50 commits, 2 milestones,
1 validation file (correctly surfacing M001's stale needs-attention
verdict against actual 5/5 slices done — exactly the case that
motivated this layer).
Total: +848 LOC, full SF extension suite (1534 tests) passes,
typecheck clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>