Skip to content

[Spec 1797] adopt-bootstrap-the-governance - #1808

Open
amrmelsayed wants to merge 101 commits into
mainfrom
builder/spir-1797
Open

amrmelsayed wants to merge 101 commits into
mainfrom
builder/spir-1797

Conversation

@amrmelsayed

@amrmelsayed amrmelsayed commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds codev bootstrap-docs. It drafts the four governance docs (hot arch-critical.md / lessons-critical.md, cold arch.md / lessons-learned.md) from an existing codebase and its git history, so adopting Codev on a mature project no longer leaves placeholders behind.

Who does what:

  • The agent writes the content. It works in a new bootstrap mode of the update-arch-docs skill and explores the code and git history itself, with read-only commands.
  • The CLI owns everything deterministic:
    • per-file eligibility, so curated files are never rewritten;
    • change detection, with a non-zero exit on anything outside the eligible files;
    • a mechanical validator (cap, map, slots, guidance comment);
    • a 3-way review of the drafts, saved to .consult/bootstrap-docs/;
    • a "review before commit" summary.
  • Nothing is staged, committed or reverted.

Integration: codev adopt offers the pass after its merge session exits (never under -y), and codev update prints a hint.

Also in this PR, at the owner's request (#1811): codev update now refreshes shipped skills.

  • A skill you never edited, whose content matches a version Codev shipped, is replaced with the package's version.
  • An edited skill is kept, and each differing file gets a <file>.codev-new copy that joins the merge session, on every update while it differs. This is the same treatment CLAUDE.md gets.
  • --force replaces edited skills too.
  • Symlinked skill paths are left alone.

With that in place, bootstrap-docs runs the project's installed skill by name when it is identical to the package's version, and inlines the packaged skill text otherwise.

Closes #1797
Closes #1811

