Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
145 commits
Select commit Hold shift + click to select a range
f0ea2e6
fix(security): harden context, dry-run, manifest, and glob handling
toshtag Jun 19, 2026
5292283
fix(security): map manifest symlink escape to a clean error; surface …
toshtag Jun 19, 2026
4e245ae
fix(security): contain planning-prompt grounding reads to the project…
toshtag Jun 19, 2026
a912655
fix(security): tag path-safety escapes and keep decision gates fail-c…
toshtag Jun 19, 2026
2c9f571
fix(security): map malformed / schema-invalid adapter manifests to a …
toshtag Jun 19, 2026
f38df15
fix(security): fail-closed adapter install/upgrade (ordering, placeho…
toshtag Jun 19, 2026
dcda22a
fix(security): contain the agent-profile path to the project root
toshtag Jun 19, 2026
ec44bd6
fix(security): preflight all adapter write paths before the --model pin
toshtag Jun 19, 2026
87c99f5
fix(security): detect dangling symlinks in resolveWithinProject
toshtag Jun 19, 2026
5d0d1c6
fix(security): unify matchGlob/globToRegex semantics for adjacent dou…
toshtag Jun 19, 2026
cd171c8
fix(security): refuse dangling symlinks in resolveWithinProject (writ…
toshtag Jun 19, 2026
3a413e0
fix(security): clean up the atomic temp file on a mid-write failure
toshtag Jun 19, 2026
4e6f70b
fix(glob): true matchGlob/globToRegex parity (escape '?', match newli…
toshtag Jun 19, 2026
e046c36
fix(security): map attacker-input read failures to structured errors,…
toshtag Jun 19, 2026
48af037
fix(security): typed adapter write preflight (reject wrong on-disk ty…
toshtag Jun 19, 2026
22a2c56
fix(security): contain loadPhase / loadRoadmap reads to the project root
toshtag Jun 19, 2026
eab7cfa
fix(security): stop forged manifest+profile from overwriting arbitrar…
toshtag Jun 19, 2026
3bf4eb6
chore(security): add a fast static fs-containment tripwire (local hoo…
toshtag Jun 19, 2026
28458d9
fix(security): structure loadPhase/loadRoadmap errors and map them in…
toshtag Jun 19, 2026
9f0cfdb
fix(security): authorize adapter overwrite/prune by canonical identit…
toshtag Jun 19, 2026
0dc19c4
fix(security): route every roadmap read through the contained loadRoa…
toshtag Jun 19, 2026
d070918
fix(security): contain the model-profiles dir; give refusals a correc…
toshtag Jun 19, 2026
2c99961
chore(security): fs-containment tripwire catches multiline fsfn(\n jo…
toshtag Jun 19, 2026
8bf138a
fix(security): contain the PlanState family's roadmap/phase reads
toshtag Jun 19, 2026
765f38a
docs(cli): fix adapter --force / --accept-modified help (was backwards)
toshtag Jun 19, 2026
f782e4a
fix plan-state config error handling
toshtag Jun 19, 2026
aaf345b
test decision retire roadmap containment
toshtag Jun 19, 2026
9df8672
fix design write containment
toshtag Jun 19, 2026
45537e9
fix remaining fs containment reads
toshtag Jun 19, 2026
a7ce5c5
fix(security): reject unowned design writes
toshtag Jun 19, 2026
39f0eea
fix(security): preflight init owned namespaces
toshtag Jun 19, 2026
d9c3ead
fix(security): own progress ledger paths
toshtag Jun 19, 2026
d563cbe
fix(security): own archive mutation paths
toshtag Jun 19, 2026
ffdd4f4
test(security): cover owned symlink refusals
toshtag Jun 19, 2026
a8e728c
fix(security): own advisory lock path
toshtag Jun 20, 2026
70e8c10
fix(security): own archive read authority
toshtag Jun 20, 2026
72cf7c7
fix(security): reject phase symlink aliases
toshtag Jun 20, 2026
87663d8
fix(security): refuse adapter symlink writes
toshtag Jun 20, 2026
e4af65b
test(security): cover remaining symlink blockers
toshtag Jun 20, 2026
175058e
fix(security): harden owned-path error handling
toshtag Jun 20, 2026
4442c60
fix(security): reject lifecycle symlink aliases
toshtag Jun 20, 2026
4f2edd7
fix(security): type-check init preflight paths
toshtag Jun 20, 2026
4cc546a
fix(security): plan adapter refusals before writes
toshtag Jun 20, 2026
cae8a70
test(security): cover lifecycle and adapter refusal blockers
toshtag Jun 20, 2026
dce874e
fix(security): contain project ref presence checks
toshtag Jun 20, 2026
7f02d4e
fix(security): contain doctor validation reads
toshtag Jun 20, 2026
5b6cbc4
fix(security): require owned adapter state writes
toshtag Jun 20, 2026
611e0d9
test(security): cover external reads and adapter state aliases
toshtag Jun 20, 2026
603ad67
test(ci): align security hardening contracts
toshtag Jun 20, 2026
8a1760e
fix(security): contain startup config reads
toshtag Jun 20, 2026
37f2dd6
fix(security): restrict adapter profile writes
toshtag Jun 20, 2026
499f9f5
fix(security): contain adapter doctor reads
toshtag Jun 20, 2026
7eb7082
fix(security): require owned grounding reads
toshtag Jun 20, 2026
671d443
fix(security): harden project config readers
toshtag Jun 20, 2026
def604c
fix(security): own phase discovery paths
toshtag Jun 20, 2026
ec9899d
fix(security): constrain decision_refs to the ADR namespace
toshtag Jun 21, 2026
b546052
fix(security): own manifest reads + wire fs-containment CI
toshtag Jun 21, 2026
9f7cea2
fix(security): restrict decision_refs to flat design/decisions/*.md
toshtag Jun 21, 2026
7e832e5
fix(security): narrow manifest read authority off the shared skills n…
toshtag Jun 21, 2026
fe616ba
fix(security): own plan-graph reads + map --decision-ref errors + fix…
toshtag Jun 21, 2026
bbabb27
fix(security): close adapter doctor read oracle
toshtag Jun 21, 2026
288ea0c
fix(security): add ownedPathRoles exact-match authority to adapter de…
toshtag Jun 28, 2026
9b228f3
fix(security): strict preflight resolves owned paths and returns prep…
toshtag Jun 28, 2026
5d1283d
fix(security): authorize adapter install paths before read or hash
toshtag Jun 28, 2026
20d1774
fix(security): authorize adapter upgrade paths before read or hash
toshtag Jun 28, 2026
7f9d82c
test(security): cover mutation read authority and preflight atomicity
toshtag Jun 28, 2026
9d77228
test(security): align integration tests with owned-path read authority
toshtag Jun 28, 2026
8ac87af
docs: update cli-contract and changelog for read authority
toshtag Jun 28, 2026
1c78e3e
fix(security): deprecate ownedPathGlobs/writePathGlobs for role-scope…
toshtag Jun 28, 2026
2fbf104
fix(security): preserve existing dynamic files opaquely instead of re…
toshtag Jun 28, 2026
5a984b6
fix(security): role-scope doctor orphan scan and conformance manifest…
toshtag Jun 28, 2026
e36c1d9
fix(security): separate CLI warnings for dynamic files and unowned or…
toshtag Jun 28, 2026
6cbf7d0
test(security): align tests with preserve-opaquely policy
toshtag Jun 28, 2026
7888019
docs: update cli-contract and changelog for role-scoped authority
toshtag Jun 28, 2026
bf9b40a
fix(security): restrict context_dir to .context/** namespace
toshtag Jun 29, 2026
5acf3e3
fix(security): simplify classifyManifestFileForRead API and enforce r…
toshtag Jun 29, 2026
2dc39e2
test(security): add filesystem operation proof tests for conformance …
toshtag Jun 29, 2026
10061d2
fix(security): add manifest identity check, desired role dedup, profi…
toshtag Jun 29, 2026
ef03e0d
fix(security): update remediation messages for dynamic files and unve…
toshtag Jun 29, 2026
3ad35ae
refactor: rename resolveOwnedProjectPath to resolveSymlinkFreeProject…
toshtag Jun 29, 2026
be5817c
docs: update cli-contract and CHANGELOG for security hardening refine…
toshtag Jun 29, 2026
cc9f2a1
docs: regenerate stale doc-blocks in cli-contract.md
toshtag Jun 29, 2026
ea1775a
refactor: symlink-free owned reads + profile contract validation
toshtag Jun 29, 2026
6074f90
test+docs: path-safety proof tests, red tests, footgun removal, SECUR…
toshtag Jun 29, 2026
0439293
refactor: harden adapter write paths with symlink-free ownership checks
toshtag Jun 29, 2026
672c169
feat: add fs operation proof tests, AST gate, and update SECURITY.md
toshtag Jun 29, 2026
4185759
fix: add context_dir type check before model pin
toshtag Jun 29, 2026
88168a7
fix(security): complete control-plane ownership enforcement
toshtag Jun 29, 2026
f05e933
docs: regenerate stale doc-blocks in cli-contract.md
toshtag Jun 29, 2026
eb593cd
fix(security): restrict agent profile ownership
toshtag Jun 29, 2026
0496428
fix(adapter): fail closed on invalid profiles
toshtag Jun 29, 2026
3f04700
fix(adapter): validate descriptor invariants
toshtag Jun 29, 2026
ee3557c
fix(security): strengthen fs authority proof
toshtag Jun 29, 2026
628b567
fix(security): enforce doctor profile authority
toshtag Jun 29, 2026
0c9493d
fix(adapter): validate create path globs
toshtag Jun 29, 2026
ff2ffa5
fix(security): scope fs authority provenance
toshtag Jun 29, 2026
bf1c206
fix(security): close unsupported-agent and task-read oracles
Jun 29, 2026
8ab9314
chore(security): make filesystem authority enforcement sound
toshtag Jun 29, 2026
847c9f2
chore(security): complete dynamic create authority validation
toshtag Jun 29, 2026
19da25c
feat(security): apply AgentProfileRefPath schema to runtime resolvers
toshtag Jun 29, 2026
5caf7a1
feat(security): refine fs-authority checker with authority objects an…
toshtag Jun 29, 2026
af45b9b
feat(security): enforce protected namespace on ownedPathRoles and pro…
toshtag Jun 29, 2026
ac72470
test(security): add protected-namespace forged manifest proof
toshtag Jun 29, 2026
0533770
feat(security): transactional multi-file mutation and lazy context_di…
toshtag Jun 29, 2026
c8fb478
refactor(security): centralize filesystem API via projectFs seam
toshtag Jun 29, 2026
9ea40ab
feat(security): establish dynamic generated-file provenance
toshtag Jun 29, 2026
fce1834
docs(security): update SECURITY.md to match B-5 through B-8 implement…
toshtag Jun 29, 2026
68dc031
fix(security): B-8 revert provenance markers to reserved namespace wi…
toshtag Jun 29, 2026
76e1314
fix(security): B-6 add backup rename, journal, PARTIAL_MUTATION to Fi…
toshtag Jun 29, 2026
25953f8
fix(security): B-7 add branded path types for compile-time authority …
toshtag Jun 29, 2026
80b5288
test(security): A-2 add switch bypass and non-path helper confusion f…
toshtag Jun 29, 2026
337b179
test(security): A-4 add FileHandle method tracking to filesystem oper…
toshtag Jun 29, 2026
332240d
docs(security): B-9 update SECURITY.md for B-8, B-6, B-7, A-2, A-4 ch…
toshtag Jun 29, 2026
06312af
fix(security): enforce semantic filesystem authority
toshtag Jun 29, 2026
603bcc6
refactor(adapter): stage and roll back multi-file mutations
toshtag Jun 29, 2026
6a764f0
test(security): strengthen descriptor and operation proofs
toshtag Jun 29, 2026
927c1f9
fix(adapter): preserve committed transaction results during cleanup
toshtag Jun 29, 2026
8e4693f
fix(adapter): recover pending staged transactions
toshtag Jun 29, 2026
8c8015e
chore(security): make filesystem authority checks capability-aware
toshtag Jun 29, 2026
d26a4a1
refactor(security): add typed project filesystem wrappers
toshtag Jun 29, 2026
04cd2ca
fix(adapter): formalize dynamic file ownership handoff
toshtag Jun 29, 2026
9021eb5
docs(security): document adapter hardening semantics
toshtag Jun 29, 2026
ac2ee4f
fix(adapter): reconcile crash state from private transaction journals
toshtag Jun 30, 2026
8c147a6
fix(security): reject untrusted adapter transaction journals
toshtag Jun 30, 2026
893c138
chore(security): close fs-authority control-flow gaps
toshtag Jun 30, 2026
a052482
fix(adapter): require typed transaction targets
toshtag Jun 30, 2026
d2c7071
chore(security): ban raw fs wildcard re-exports
toshtag Jun 30, 2026
2be62ca
fix(adapter): finalize dynamic handoff diagnostics
toshtag Jun 30, 2026
d9357e8
fix(adapter): reject test-only recovery journals
toshtag Jun 30, 2026
34cdcbb
chore(security): track aliased filesystem sinks
toshtag Jun 30, 2026
2110c58
fix(adapter): journal transactions before staging files
toshtag Jun 30, 2026
d611bd2
fix(adapter): validate private transaction state and artifacts
toshtag Jun 30, 2026
e218e9b
fix(adapter): preserve cleanup-pending error contract for journal cle…
toshtag Jun 30, 2026
f481e94
refactor(security): separate delete capability from write in adapter …
toshtag Jun 30, 2026
32725e1
docs(security): align transaction and authority guarantees
toshtag Jun 30, 2026
dacd747
refactor(security): reduce trusted module scope to core primitives
toshtag Jun 30, 2026
ed9b740
refactor(security): internalize brand constructors and downgrade owne…
toshtag Jun 30, 2026
ad29b3e
test(adapter): add crash matrix and journal cleanup failure tests
toshtag Jun 30, 2026
bd2d60e
fix(decisions): support nested ADR records safely
toshtag Jun 30, 2026
a4513b1
test(decisions): cover nested ADR lifecycle
toshtag Jun 30, 2026
d4eb43f
docs(decisions): align lifecycle docs with nested ADR support
toshtag Jun 30, 2026
fbadfc5
docs(security): fix stale comments after nested ADR and authority enf…
toshtag Jun 30, 2026
baa8e32
refactor(security): isolate raw fs imports into raw-internal.ts
toshtag Jun 30, 2026
d7e3f9f
refactor(security): replace doctor.ts function-level allowlist with d…
toshtag Jun 30, 2026
257e5b1
test(security): add negative compile fixture for branded path types
toshtag Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
850 changes: 850 additions & 0 deletions .code-pact/fs-authority-allowlist.json

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ jobs:
- run: pnpm check:docs
if: matrix.profile == 'full'

# Lexical filesystem-containment guard: flags raw readFile(join(cwd, ...))
# reads that bypass the owned/contained path seams. A structural backstop
# for the path-containment work; the SEMANTIC invariants (decision_refs
# namespace, forged-manifest ownership) are pinned by the security
# regression tests in test:unit, which this does NOT replace.
- run: pnpm check:fs-containment
if: matrix.profile == 'full'

# AST-based filesystem-authority gate: flags fs operations on paths
# not sourced from an authority resolver (resolveSymlinkFreeProjectPath,
# resolveOwnedReadPath, etc.). A structural backstop complementing the
# lexical containment guard above.
- run: pnpm check:fs-authority
if: matrix.profile == 'full'

- run: pnpm typecheck

- run: pnpm test:unit
Expand Down
25 changes: 22 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,34 @@ identifiers. Starting with v1.0.0, stable releases use plain

## [Unreleased]

No changes yet.
### Security

- **Context pack no longer follows a `design/constitution.md` symlink out of the project (CWE-59).** `loadConstitution` now reads through the same project-contained helper as rules/decisions (`resolveWithinProject`), so a repo that symlinks `design/constitution.md` to an outside file cannot leak that file into the agent-facing context pack. A missing/unreadable/unsafe constitution still degrades to "not included".
- **`task complete --dry-run` no longer executes verification shell commands (CWE-78).** The caller's `dryRun` is now propagated into verify, so the project-controlled `verification.commands` (run with `shell: true`) are previewed, not executed, on a dry run. The read-only decision gate still runs. **Behavior change:** a `--dry-run` whose only failing check is a command no longer exits 1 — it returns a clean `dry_run` preview. A non-dry-run completion is unchanged (it executes commands and fails on a failing command).
- **Adapter manifest I/O fails closed on a `.code-pact/adapters` symlink escape (CWE-59).** `readManifest` / `writeManifest` resolve the manifest path through `resolveWithinProject`, so a symlinked adapters directory can no longer make a read pull a foreign manifest or a write land outside the project. `adapter install` / `adapter upgrade` map the refusal to a structured `ADAPTER_MANIFEST_INVALID` envelope (exit 2) instead of leaking an internal error / exit 3.
- **Atomic writes use unpredictable, exclusively-created temp files (CWE-59 / CWE-377).** Temp paths are now crypto-random and opened with `wx` (`O_CREAT|O_EXCL`), so a pre-planted symlink at the temp path is refused (EEXIST, never followed) instead of being written through to an outside target.
- **`adapter install` no longer trusts a project-shipped manifest hash to preserve stale/forged generated content (CWE-345).** A `managed-clean` file whose content no longer matches the generator output is now re-rendered (`update`) instead of skipped, so a forged manifest hash matching shipped-malicious instructions is self-healed. A managed file that matches **neither** the manifest hash **nor** the generator output (`managed-modified × stale` — the shape a hostile repo ships: malicious content + a non-matching forged hash) is no longer **silently** skipped: it is **refused** (not overwritten — it could be a genuine local edit — but surfaced via `result.refused[]` / `files[].action: "refuse"`, and `adapter install` exits 1). Genuinely user-modified files are still never overwritten.
- **`adapter upgrade --write` no longer deletes an orphan just because the manifest claims it (CWE-73).** An orphan is auto-pruned only when its path is in the adapter descriptor's `ownedPathRoles`; an orphan outside that set is surfaced (`action: "warn"`) and kept on disk. **Behavior change:** a renamed/removed generated file whose path is not in the owned set is now reported rather than auto-deleted, so a forged manifest entry cannot turn `upgrade --write` into an arbitrary in-project delete.
- **`adapter install` / `adapter upgrade` establish read authority before touching generated-file targets (CWE-200).** Static existing files are read only after exact path+role authorization and symlink-free resolution. Existing dynamic skill collisions are **preserved opaquely** (warn, not refuse): their bytes are never read or hashed, but the rest of the install/upgrade continues (static writes, model pin, manifest refresh). Unowned manifest orphans are reported as `local: "unverifiable"` without a target existence/hash probe. This removes the manifest-SHA equality oracle for profile redirects such as `.env`.
- **Adapter authority model is now role-scoped (CWE-345).** `ownedPathGlobs` and `writePathGlobs` are replaced by `ownedPathRoles` (exact static read/hash/overwrite/delete authority) and `createPathGlobsByRole` (role-scoped create-only authority). A missing target whose path matches a create glob AND whose role matches the key may be CREATED; an existing file at that path is never read, hashed, or overwritten. This prevents a forged manifest from elevating a shared-namespace path (e.g. `.claude/skills/private.md`) to read authority via a wildcard match.
- **Adapter placeholder preflight now rejects every symlink component before model pinning (CWE-59).** `context_dir` / `hook_dir` use the same strict owned-path resolver as the commit phase, including in-project final and parent symlinks. The resolved paths are carried into mkdir, generated-file write/prune, and manifest-write phases, so a failed `--model` install/upgrade cannot leave only the profile pin behind.
- **Glob matching is now linear and backtrack-free (CWE-1333).** The file-walk / write-audit / doctor match paths use a two-pointer segment matcher instead of a regex compiled from `**`, eliminating the catastrophic backtracking a project-controlled `task.reads` glob could trigger. A pattern-length cap is also enforced in `validateGlobSyntax`.
- **`context_dir` is now restricted to the `.context/**`namespace (CWE-22/CWE-73).** The`AgentProfile.context_dir`field is validated by a dedicated`ContextOutputDir`schema that rejects any path outside`.context/`. A new `resolveProfileContextOutputPath`enforces namespace containment and symlink-free resolution before any write.`writeContextPack`and`task prepare --dry-run`both route through this resolver, so a hostile profile can no longer redirect context pack output to an arbitrary project file (e.g.`CLAUDE.md`or`.env`).
- **Manifest `agent_name` identity check (CWE-345).** `readManifest` and `writeManifest` now refuse a manifest whose `agent_name` doesn't match the target agent (`ADAPTER_MANIFEST_INVALID`), preventing a cross-agent manifest swap from being acted on.
- **`classifyManifestFileForRead` now enforces role mismatch before filesystem access (CWE-200).** The API is simplified: the declared role is always checked against the static path's expected role. A role-swap (e.g. `CLAUDE.md` with `role: skill`) is `unowned` before any read/stat/heading inspection — no content oracle. The `roleCheck` / `expectedRoleFor` parameters are removed; the declared role is passed directly.
- **`dedupeDesiredFiles` now rejects same-path different-role duplicates (CWE-345).** Two desired files at the same path with identical content but different roles now throw `ADAPTER_DESIRED_PATH_CONFLICT`, preventing a role confusion from silently corrupting the adapter's converged state.
- **`resolveOwnedProjectPath` renamed to `resolveSymlinkFreeProjectPath`.** The old name implied ownership proof; the new name accurately describes the function's behavior: symlink-free project containment. A deprecated alias keeps existing imports working.
- **Adapter staged transactions are journaled before project temp files are written.** `FileTransaction` now separates pre-commit rollback from post-commit cleanup and writes the prepared journal to user-private state before staging project-side temp files. Backup/temp/journal cleanup failures after the durable commit marker surface as `TRANSACTION_CLEANUP_PENDING` while preserving the new final files. The next adapter install/upgrade attempts journal recovery before starting a new mutation.
- **`check:fs-authority` now rejects known false-negative bypasses.** The gate no longer treats `resolveWithinProject` or generic `resolveOwnedReadPath` as authority sources, merges branch authority by capability intersection, checks multi-path fs operations such as `rename`/`copyFile`/`symlink` per argument, tracks aliased projectFs/raw fs sinks, rejects namespace/dynamic/require raw fs calls, and removes the trusted-name nested-function exemption.
- **Dynamic adapter skills are create-once handoff outputs.** A newly created dynamic skill records `ownership: handed_off` in the manifest. Later runs do not use the reserved `code-pact-*` prefix as provenance, do not read/hash/update/prune the file, and do not repeatedly warn once handoff is recorded.

## [2.0.0] — 2026-06-18

**v2.0.0 — bounded archive maintenance.** `state archive-maintain` is the one command that keeps `.code-pact/state/archive` bounded — it recovers any pending delete-intent journal, compacts the loose tail into bundles, retains/removes unreferenced old truth, re-plans, and runs `validate` + `plan lint`, reporting an honest `bounded_status`. **Scope (no over-claim):** v2.0.0 bounds the archive's **file-count** sprawl and removes **unreferenced old truth** while **preserving referenced truth**. It does **not** yet bound a single bundle's **byte size** — sharding is the next storage milestone. This is a **major** bump because of one breaking error-code-contract change (see Changed → `MISSING_PHASE_FILE`).

### Changed

- **Behavior fix (error-code contract): `doctor` / `validate` now report a roadmap-referenced missing phase file as `MISSING_PHASE_FILE`, matching `plan lint`.** Previously `doctor` (and `validate`, which delegates to it) emitted `ORPHAN_PHASE_FILE` (severity `error`) for a `roadmap.yaml` reference whose phase file is absent or present-but-inaccessible — the opposite of that code's documented meaning ("a phase file present but not referenced"), so a user looking the code up read a contradictory definition. The condition now uses the code whose name matches it (`MISSING_PHASE_FILE`, *referenced but not present*), with **severity unchanged (`error`)**. `ORPHAN_PHASE_FILE` (warning) is unchanged and now means **only** *present but unreferenced*. **Migration:** a consumer that string-matched `doctor` / `validate` JSON for `ORPHAN_PHASE_FILE` to detect a missing referenced phase must switch to `MISSING_PHASE_FILE`; one that keys on `severity` (error vs warning) needs no change. `plan lint` already used `MISSING_PHASE_FILE` and is unaffected.
- **Behavior fix (error-code contract): `doctor` / `validate` now report a roadmap-referenced missing phase file as `MISSING_PHASE_FILE`, matching `plan lint`.** Previously `doctor` (and `validate`, which delegates to it) emitted `ORPHAN_PHASE_FILE` (severity `error`) for a `roadmap.yaml` reference whose phase file is absent or present-but-inaccessible — the opposite of that code's documented meaning ("a phase file present but not referenced"), so a user looking the code up read a contradictory definition. The condition now uses the code whose name matches it (`MISSING_PHASE_FILE`, _referenced but not present_), with **severity unchanged (`error`)**. `ORPHAN_PHASE_FILE` (warning) is unchanged and now means **only** _present but unreferenced_. **Migration:** a consumer that string-matched `doctor` / `validate` JSON for `ORPHAN_PHASE_FILE` to detect a missing referenced phase must switch to `MISSING_PHASE_FILE`; one that keys on `severity` (error vs warning) needs no change. `plan lint` already used `MISSING_PHASE_FILE` and is unaffected.
- **Docs: trimmed duplicated error-code tables from concept docs.** `concepts/finalization-reconciliation.md` and `concepts/governance.md` now link to `cli-contract.md` § Error codes for exit codes / triggers / envelopes instead of restating them in their own tables (matching the existing `concepts/runbook.md` pattern). Reference detail stays in its single owner; the concept docs keep only the mental model. No code change.

### Added
Expand All @@ -31,7 +50,7 @@ No changes yet.
existing archive primitives in the safe order (recover any pending
delete-intent journal → `compact-archive` all kinds → `archive-retention` →
compact again if a follow-up materialised → re-plan → `validate` → `plan
lint`) so an operator no longer has to remember and order the low-level verbs.
lint`) so an operator no longer has to remember and order the low-level verbs.
It adds **no new destructive semantics and no new persistent state** — a thin,
honest orchestration over `compactArchive` / `applyArchiveRetention` and their
journal recovery, writing nothing outside `.code-pact/state/archive` (no
Expand Down
Loading