|
| 1 | +# Full Codebase Sweep, 2026-07-23 (Fable 5) |
| 2 | + |
| 3 | +Scope: every source file in packages/core (17 modules), packages/cli, packages/mcp, sdks/python, integrations/claude-code hooks, spec fixtures. 4,139 lines reviewed line-by-line. |
| 4 | + |
| 5 | +## Fixed (verified live, regression tests added) |
| 6 | + |
| 7 | +### 1. `gotcha add` silent data loss on inline `gotchas: []` (packages/cli/src/cli.ts, upsertGotchasYaml) |
| 8 | +The frontmatter rewrite regex could not match the inline-empty form `gotchas: []`, so `marchese gotcha add` printed "Added GOTCHA-001" while writing nothing to MARCHESE.md. Reproduced live before the fix; the trap was self-inflicted because `toYamlFragment()` itself emits `gotchas: []` after removing the last gotcha, guaranteeing the next add would be lost. Replaced the regex with a line-based block splice that handles both block and inline forms. Regression test: add over `gotchas: []` now persists and round-trips through `gotcha list`. |
| 9 | + |
| 10 | +### 2. PreToolUse hook output not in Claude Code protocol shape (cli.ts rtk hook + integrations/claude-code/hooks/PreToolUse.sh) |
| 11 | +The hook emitted `{"permissionDecision":"allow","updatedInput":...}` at the top level. Claude Code reads decisions from `hookSpecificOutput: { hookEventName, permissionDecision, updatedInput }`, so the RTK bash rewrite would never actually be applied by the host; commands passed through unmodified. Both the CLI hook processor and the shell hook (including its pass-through fallback) now emit the `hookSpecificOutput` envelope. Caveat: verified against the documented protocol shape and by unit test on the JSON envelope; not exercised through a live Claude Code hook round-trip in this session. |
| 12 | + |
| 13 | +### 3. YAML type coercion in gotcha serialization (packages/core/src/gotchas.ts, yamlQuote) |
| 14 | +Values like `true`, `no`, `123` were emitted unquoted, so re-parsing coerced them to boolean/number and schema validation then rejected the file the tool itself wrote. Coercible scalars are now quoted. Regression test round-trips title `"true"`, issue `"123"`, resolution `"no"`. |
| 15 | + |
| 16 | +### 4. `loop --run-gate` executed a fabricated gate for undeclared loops (cli.ts) |
| 17 | +An unknown loop name fell back to an ephemeral definition with `verification_gate: "npm test"`; combined with `--run-gate` that executed a shell command the user never declared. Now refuses with exit 1 when `--run-gate` targets a loop not present in MARCHESE.md. Training-mode ephemeral fallback unchanged. Regression test added. |
| 18 | + |
| 19 | +### 5. Ingest churn from layout timestamp (packages/core/src/knowledge.ts, buildLayoutDoc) |
| 20 | +`project-layout.md` embedded a generation timestamp, so every `marchese knowledge ingest` dirtied git even with zero real changes. Timestamp removed; re-ingest is now idempotent (verified: two consecutive ingests, single stable diff). |
| 21 | + |
| 22 | +## Design notes, no code change (candidates for v1.1) |
| 23 | + |
| 24 | +- **Sign-off apply is approval logging, not mutation.** Checked review items are appended to change-log.md and the review file is retired, but sign-off proposals carry no stored autoFix; the actual edit is the agent's or human's job. The review file wording says "applied" which slightly overpromises. Consider storing autoFix payloads for mechanically applicable sign-off kinds. |
| 25 | +- **Proposal IDs regenerate per scan** (IMP-001... per run). Stable across a single review cycle only because the review file freezes them; fine today, would break if two reviews coexist. |
| 26 | +- **`empty-raw-stub` auto-approve proposals carry no autoFix**, so they re-report on every run rather than resolving. Harmless noise; either attach a delete/re-ingest fix or downgrade to more-context. |
| 27 | +- **auditContextBudget:** when `estimatedSessionTokens` is supplied, baseline tax (CLAUDE.md + skills) is ignored rather than added. Documented-in-tests behavior; semantics debatable. |
| 28 | +- **compressInput `dedupeConsecutiveLines` default-on is lossy for code payloads** (legit duplicate lines get dropped). Fine for logs; callers compressing source files should disable it. |
| 29 | +- **MCP dispatcher** (`handleToolCall`) supports three unregistered tools (marchese_compress, marchese_history_insight, marchese_parse); harmless extras, register or delete when convenient. |
| 30 | +- **detectRtkBinary on Windows** treats a directory named `rtk` on PATH as the binary (existsSync only). Cosmetic, wrong platform for current use. |
| 31 | + |
| 32 | +## Verification |
| 33 | + |
| 34 | +| Suite | Result | |
| 35 | +|---|---| |
| 36 | +| vitest (core + cli) | 61/61 (3 new regression tests) | |
| 37 | +| MCP node:test | 14/14 | |
| 38 | +| conformance fixtures | 7/7 | |
| 39 | +| Python pytest | 8/8 | |
| 40 | +| build / typecheck / lint (Biome) | clean | |
| 41 | +| Live repros | gotcha-add persists; hook emits hookSpecificOutput; double ingest idempotent | |
0 commit comments