Changes

  • lib/governance-bootstrap.ts: classifier, non-empty-repo rule, hot/cold validator, and the eligibility rules shared by adopt, update and bootstrap-docs.
  • lib/tree-snapshot.ts: the change-detection core, promoted from consult's tree tripwire. It adds an index fingerprint, support for a project in a repo subdirectory, an unborn HEAD, symlinks compared by target, and a non-git walk.
  • HarnessProvider.buildInteractiveTaskLaunch: claude and codex only, with positive identification and per-provider launch blockers. Any other harness gets the prompt-file fallback.
  • commands/bootstrap-docs.ts with --dry-run, plus the adopt and update integration.
  • lib/skill-refresh.ts (codev update: refresh unedited shipped skills; bootstrap-docs runs the installed skill by name #1811), with a generated history of shipped skill versions (lib/shipped-skill-hashes.ts, built by scripts/generate-shipped-skill-hashes.mts). A test fails when a shipped skill changes without the history being regenerated.
  • update-arch-docs skill, in all four copies:
    • bootstrap mode, including how to explore git history;
    • a sensitive-material rule that applies in every mode.
  • Skeleton prompt and review templates, and command docs in both trees.
  • Side fixes: cloud-config.test.ts sets its umask precondition explicitly, and a flaky session-manager.test.ts case is skipped, citing Flaky: session-manager real-shellper tests use fixed wall-clock deadlines that fail under full-suite load (CI-skipped, so only local/porch runs see them) #1800.

Testing

  • Full codev suite on the final code: 315 files, 6400 passed; tsc is clean.
  • Real-repo verification on sindresorhus/execa, three runs; details are in the review doc. Run 3 is on the final code and played an older adopter whose skill predates bootstrap mode:
    • codev update refreshed update-arch-docs and nothing else;
    • bootstrap-docs then ran the installed skill (the transcript shows the agent loading it) and explored git history with the skill's commands;
    • all four drafts were written, validation passed, nothing changed outside them, and the exit code was 0;
    • the reviewers found claims to correct before commit;
    • a re-run was a byte-identical no-op.
  • Not verified: a human-driven interactive session. All three runs used a headless stand-in for the agent.

Spec

codev/specs/1797-adopt-bootstrap-the-governance.md (the digest removal and #1811 are recorded under Deviations in the review)

Review

codev/reviews/1797-adopt-bootstrap-the-governance.md

@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Architect integration review (main) — round 1, head 3fe8403

Risk tier: High (+5755/-331, 48 files; new CLI command, adopt/update integration, harness capability, consult tripwire moved to a shared lib). 3-way review: Codex REQUEST_CHANGES, Claude APPROVE (seven items), Gemini skipped (agy not signed in). CI 7/7 green on this head. I verified the headline findings in source and exercised the real path from the branch build on a fresh shallow clone of a real public repo (adopt -y prints the command and launches nothing; bootstrap-docs --dry-run classifies all four files eligible and resolves claude -- '<prompt>'; a headless probe confirms the Claude CLI accepts -- before the positional prompt). The force-advanced commit b87516dcd reads clean (lstat + readlink; broken links and loops are safe).

Must fix before the pr gate

  1. Symlinked governance files escape the detector (Codex; verified). classifyProjectFile reads through a symlink (fs.readFileSync follows), so a linked codev/resources/*.md can classify as placeholder and become eligible, while hashGovernanceFiles → hashPath hashes only <link:TARGET>. An agent writing through the link lands bytes outside the project with no governance-hash or tree-snapshot change. Fix: lstat in classification; a symlink or any non-regular path is curated (ineligible) and named in the per-file status; regression test with a symlinked starter.
  2. Pin the starter history (Claude 1). EARLIER_STARTERS is hand-maintained; a future edit to a starter template silently reclassifies every adopter's untouched placeholders as curated and disables the feature for its target users. Add a test that hashes the four shipped starter templates and fails with a message telling the editor to append the previous text to EARLIER_STARTERS.
  3. codev adopt exit code (Claude 4) — ruling: adopt's exit status reflects adoption. When the user accepts the offer, adopt prints the bootstrap summary and validation result but exits 0 if adoption itself succeeded; codev bootstrap-docs run directly keeps its own non-zero semantics. Test for the adopt path.
  4. Layering, small (Claude 2 + 3): move spawnAgentProcess/AgentExit from commands/bootstrap-docs.ts to lib/ (restores cli.ts's lazy import of the command module), and home CONSULT_OWNED_PREFIXES in lib/tree-snapshot.ts next to the snapshot core with consult re-exporting it.

Noted, not blocking

Process

Fix 1-4 in this branch, CMAP the fix, push, post the new head here and tell main. Main re-reviews the delta and takes the pr gate to the owner. Not merging.

@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Integration review round 1: addressed (new head 7ebbe95e5)

Main's four must-fix items:

  1. Symlinked governance files (fd450a7): classified with lstat, so a symlink or non-regular path is curated, never eligible, and named in the per-file status ("a symlink, never rewritten"). Governance hashes now cover the resolved content as well as the link target, so a write through a symlink pointing outside the repo is caught. The regression test was confirmed to fail without the fix.
  2. Starter history pinned (fd450a7): a sha256 pin of the four shipped starters fails with "append the previous text to EARLIER_STARTERS…" when a template changes.
  3. adopt's exit code, per the ruling (a7a469e): adopt exits 0 once adoption succeeds and prints a yellow line when the pass reported problems. codev bootstrap-docs keeps its non-zero exit. The adopt path is tested, including that process.exitCode stays untouched.
  4. Layering (d42fc36): lib/agent-process.ts now holds spawnAgentProcess, AgentExit and AgentLaunch. CONSULT_OWNED_PREFIXES now lives in lib/tree-snapshot.ts, and consult re-exports it. adopt loads bootstrap-docs lazily, so cli.ts's lazy import is effective again.

PR consult round 1:

  • Codex RC (9e87ce1): the tree is re-snapshotted after the draft review, so reviewer-time changes are named and exit non-zero.
  • Claude minors (9e87ce1): fence-proof git digest, and --> placement tolerated.
  • main merged.

PR consult round 2, on these fixes: Gemini APPROVE, Claude APPROVE. Codex RC on docs and metadata only (exit-code docs, adopt JSDoc, spec/plan frontmatter); all three fixed at 7ebbe95e5.

Real-repo run 2 on the final code (fresh sindresorhus/execa): validation passed under the stricter checks, and the guidance comment was kept this time. No changes outside the eligible files, so exit 0. Codex and Claude reviewed the drafts (Gemini skipped). Re-run: byte-identical no-op. Recorded in the review doc.

Suite: after the merge, 6384 passed; tsc clean. Not merging; the owner's pr gate is outstanding.

@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Architect integration review (main) — round 2, head 7ebbe95

Re-reviewed the delta since 3fe8403 (four fix commits, the review-phase docs commit, and a clean merge of origin/main for #1783 with no overlap on this feature's files).

  • Item 1 (symlinked governance files) — fixed, verified. Classification now lstats the path; a symlink or any non-regular path is curated and named as such in the per-file status, and the change report hashes through the link so a write via the link is seen. Regression test present.
  • Item 2 (starter history pin) — fixed, verified. A test hashes every shipped starter template against pinned digests and fails with the "append the previous text to EARLIER_STARTERS" instruction.
  • Item 3 (adopt exit code) — fixed as ruled. Adopt exits 0 once adoption succeeded; a bootstrap pass's problems are reported, not propagated; the direct command keeps its own non-zero semantics.
  • Item 4 (layering) — fixed. spawnAgentProcess/AgentExit live in lib/agent-process.ts, CONSULT_OWNED_PREFIXES in lib/tree-snapshot.ts with consult re-exporting, and cli.ts lazy-imports the command module again.

Also taken: mutations during the draft review now fail the run (Codex round 1), the fence-proof git digest and --> placement (Claude minors), exit-code docs / adopt JSDoc / approval frontmatter (Codex round 2). Real-repo run 2 on the final code recorded in the review doc: validation passed, guidance comment kept, exit 0, byte-identical no-op on re-run. Builder reports 6384 passing and tsc clean.

Verdict: APPROVE for integration. Taking the pr gate to the owner; merge waits on the owner's word and 7/7 green on 7ebbe95. Outstanding on the owner's side, not the builder's: one genuine interactive launch from this build (main's UX check).

…ess providers

The Claude and codex subcommand and blocking-flag lists are CLI-specific
knowledge; they now sit beside the provider that uses them, unexported, and
the tests check the blocker through the provider. Refs #1810 for the full
split of built-in providers out of harness.ts.

@waleedkadous waleedkadous left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, really like the direction and am happy to approve.

One thing to consider: is the code for the bootstrap-docs-prompt duplicative of the update-arch-docs protocol? Is there a way we could just have codev bootstrap-docs just invoke the protocol?


A bounded digest of the repository's history, prepared for you: the most recent commit subjects plus subjects matching fix, revert, incident and similar words. Use it to find scar tissue for `lessons-learned.md`. Inspect individual commits with `git show <hash>` when one looks significant; do not walk the full log.

{{GIT_DIGEST}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find that just giving the agent tools is the best way and telling it how to explore instead of a pre-cooked digets works best.

…ed skills; bootstrap runs the installed skill

The agent now explores git history itself, guided by the update-arch-docs
skill's bootstrap-mode survey step, and the prompt no longer restates the
skill's rules. codev update replaces shipped skills the user never edited
(matched against a generated history of shipped versions) and offers an
edited skill's new version as .codev-new on every update. bootstrap-docs
names the installed skill when it matches the package and inlines the
packaged text otherwise. Refs #1811.
…esolved .codev-new; real-repo run 3

An edited skill holding a symlinked subdirectory let the .codev-new write
land outside the project; a skill holding a symlink, or a symlinked skills
root, is now left alone. A pending .codev-new that the skill has caught up
with is removed. Records real-repo run 3 (older-adopter path) and the
round-3 consultation. Refs #1811.
…e keeps unshipped files

update --dry-run now previews skill changes (added, updated, conflict,
skipped) without writing. --force on an edited skill overwrites only the
package's files and keeps files the package does not ship. The edited path
drops a .codev-new once its file matches again. A test ties the skill's cap
numbers to the validator, the inline fallback reads the launching harness's
skill copy, the hash generator has a pnpm script, and the codev skill warns
about running update here with an older package. Refs #1811.
… no root files

copyRootFiles takes dryRun. Under --dry-run (with or without --force),
update now reports CLAUDE.md / AGENTS.md as new, updated or conflicting
with 'would be' wording and writes neither the files nor .codev-new copies.
Before, a dry run wrote .codev-new copies and --dry-run --force created a
missing root file.
…quired sections

An empty Critical facts / Map of <cold doc> section could pass when a
similarly named section held bullets, and such a section counted toward
the caps. Counting is now scoped to the exact required headings. Also
moves an orphaned JSDoc and documents the .consult/ detection exemption.
The last 100 raw commits can be days of history. The skill's survey step
now reads the project's own record first (CHANGELOG, release notes, ADRs,
tags), lists recent direction one line per PR via --first-parent (merge
commit PR titles from the body, which also works for squash-merge repos),
samples older eras, and looks at removed areas.
…v-new; exact hot section headings

A skill or root file whose pending .codev-new is a symlink is left alone,
and a dangling root-file symlink is not followed to create a file; a root
file that is itself a symlink still gets a regular .codev-new beside it.
Required hot sections match the exact name or the name plus its
parenthetical, so a prefix-colliding heading no longer counts. Also
commits four rebuttal docs from the phase reviews.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants