Skip to content

I1: replace the dispatcher's bespoke repair functions with a manifest, and gate it against the canonical field text #91

Description

@bdelanghe

Implements I1 of docs/session-capability-invariants.mdevery step of the canonical bootstrap has a fallback, or is declared irreducible. Currently graded Partial: two of four steps self-heal.

The problem

ensureMcpRegistered (#84) and syncStopHook (#88) are two bespoke implementations of one idea, written a few hours apart. A third would be a third. Worse, nothing relates the setup-script field's contents to the dispatcher's coverage — that mapping exists only as prose in .claude/README.md, so a step added to the field without a fallback is invisible until it goes missing in production, which is how #85 happened.

Shape

One manifest the dispatcher interprets. Per entry: artifact, canonical source, install target, comparison (bytes or predicate), repair action, failure wording. The dispatcher becomes a loop; mcpDriftContext generalises to "entries that could not be repaired".

The two existing repairs are deliberately not symmetric today, and the manifest has to keep both:

  • MCP: compare declared-vs-registered JSON, repair by merging into ~/.claude.json.
  • Stop hook: compare bytes, repair by copying. Bytes matter — the failure was a wrong file (3262 stock vs 5458), so a presence check reports health.

The gate is the point

gen-bootstrap-pin.mjs already parses the canonical setup-script text in .claude/README.md to extract PIN and the SUM_* lines. Extend that parse to enumerate the field's steps and assert each maps to a manifest entry or an explicit irreducible: declaration with a reason.

Then adding a line to the field without a fallback fails a test — which is the gap this whole thread is about.

Follow the existing idiom: bootstrap-pin.test.mjs asserts on the generator rather than reimplementing its logic, specifically so the two cannot drift. The manifest gate should do the same.

Done when

  • The dispatcher contains no per-artifact repair code, only the manifest and the loop.
  • Both existing repairs still pass their current tests, unchanged in behaviour.
  • A step added to the canonical text with no manifest entry fails node --test .claude/.
  • The two irreducible steps (settings.json write, CLAUDE_SESSION_ROOT prefix) are declared as such with reasons, not merely absent.

Note

This is a refactor plus a gate; it fixes no live bug. Its value is that the next #85 is caught by CI instead of by reading /tmp/env-manager.log.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions