simt-dev 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +162 -841
  2. package/README.md +21 -135
  3. package/agents/simt-agent.md +84 -0
  4. package/bin/simt.mjs +19 -55
  5. package/docs/decisions/ADR-009-skill-layout.md +1 -1
  6. package/docs/decisions/ADR-014-workspace-is-configuration.md +1 -1
  7. package/docs/decisions/ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md +1 -1
  8. package/docs/decisions/ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md +1 -1
  9. package/docs/decisions/ADR-106-the-harness-hook-runs-through-a-repo-shim.md +46 -0
  10. package/docs/decisions/ADR-107-an-install-can-name-one-harness-and-the-skipped-ones-are-named.md +51 -0
  11. package/docs/decisions/ADR-108-an-adoption-builds-the-index-and-a-command-refreshes-it-on-read.md +59 -0
  12. package/docs/decisions/ADR-109-simt-dev-is-its-own-consumer-and-the-guards-that-kept-it-from-being-one-are-retired.md +47 -0
  13. package/docs/decisions/ADR-110-the-lock-file-follows-the-manifest-name-and-the-old-name-is-read-until-the-next-write.md +43 -0
  14. package/docs/decisions/ADR-111-the-tool-ships-one-agent-rendered-per-harness-and-installs-it-with-init-and-a-command.md +75 -0
  15. package/docs/decisions/ADR-112-the-registry-is-what-simt-dev-ships-and-a-repo-owns-its-own-skills.md +81 -0
  16. package/docs/decisions/ADR-113-a-pre-push-that-carries-only-documentation-skips-the-test-gate-and-says-so.md +87 -0
  17. package/docs/decisions/ADR-114-the-bench-pairs-at-the-task-level-a-missing-cost-is-not-zero-and-an-unasked-cross-group-compare-is-refused.md +74 -0
  18. package/docs/decisions/ADR-115-the-index-stamps-its-schema-version-migrates-older-databases-in-place-and-serves-newer-ones-from-a-sidecar.md +69 -0
  19. package/docs/decisions/ADR-116-rust-support-reaches-the-example-path-the-indent-and-the-bench-runner.md +100 -0
  20. package/docs/decisions/ADR-117-the-darwin-release-builds-on-supported-macos-15-runners-and-a-re-run-is-idempotent.md +81 -0
  21. package/docs/decisions/ADR-118-the-bench-corpus-is-keyed-on-history-is-append-only-and-is-portable-as-a-sealed-document.md +91 -0
  22. package/docs/decisions/ADR-119-the-environment-variable-points-into-a-workspace-the-repo-declared.md +90 -0
  23. package/docs/decisions/ADR-120-a-pre-push-whose-tree-is-already-proven-green-skips-the-test-gate-on-that-evidence.md +96 -0
  24. package/docs/decisions/ADR-122-the-shims-move-into-the-state-directory-and-the-legacy-directory-removes-itself.md +94 -0
  25. package/docs/decisions/ADR-123-a-surplus-positional-is-not-refused-because-arity-is-not-in-the-source.md +57 -0
  26. package/docs/decisions/ADR-124-the-manifest-has-a-schema-in-the-tool-and-its-unknown-keys-stay-the-repositorys.md +64 -0
  27. package/docs/decisions/ADR-125-a-shared-context-belongs-to-a-read-and-a-writer-reads-directly.md +65 -0
  28. package/package.json +13 -3
  29. package/rules/core.md +9 -2
  30. package/rules/mdc/slice-commit.mdc +57 -4
  31. package/rules/mdc/test-gate.mdc +2 -0
  32. package/rules/stacks/android.md +3 -3
  33. package/rules/stacks/connectiq.md +2 -2
  34. package/rules/stacks/dart.md +1 -1
  35. package/rules/stacks/deno.md +1 -1
  36. package/rules/stacks/dotnet.md +1 -1
  37. package/rules/stacks/elixir.md +1 -1
  38. package/rules/stacks/go.md +1 -1
  39. package/rules/stacks/jvm.md +3 -2
  40. package/rules/stacks/node.md +2 -2
  41. package/rules/stacks/python.md +7 -6
  42. package/rules/stacks/ruby.md +1 -1
  43. package/rules/stacks/rust.md +1 -1
  44. package/rules/stacks/swift.md +1 -1
  45. package/rules/stacks/typescript.md +2 -2
  46. package/rules/stacks/uv.md +3 -2
  47. package/skills/simt-commands/SKILL.md +70 -0
  48. package/src/advice/advice.mjs +7 -3
  49. package/src/agenthooks/decide.mjs +141 -9
  50. package/src/agenthooks/opencode.mjs +72 -0
  51. package/src/agenthooks/prompt.mjs +10 -3
  52. package/src/agenthooks/render.mjs +186 -19
  53. package/src/agenthooks/shim.mjs +55 -0
  54. package/src/agents/render.mjs +277 -0
  55. package/src/api.mjs +29 -0
  56. package/src/argv.mjs +37 -3
  57. package/src/bench/ablate.mjs +31 -14
  58. package/src/bench/adapters.json +16 -0
  59. package/src/bench/corpus.mjs +150 -0
  60. package/src/bench/grade.mjs +23 -49
  61. package/src/bench/mine.mjs +247 -36
  62. package/src/bench/probes.mjs +104 -68
  63. package/src/bench/process.mjs +128 -0
  64. package/src/bench/report.mjs +260 -84
  65. package/src/bench/run.mjs +251 -150
  66. package/src/bench/variants.mjs +112 -40
  67. package/src/brief/assemble.mjs +44 -3
  68. package/src/ci/workflow.mjs +46 -14
  69. package/src/cli.mjs +45 -0
  70. package/src/commands/agent.mjs +205 -0
  71. package/src/commands/agenthook.mjs +113 -20
  72. package/src/commands/bench.mjs +192 -18
  73. package/src/commands/brief.mjs +5 -4
  74. package/src/commands/ci.mjs +2 -1
  75. package/src/commands/compare.mjs +50 -49
  76. package/src/commands/completions.mjs +2 -6
  77. package/src/commands/decide.mjs +10 -9
  78. package/src/commands/distill.mjs +4 -3
  79. package/src/commands/doctor.mjs +11 -7
  80. package/src/commands/evidence.mjs +19 -12
  81. package/src/commands/explain.mjs +0 -1
  82. package/src/commands/gate.mjs +98 -28
  83. package/src/commands/graph.mjs +20 -8
  84. package/src/commands/harness.mjs +3 -2
  85. package/src/commands/help.mjs +160 -31
  86. package/src/commands/hooks.mjs +163 -50
  87. package/src/commands/ignore.mjs +2 -1
  88. package/src/commands/impact.mjs +8 -9
  89. package/src/commands/index.mjs +278 -180
  90. package/src/commands/init.mjs +171 -38
  91. package/src/commands/lease.mjs +206 -39
  92. package/src/commands/lessons.mjs +72 -15
  93. package/src/commands/local.mjs +3 -3
  94. package/src/commands/map.mjs +47 -27
  95. package/src/commands/mcp.mjs +0 -1
  96. package/src/commands/pack.mjs +9 -6
  97. package/src/commands/plan.mjs +6 -5
  98. package/src/commands/plugin.mjs +3 -3
  99. package/src/commands/prbody.mjs +3 -3
  100. package/src/commands/repoindex.mjs +5 -3
  101. package/src/commands/review.mjs +2 -2
  102. package/src/commands/rules.mjs +124 -33
  103. package/src/commands/shared.mjs +2 -3
  104. package/src/commands/skills.mjs +82 -45
  105. package/src/commands/skillscompile.mjs +12 -12
  106. package/src/commands/skillsinstall.mjs +14 -2
  107. package/src/commands/slice.mjs +396 -26
  108. package/src/commands/spec.mjs +151 -0
  109. package/src/commands/status.mjs +4 -7
  110. package/src/commands/sync.mjs +50 -33
  111. package/src/commands/tests.mjs +11 -11
  112. package/src/commands/tokens.mjs +2 -2
  113. package/src/commands/undo.mjs +29 -31
  114. package/src/commands/upgrade.mjs +40 -4
  115. package/src/commands/why.mjs +19 -12
  116. package/src/compare/hooksstate.mjs +23 -1
  117. package/src/compare/learn.mjs +82 -57
  118. package/src/compare/parallel.mjs +50 -0
  119. package/src/compare/row.mjs +26 -3
  120. package/src/completions.mjs +5 -0
  121. package/src/context.mjs +64 -0
  122. package/src/decisions/dir.mjs +84 -0
  123. package/src/decisions/index-doc.mjs +46 -0
  124. package/src/decisions/index.mjs +109 -11
  125. package/src/diff.mjs +1 -1
  126. package/src/distill/distill.mjs +17 -2
  127. package/src/distill/engine.mjs +5 -1
  128. package/src/ecosystem/node-runner.mjs +144 -0
  129. package/src/explain.mjs +18 -6
  130. package/src/graph/load.mjs +42 -20
  131. package/src/hooks/capability.mjs +17 -4
  132. package/src/hooks/dispatcher.mjs +513 -36
  133. package/src/hooks/gates.mjs +0 -43
  134. package/src/hooks/resolve.mjs +11 -10
  135. package/src/hooks/shim.mjs +17 -9
  136. package/src/identity.mjs +96 -15
  137. package/src/index/extract.mjs +192 -11
  138. package/src/index/persist.mjs +307 -47
  139. package/src/index/store.mjs +263 -60
  140. package/src/index/tests.mjs +6 -35
  141. package/src/journal.mjs +372 -84
  142. package/src/kernel/card.mjs +37 -12
  143. package/src/kernel/checks.mjs +44 -9
  144. package/src/kernel/variants.mjs +27 -16
  145. package/src/lease.mjs +97 -15
  146. package/src/ledger/index.mjs +120 -25
  147. package/src/local/client.mjs +4 -6
  148. package/src/locate.mjs +33 -9
  149. package/src/manifest/schema.mjs +213 -0
  150. package/src/mcp/resources.mjs +12 -13
  151. package/src/mcp/server.mjs +151 -38
  152. package/src/mcp/tools.mjs +90 -16
  153. package/src/measure/session.mjs +3 -2
  154. package/src/memory/decide.mjs +98 -43
  155. package/src/memory/lessons.mjs +168 -33
  156. package/src/name.mjs +9 -0
  157. package/src/node-version.mjs +37 -0
  158. package/src/output/index.mjs +111 -3
  159. package/src/packs/manage.mjs +17 -3
  160. package/src/packs.mjs +20 -2
  161. package/src/plan/index.mjs +31 -8
  162. package/src/plan/template.mjs +27 -5
  163. package/src/plugins.mjs +6 -2
  164. package/src/prbody.mjs +7 -5
  165. package/src/projection/baselines.mjs +1 -1
  166. package/src/projection/disclosure.mjs +2 -2
  167. package/src/projection/loaders.mjs +41 -1
  168. package/src/projection/lock.mjs +31 -14
  169. package/src/projection/manifest.mjs +89 -53
  170. package/src/projection/markers.mjs +43 -3
  171. package/src/projection/mdc.mjs +34 -7
  172. package/src/projection/project.mjs +162 -18
  173. package/src/projection/rules.mjs +58 -6
  174. package/src/projection/surfaces.mjs +9 -1
  175. package/src/repo-root.mjs +88 -0
  176. package/src/resolve/body.mjs +4 -0
  177. package/src/resolve/fingerprint.mjs +24 -15
  178. package/src/resolve/local.mjs +58 -0
  179. package/src/review/critic.mjs +6 -3
  180. package/src/secrets.mjs +165 -22
  181. package/src/state.mjs +76 -0
  182. package/src/status.mjs +9 -4
  183. package/src/toolwords.mjs +8 -0
  184. package/src/tsconfig.mjs +39 -99
  185. package/src/workspace.mjs +55 -10
  186. package/templates/plan/tracker.json +1 -1
  187. package/docs/decisions/README.md +0 -591
@@ -1,591 +0,0 @@
1
- # Decisions
2
-
3
- Architecture decision records for the SIMT development ecosystem. One canonical home per
4
- decision; nothing here is duplicated into a repo's `AGENTS.md`.
5
-
6
- A decision is superseded by writing a new ADR with a higher number and editing the old
7
- record's status line — never by editing the ruling in place.
8
-
9
- | ADR | Decision | Status |
10
- |---|---|---|
11
- | [001](ADR-001-push-requires-approval.md) | Push requires explicit approval | accepted |
12
- | [002](ADR-002-refactor-blast-radius.md) | Blast radius bounds refactoring; a third copy is a defect | accepted |
13
- | [003](ADR-003-test-breadth.md) | Focused tests by default; a full suite needs a named trigger | accepted |
14
- | [004](ADR-004-hook-owns-format.md) | The hook owns format and lint for staged files | accepted |
15
- | [005](ADR-005-file-length.md) | File length: 400 review trigger, 1000 hard ceiling | accepted |
16
- | [006](ADR-006-coverage-bar.md) | Evidence discipline is central; the numeric bar is per-repo | accepted |
17
- | [007](ADR-007-section-skeleton.md) | One canonical section skeleton | accepted |
18
- | [008](ADR-008-verdict-vocabulary.md) | One review verdict vocabulary: three values | accepted |
19
- | [009](ADR-009-skill-layout.md) | Skills are `<name>/SKILL.md` with mandatory frontmatter | accepted |
20
- | [010](ADR-010-runner-invocation.md) | Invoke through the repo's own runner, never a package runner | accepted |
21
- | [011](ADR-011-windows-support.md) | Windows is supported from v1 for the CLI | **superseded by 012** |
22
- | [012](ADR-012-drop-windows-support.md) | Windows support dropped; POSIX only | accepted |
23
- | [013](ADR-013-genericity-by-facts-and-local-profiles.md) | Genericity comes from emitted facts and repo-local profiles | accepted |
24
- | [014](ADR-014-workspace-is-configuration.md) | The workspace is configuration, and a single repo is a supported shape | accepted |
25
- | [015](ADR-015-a-source-is-content-not-a-location.md) | A source is identified by its content; the repo is a location, not a precondition | accepted |
26
- | [016](ADR-016-a-divergent-rule-is-retired-not-merged.md) | A divergent rule is retired by a union, not merged by a variant | accepted |
27
- | [017](ADR-017-a-declared-gate-must-be-runnable.md) | A declared gate must be one the repo can actually run | accepted |
28
- | [018](ADR-018-an-unset-hooks-path-is-not-an-absent-hook.md) | An unset hooks path is not an absent hook | accepted |
29
- | [019](ADR-019-a-declared-command-is-the-runner.md) | A declared command is the runner; the remedy must be one the reader can take | accepted |
30
- | [020](ADR-020-a-rule-is-written-per-surface-and-pointed-not-copied.md) | A rule is written per surface, and pointed at — never copied | accepted |
31
- | [021](ADR-021-one-surface-per-repo.md) | One surface per repo, chosen or defaulted to opencode | accepted |
32
- | [022](ADR-022-a-key-simt-dev-reads-is-prefixed.md) | A key simt-dev reads is prefixed `simt-`; an editor's key is not | accepted |
33
- | [023](ADR-023-the-gate-ships-as-a-file-the-repo-owns.md) | The gate ships as bytes the repo owns, written once where Actions already runs | accepted · ruling 2 superseded by 024 |
34
- | [024](ADR-024-simt-dev-overwrites-its-own-gate-file.md) | simt-dev overwrites its own gate file, and no repository else's | accepted |
35
- | [025](ADR-025-a-baseline-is-a-region-in-a-file-the-repo-owns.md) | A baseline is a region in a file the repo owns, and only a file that can hold one | accepted · rulings 1 and 2 narrowed by 026 · ruling 8 withdrawn by 048 |
36
- | [026](ADR-026-a-config-without-a-region-is-a-file-the-repo-owns.md) | A config whose grammar cannot hold a region is a file the repo owns | accepted |
37
- | [027](ADR-027-the-one-gitattributes-line-that-is-neither-dangerous-nor-empty.md) | The one gitattributes line that is neither dangerous nor empty | accepted |
38
- | [028](ADR-028-a-base-file-is-a-floor-so-the-disagreement-it-cannot-repair-becomes-a-check.md) | A base file is a floor, so the disagreement it cannot repair becomes a check | accepted |
39
- | [029](ADR-029-the-pins-a-repository-declares-are-its-own.md) | The pins a repository declares are its own, so a check reports them and never writes them | accepted |
40
- | [030](ADR-030-what-a-plan-does-not-ship-is-a-decision-with-a-record.md) | What a plan does not ship is a decision with a record, not a silence | accepted |
41
- | [031](ADR-031-the-suite-stages-the-environment-it-needs.md) | The suite stages the environment it needs, because a test that inherits the author's directory is not evidence | accepted |
42
- | [032](ADR-032-provenance-is-a-content-digest-not-a-commit.md) | Provenance is a digest of the content that leaves this package, not a commit id | accepted |
43
- | [033](ADR-033-three-plan-rows-closed-by-decision-not-by-authoring.md) | Three plan rows are closed by ruling on them, not by authoring what they asked for | accepted |
44
- | [034](ADR-034-a-staged-tool-refuses-a-partially-staged-file.md) | A staged tool refuses a partially staged file rather than staging around it | accepted |
45
- | [035](ADR-035-one-write-decision-and-one-json-document.md) | One place decides whether a run may write, and one document says whether it did | accepted |
46
- | [036](ADR-036-a-writer-that-writes-says-so-and-the-instructions-naming-it-move-with-it.md) | A command that writes says so, and every instruction that names it moves with it | accepted |
47
- | [037](ADR-037-unchanged-means-writing-would-not-change-a-byte.md) | `unchanged` means writing would not change a byte, not that the body matches | accepted |
48
- | [038](ADR-038-the-gate-filter-belongs-to-every-manifest-writer.md) | The gate filter belongs to every writer of a manifest, not to `init` | accepted |
49
- | [039](ADR-039-a-ci-step-runs-a-form-that-can-fail.md) | A gate a CI step runs must have a form that can fail, and a refusal is a failure | accepted |
50
- | [040](ADR-040-the-last-writer-that-wrote-by-default-was-not-the-one-named.md) | The last writer writing by default was not the one the finding named | accepted |
51
- | [041](ADR-041-the-suite-installs-the-package-in-order-to-test-it.md) | The suite installs the package in order to test it | accepted |
52
- | [042](ADR-042-a-declared-glob-must-match-a-path-built-from-it.md) | A declared glob must match a path built from it | accepted |
53
- | [043](ADR-043-a-keyword-is-a-phrase-and-two-letters-is-a-word.md) | A keyword is a phrase, and two letters is a word | accepted |
54
- | [044](ADR-044-compatibility-is-not-evidence.md) | Compatibility is not evidence, and a resolver nobody measured is merely felt | accepted |
55
- | [045](ADR-045-a-dashboard-that-counts-a-defect.md) | A dashboard that counts a defect and will not name it is worse than one that does not count it | accepted |
56
- | [046](ADR-046-one-rule-one-copy.md) | One rule, one copy: a reader that reads AGENTS.md must not also get the file | accepted |
57
- | [047](ADR-047-a-profile-selects-on-what-a-repository-runs-on.md) | A profile selects on what a repository runs on, not on what it is written in | accepted · refines ADR-013 r1 |
58
- | [048](ADR-048-a-baseline-carries-only-keys-a-reader-honours.md) | A baseline carries only keys a reader honours | accepted · withdraws ADR-025 r8 |
59
- | [049](ADR-049-a-ruling-that-a-later-record-moved-says-so-where-it-is-printed.md) | A ruling that a later record moved says so where it is printed | accepted |
60
- | [050](ADR-050-a-byte-count-is-not-a-region-and-updated-is-not-a-change-of-rules.md) | A byte count is not a region, and `updated` is not a change of rules | accepted |
61
- | [051](ADR-051-a-pointer-is-the-readers-only-route-so-it-is-not-a-convenience.md) | A pointer is the reader's only route, so it is not a convenience | accepted |
62
- | [052](ADR-052-a-dependency-is-counted-against-the-budget-and-there-is-one-budget.md) | A dependency is counted against the budget, and there is one budget | accepted |
63
- | [053](ADR-053-the-node-floor-is-22-20-0.md) | The Node floor is 22.20.0 | accepted |
64
- | [054](ADR-054-the-digest-covers-every-byte-that-leaves-the-package.md) | The digest covers every byte that leaves the package, and a cause is read off the body | accepted · amends ADR-032 |
65
- | [055](ADR-055-a-status-line-travels-so-it-may-not-name-a-location.md) | A status line travels, so it may not name a location; prose is the record's own argument | accepted |
66
- | [056](ADR-056-three-names-one-of-which-is-cheap-to-move.md) | The command, the package and the project are three names, and only one of them is cheap to move | accepted · amends ADR-023 |
67
- | [057](ADR-057-an-identity-is-per-developer-and-a-repository-does-not-own-it.md) | An identity is per-developer, and a repository does not own it | accepted |
68
- | [058](ADR-058-one-tool-three-channels-and-the-order-is-forced.md) | One tool, three channels, and the order is forced | accepted |
69
- | [059](ADR-059-the-version-a-repository-runs-is-the-one-it-pinned.md) | The version a repository runs is the one it pinned, and the gate refuses otherwise | accepted |
70
- | [060](ADR-060-a-repository-with-nothing-to-run-is-adopted-and-says-so.md) | A repository with nothing to run is adopted and says so; a gate is verified where it runs | accepted |
71
- | [061](ADR-061-the-skill-registry-is-workspace-data.md) | The skill registry is workspace data, and the package ships none of it | **accepted** · 2026-10-12 · filed as S61 |
72
- | [062](ADR-062-a-fresh-adoption-seeds-the-gates-it-can-run.md) | A fresh adoption seeds the canonical gates it can run, and never more | **accepted** · 2026-10-13 · filed as S40 |
73
- | [063](ADR-063-the-adoption-escape-hatch-is-opt-in.md) | The adoption escape hatch is opt-in, and the default writes in place | **accepted** · 2026-10-13 · filed after a consumer asked why every adoption branched |
74
- | [064](ADR-064-the-context-meter-counts-what-the-tool-wrote.md) | The context meter counts what the tool wrote, and says what it did not | **accepted** · 2026-10-13 · filed after review 0002 S38 |
75
- | [065](ADR-065-a-pack-is-one-shared-rule-set-pinned-by-digest.md) | A pack is one shared rule set, vendored into the repository and pinned by digest | **accepted** · 2026-10-13 · filed as S39 |
76
- | [066](ADR-066-a-monorepo-projects-once-per-package.md) | A monorepo projects once per package | **accepted** · 2026-10-13 · filed as S41 |
77
- | [067](ADR-067-which-harnesses-read-agents-md-is-a-column.md) | Which harnesses read AGENTS.md is a column, and a row without a document gets none | **accepted** · 2026-10-13 · filed as S42 |
78
- | [068](ADR-068-the-mcp-revision-list-cites-what-was-read.md) | The revision list is a claim about revisions that were read | **accepted** · 2026-10-13 · filed as S43 |
79
- | [069](ADR-069-the-conformance-lint-checks-the-published-specification.md) | The conformance lint checks the published specification | **accepted** · 2026-10-13 · filed as S44 |
80
- | [070](ADR-070-the-json-payload-carries-its-own-version.md) | The JSON payload carries its own version | **accepted** · 2026-10-13 · filed as S51 |
81
- | [071](ADR-071-a-rule-that-can-be-narrowed-is-written-narrow.md) | A rule that can be narrowed is written narrow | **accepted** · 2026-10-14 · filed as S50 |
82
- | [072](ADR-072-the-budget-is-a-declaration-beside-the-gates.md) | The budget is a declaration beside the gates, not a number inside the projection | **accepted** · 2026-10-14 · filed as S38 |
83
- | [073](ADR-073-a-kernel-is-a-smaller-projection-the-repository-asks-for.md) | A kernel is a smaller projection the repository asks for, not one it is given | **accepted** · 2026-10-14 · filed as S38 (R07) · ruling 6 narrowed by ADR-084 |
84
- | [074](ADR-074-a-rule-and-a-decision-are-readable-by-uri.md) | A rule and a decision are addressable, so they are readable by URI | **accepted** · 2026-10-14 · filed as S43 |
85
- | [075](ADR-075-nothing-leaves-the-machine.md) | Nothing leaves the machine: no telemetry, local transcripts, loopback models by default | **accepted** · 2026-10-14 · filed as D7 (R06) |
86
- | [076](ADR-076-a-change-to-what-agents-read-is-measured.md) | A change to what agents read is measured before it ships, or labelled unmeasured in its record | **accepted** · 2026-10-15 · filed as D1 (R01) |
87
- | [077](ADR-077-the-command-card-leads-the-region-and-reads-committed-evidence.md) | The command card leads the region, and is derived from committed evidence only | **accepted** · 2026-10-16 · filed as R10 (plan 0003) · ruling 1 narrowed by ADR-086 |
88
- | [078](ADR-078-a-line-the-repository-already-proves-does-not-ship.md) | A line the repository already proves does not ship, and the author says so | **accepted** · 2026-10-16 · filed as R09 (plan 0003) |
89
- | [079](ADR-079-the-rules-are-enforced-at-the-tool-call-from-one-policy-table.md) | The rules are enforced at the tool call, from one policy table every harness renders | **accepted** · 2026-10-16 · filed as R15 (plan 0003) |
90
- | [080](ADR-080-the-tools-own-names-are-not-repositories-and-neither-reader-decides-by-shape.md) | The tool's own names are not repositories, and neither reader decides by shape | **accepted** · 2026-10-16 · settles what `rules why` calls a repository |
91
- | [081](ADR-081-a-tracker-is-read-through-the-repositorys-template.md) | A tracker is read through the repository's template | **accepted** · 2026-10-16 · rulings 1 and 2 superseded by ADR-082 |
92
- | [082](ADR-082-the-tracker-override-is-a-manifest-key.md) | The tracker override is a manifest key, and init keeps what it did not write | **accepted** · 2026-10-16 · supersedes ADR-081 rulings 1 and 2 |
93
- | [083](ADR-083-a-budget-is-met-by-cutting-the-kernel-and-hard-is-the-floor.md) | A budget is met by cutting the kernel, and the hard constraints are the floor | **accepted** · 2026-10-17 · filed as R08 (plan 0003) · ruling 7 narrowed by ADR-084 |
94
- | [084](ADR-084-a-workspace-carries-its-repeated-rules-once.md) | A workspace carries its repeated rules once, and the region does not read the reader's home | **accepted** · 2026-10-17 · filed as R11 (plan 0003) |
95
- | [085](ADR-085-the-region-ends-with-the-names-it-kept-out.md) | The region ends with the names of what it kept out | **accepted** · 2026-10-18 · filed as R12 (plan 0003) |
96
- | [086](ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md) | The stable prefix comes first, and the lock records both digests | **accepted** · 2026-10-18 · filed as R13 (plan 0003) |
97
- | [087](ADR-087-a-run-is-evidence-for-one-tree.md) | A run is evidence for one tree | **accepted** · 2026-10-18 · filed as R17 (plan 0003) |
98
- | [088](ADR-088-a-marked-line-is-enforced-by-a-checker.md) | A marked line is enforced by a checker | **accepted** · 2026-10-18 · filed as R19 (plan 0003) · ruling 3 narrowed by ADR-090 |
99
- | [089](ADR-089-the-local-index-is-a-cache-of-git-blobs.md) | The local index is a cache of git blobs | **accepted** · 2026-10-18 · filed as R20 (plan 0003) |
100
- | [090](ADR-090-an-optional-adapter-is-off-until-named.md) | An optional adapter is off until a repository names it | **accepted** · 2026-10-18 · filed as R21 (plan 0003) |
101
- | [091](ADR-091-the-map-ranks-files-a-task-mentions.md) | The map ranks the files a task mentions, and the files next to them | **accepted** · 2026-10-18 · filed as R22 (plan 0003) |
102
- | [092](ADR-092-tests-are-imports-conventions-and-coverage.md) | A test is an import, a conventional neighbour, or a coverage record | **accepted** · 2026-10-18 · filed as R24 (plan 0003) |
103
- | [093](ADR-093-why-names-what-governs-a-file.md) | why names what governs a file | **accepted** · 2026-10-18 · filed as R25 (plan 0003) |
104
- | [094](ADR-094-a-change-runs-the-tests-that-import-it.md) | a change runs the tests that import it | **accepted** · 2026-10-18 · filed as R16 (plan 0003) |
105
- | [095](ADR-095-gate-output-keeps-the-failures.md) | gate output keeps the failures | **accepted** · 2026-10-18 · filed as R18 (plan 0003) |
106
- | [096](ADR-096-impact-names-who-a-change-reaches.md) | impact names who a change reaches | **accepted** · 2026-10-18 · filed as R23 (plan 0003) |
107
- | [097](ADR-097-the-channels-publish-by-hand-and-the-version-rides-in-as-an-input.md) | the channels publish by hand, and the version rides in as an input | **accepted** · 2026-10-25 · ruling 3's Homebrew precondition is superseded by [ADR-098](ADR-098-the-fourth-channel-is-one-file-and-it-needs-no-toolchain.md), which also restates what each channel now waits on |
108
- | [098](ADR-098-the-fourth-channel-is-one-file-and-it-needs-no-toolchain.md) | The fourth channel is one file, and it needs no toolchain | **accepted** · 2026-10-26 · supersedes ADR-058 ruling 5 · narrows ADR-058 ruling 7 and ADR-097 ruling 3 · supersedes ADR-059 ruling 3 · ruling 3's cross-host byte-identicality narrowed by [ADR-099](ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md) |
109
- | [099](ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md) | the release verifies served bytes, and the formula mirrors them | **accepted** · 2026-10-27 · narrows ADR-098 ruling 3 |
110
- | [100](ADR-100-a-staged-diff-is-the-last-gate-before-history-and-it-runs-inside-the-tool.md) | a staged diff is the last gate before history, and it runs inside the tool | **accepted** · 2026-10-27 |
111
- | [101](ADR-101-a-file-lease-belongs-to-one-session-and-the-pre-edit-hook-refuses-another.md) | a file lease belongs to one session, and the pre-edit hook refuses another's edit | **accepted** · 2026-10-28 |
112
- | [102](ADR-102-the-two-queued-review-rows-are-closed-by-ruling.md) | the two rows review 0002 left queued are closed by ruling, not by authoring | **accepted** · 2026-10-28 |
113
- | [103](ADR-103-co-projected-duplicates-merge-down.md) | duplicates stand alone, fingerprints generalize, references spell out | **accepted** · 2026-10-28 |
114
- | [104](ADR-104-the-pre-tool-use-policy-reads-the-command-the-way-a-shell-reads-it.md) | the pre-tool-use policy reads the command the way a shell reads it | **accepted** · 2026-10-28 |
115
-
116
- ADR-001 to ADR-010 resolve the contradictions found across the 16 repos in the 2026-10-05
117
- audit; each record names the repos whose text it replaces. ADR-011 and ADR-012 are the
118
- platform decision for the CLI described in
119
- [plan 0002](../plans/0002-simt-dev-cli.md), and they are a worked example of the
120
- supersession rule above: 011 was accepted, 012 reversed it the same day, and 011's record was
121
- kept rather than rewritten because the cost table it contains is the evidence 012 relies on.
122
- ADR-013 is the same rule applied to the tool rather than to the repos: the mechanism carries
123
- no product taxonomy, and adding an ecosystem is a profile file rather than a code change.
124
- ADR-014 and ADR-015 are the same rule applied to the **filesystem**. ADR-014 made the workspace
125
- optional; ADR-015 found that a repository is itself a location for a declared source, so a clone of
126
- one repo is self-sufficient with no configuration at all. Both were found by running the tool the
127
- way a consumer runs it, not the way its author does: the tool's own directory layout turned out to
128
- be part of its interface, and every test that ran from the checkout could not see that it only
129
- worked from the checkout.
130
-
131
- ADR-016 applies the rule to rule content itself. The estate's three always-on `.mdc` families
132
- existed in eight copies, none byte-identical, the worst pair differing by one byte while hiding
133
- three semantic losses. The canonical body is therefore the **union** of what every copy needed —
134
- not a per-stack variant, because two of the differences were rules each repo was missing rather
135
- than a choice either repo made.
136
-
137
- ADR-031 is the same lesson arriving from the other end. ADR-014 and ADR-015 fixed the tool's
138
- dependence on the checkout; ADR-031 fixes the **suite's**, which had quietly reintroduced it —
139
- nineteen tests read skill bodies out of sibling repositories and passed only on a machine that
140
- had them. The gate had been red on every push since the first baseline record landed. What makes
141
- this one worth a paragraph rather than a table row is the third cause it found: two tests that
142
- passed for a reason that had nothing to do with the code, because the checkout's directory
143
- happened to be named `simt-dev`. Those failed on nobody's machine and would have failed for
144
- anyone who cloned the repository under a different name. A green test that asserts a folder's
145
- name is worse than a red one, because it looks like evidence.
146
-
147
- ADR-032 is that lesson inside the tool rather than around it. The provenance stamp was read
148
- with `git rev-parse HEAD`, run in the package root — and for anyone who installed the package
149
- into a repository, which is the entire audience, git walks *up* out of `node_modules` and
150
- answers with the **consumer's** HEAD. It succeeded, so no fallback could catch it. Every
151
- commit a consumer made moved the stamp, including commits touching nothing the tool projects,
152
- so `check` reported drift on all three generated files and exited 1 after an unrelated commit,
153
- and `upgrade` named a cause that was false. Where git could not answer at all the answer was
154
- `unknown`, which the marker grammar cannot read back and `upgrade` compared against a real pin
155
- as though the two were versions. The stamp now identifies the content that leaves the package,
156
- which is the one thing every install can compute.
157
-
158
- ADR-033 is the same instinct applied to a plan instead of a tool. Closing plan 0001 meant auditing
159
- each row against the tree, and three rows asked for things that had never been decided: seven agent
160
- policies with no surviving source anywhere in the estate, a skill-collapse step that a mechanism
161
- landed two hours after the plan was written already answered, and two `local.properties` files that
162
- were committed on purpose. Each is closed by saying so, because the failure the plan's own text
163
- invites is a reader concluding a mechanism is outstanding and going to build it.
164
-
165
- ADR-034 is the same instinct in a hook, and the second time the defect was a promise the code
166
- already made in writing. `src/hooks/gates.mjs` defines a staged gate as one that runs over the
167
- staged files only, precisely so that "whole-repo formatting from a pre-commit hook" cannot
168
- "rewrite unstaged work the author did not ask to touch" — and the dispatcher then ran
169
- `git add` on every staged path. A file staged with `git add -p` came back with its unstaged
170
- hunk replaced, not merely committed, and the gate said nothing. The same loop also fed
171
- staged deletions to `git add`, whose failure was swallowed, so a commit holding a deletion and
172
- a formattable file recorded unformatted bytes silently. Both are the shape this estate's rules
173
- keep warning about: a control that appears to hold, reports pass, and does not.
174
-
175
- ADR-035 is the same thing measured across a whole command surface instead of one control.
176
- Six commands disagreed about what `--yes`, `--dry-run` and `--json` mean: `upgrade` read
177
- `--yes` and ignored `--dry-run`, `skills install` read neither and printed "nothing written"
178
- on the path that wrote, and `doctor --json` and `hooks status --json` both reported `ok: true`
179
- while the same commands in a terminal exited non-zero. Two of those are the shape above
180
- again — a check that appears to hold and reports pass. The difference is where the fix goes:
181
- one function decides whether a run may write, and one table asserts the JSON contract for
182
- every command at once, because a contract checked one command at a time is checked by
183
- whoever remembers.
184
-
185
- ADR-036 is the deferral that record made, settled. ADR-035 left `sync` writing by default
186
- because the change belonged to a slice that depended on it, and wrote the reason down
187
- twice rather than quietly half-applying it. Measured afterwards, `sync` was the only
188
- writer left that rewrote a file a bare invocation had no permission to touch — and it is
189
- the command a caller reaches for most, because it is the one that regenerates the text in
190
- front of them. The second half is the half that would have been easy to skip: the note
191
- inside every generated region and the comment in every manifest both tell the reader to
192
- run that command, and both ship into repositories that have no other copy of the
193
- instruction. A flag that changes what a command does without changing what the tool says
194
- about it leaves a permanently-false instruction in every repository in the estate, which is
195
- the same failure as a check that reports pass and does not hold — one layer up.
196
-
197
- ADR-037 is the same failure inside the projection primitive, and the first record here whose
198
- finding arrived with a line number and turned out to be two branches over. Review 0002's S29
199
- pointed at the code that appends a region to a document that has none; that branch was
200
- already correct. The blank line was missing in the code that *replaces* one, so the defect
201
- only appeared once a repository already had a region — which is every repository that has
202
- been adopted. The list case is worth reading for what it says about the failure: with no
203
- separating gap, a Markdown formatter reads the whole region as a continuation of the last
204
- list item and indents every line of it, so the file comes back changed in a way no amount
205
- of careful body comparison would notice. The second half is the part that made the first
206
- worth doing: a body that matched behind a wrong seam was reported `unchanged`, so `check`
207
- found nothing to report and `sync` had nothing to repair, and the repository was red on its
208
- own formatter with no remedy on offer. Fixing the seam without that half would have shipped
209
- a fix that worked once, for the one repository whose rules happened to change next.
210
-
211
- ADR-038 is the same failure once more, and the smallest instance of it so far: a decision
212
- record that named the right rule and attributed it to the wrong command. ADR-017 ruled that
213
- a gate is declared only if the repo can run it, and wrote *"`init` filters the stack table's
214
- proposals"* — so for as long as `init` was the only writer of a manifest, the belief and the
215
- code agreed. `skills install` also writes one, for a repo that has none, and it did not
216
- probe. The result was four gates in a repo with no scripts and no formatter, `check` red on
217
- all four, and a pre-commit hook that blocked the first commit it was installed in front of.
218
- Nothing about the rule was wrong; only the sentence that carried it. That is what the
219
- `Affects:` line on a record is for, and this record amends one in place of editing it —
220
- because a reader who finds the record and trusts it has to be able to trust the whole of it.
221
-
222
- ADR-039 is the same shape turned on the tool's own controls, and it is the only one of these
223
- whose subject is a gate that was enforcing a gate. This repository's workflow carries a step
224
- named "the gate copy in this repo is current", commented as the place the drift would be
225
- caught, running `simt-dev ci`. With a hand edit in that copy, `ci` printed the drift and
226
- exited 0 — so the step read the thing it was written to catch, said it out loud, and passed.
227
- Every other record here is about a check that reports pass and does not; this one is about
228
- the check on the checks. The same slice found two smaller instances of the same habit in the
229
- same command: `--json --dry-run` printed no document at all, because the mode guard was in
230
- the wrong place, and a refusal in a repository that adopted simt-dev printed a paragraph
231
- saying it was refused directly above `ok: true` and exited 0.
232
-
233
- ADR-040 is the only one here that says a previous record's *premise* was wrong, and it is worth
234
- reading for the shape rather than the command. Review 0002 opened Wave 0 with "`sync` is the only
235
- writer that writes by default" and named five siblings that "all preview first". Four were. The
236
- fifth, `hooks install`, read `flags.yes` and `flags.dryRun` directly, imported no write decision
237
- at all, and wrote the shims and repointed `core.hooksPath` whenever neither flag said otherwise —
238
- in the ordinary case, where ADR-018's takeover consent never fired. Three strings that ship into
239
- adopting repositories assumed the preview, one of them inside the shim being installed, and 586
240
- tests passed. What makes it a rule rather than a fix is that the same commit had to amend a
241
- comment written the day before, which called `hooks install` a previewing writer; a comment that
242
- enumerates which commands follow a rule is a claim about code its file does not own, and the next
243
- reader has no cheap way to check it. So the writers are a set, the set is checked by a table, and
244
- the table asserts the exit code as well as the bytes — because a command that *refuses* also
245
- changes nothing, and "wrote nothing" is the one claim a refusal satisfies for free.
246
-
247
- ADR-041 is the one that closes the gap those other records kept falling into. Every test in this
248
- repository imported from `../src`, which is right for a unit and blind to the artefact: S01 shipped
249
- a package whose `files` list and whose runtime reads disagreed, with the whole suite green, because
250
- no test was reading the tarball. The fix is not a better assertion but a different subject — pack
251
- the working tree, install it with `--offline`, and drive `node_modules/.bin/simt-dev`. `--offline`
252
- is the load-bearing word, and it is a constraint rather than a setting: the package has no
253
- dependencies to install, so adding a build-time or test-time tool starts costing a network on a
254
- cold runner, and a suite that fails there gets skipped, and a skipped test is indistinguishable
255
- from a passing one. The same constraint is why one thing that test cannot assert is recorded as
256
- open instead of worked around: there is no formatter to run over the output, so S29's second
257
- acceptance half stays pending and the seam it would have caught is asserted structurally in
258
- `markers.test.mjs` instead.
259
-
260
- ADR-042 is the smallest instance of the same habit: a declared value nobody ever executes. 13 of the
261
- registry's 65 path globs began with a double star, which compiled to an invalid regex that a `catch`
262
- turned into `false`, so the heaviest signal the resolver has was silently dropped for every skill
263
- that used one. The lint rule that keeps the registry honest asked only whether `paths` was *present* —
264
- the same question, in the same file, that `checkStack` had already answered for stack tags by
265
- rejecting a tag the detector cannot emit. A glob that matches nothing is that failure under another
266
- field name, so `graph lint` now requires each declared glob to match a path built from itself. Its
267
- third ruling is the part worth carrying forward: the registry-wide test reads the same generator the
268
- lint rule validates, so narrowing the generator narrows the test in step, and the test passed with
269
- the generator sabotaged. A check that shares its subject with the thing it checks has to have its own
270
- assertion about that subject.
271
-
272
- ADR-043 is the same failure in the other half of the resolver, and the word that connects them is
273
- *declared*. A hand-authored field is checked for being present and well-formed, which is a question
274
- about the file, while the resolver asks whether the value can reach anything — and a value nobody
275
- executed costs nothing to write. Thirteen globs matched nothing (ADR-042); thirteen keywords could
276
- never be produced by a task, including `durable object`, declared on three skills and dead on all
277
- three. Two filters were responsible: a tokenizer that discarded every word of length two, which in
278
- this domain is where `d1`, `r2`, `kv` and `ci` live, and a keyword comparison that asked whether one
279
- task token equalled the declaration, which no multi-word keyword can ever satisfy. Both were filters
280
- on precision applied to a registry whose values were never reachable in the first place — the same
281
- inversion, in the same file, one field over. It also records what the fix costs, because it does
282
- cost something: six two-letter stopwords now reach the summary signal, while `the` already selected
283
- eleven skills before the change. The honest reading is that S04's threshold was too low all along,
284
- and hiding that by putting the floor back to 3 would make `d1` disappear again.
285
-
286
- ADR-044 is what came after the two above, and it is the first of the three that is about the shape of
287
- an argument rather than about a broken value. The resolver asked two questions of a skill — *is this
288
- compatible with my repo* and *is this about my task* — and scored them into one number. The gate had
289
- already answered the first, so a skill matching three stack tags reached 45 points having said nothing
290
- about the task, and any score above zero selected. Meanwhile a shared word of English was worth 8 and
291
- cleared the bar, so a brief for "fix a typo in the README" filled a 20 KB budget with launch galaxies.
292
- The rule it lands on is one sentence: compatibility is a precondition, not evidence, and a
293
- precondition must not be counted twice. It also carries the first gold corpus, because plan 0002 has
294
- claimed an `eval` corpus since before this file existed and every ranking change until now was argued
295
- from examples. The corpus immediately earned its keep by failing a case where the resolver was right and
296
- the author was wrong — two skills written into a rejection list both declare the `contract`
297
- capability, and a hand-authored gold set is an opinion written down. Its fourth mutation is the one to
298
- remember: reverting the third of three commands to its own older copy of the rule passed all 621 tests,
299
- because nothing checked the set. ADR-035 said a promise about a set of commands holds only while
300
- something checks the set; that sentence was written about seven writers and turned out to be about
301
- three readers too.
302
-
303
- ADR-046 is the third of these records to be settled by running the command against the estate
304
- rather than by reading the code, and the first to overturn an earlier ruling on a fact about a
305
- vendor. ADR-021 decided that a Cursor reader could not be reached through `AGENTS.md` — so a repo on
306
- `opencode,cursor` was given the same three rules twice, once folded and once in `.mdc`, across five
307
- repositories and 28 KB. Cursor's documentation says plainly that it reads `AGENTS.md`. The claim was
308
- false when written, and it was false in a way simt-dev's own surface table already contradicted: the
309
- `readers` line on the opencode row names Cursor as reading `AGENTS.md` natively. A decision that
310
- depends on a fact should be checked against the file that records facts, and here that file was one
311
- row away.
312
-
313
- Its more useful lesson is the one that cost the most. The first version of the change made the
314
- estate go *quiet*: `staleRuleFiles` fell from 17 to 0 and every one of those files was still on
315
- disk, still being read twice. Then the fix for that scanned the wrong set and reported nothing at
316
- all, because a file becomes orphaned exactly when a repo drops the surface that wrote it. Both were
317
- found by running `compare` over sixteen repositories, not by reading the code. The flip side is worse:
318
- three of six mutations passed all 627 tests, including the one that would have made a gate nothing
319
- can satisfy — a file simt-dev will never write again and may never delete. A feature whose failure
320
- mode is "the tool silently stops looking at something it wrote" needs a negative control, because
321
- the broken version returns an empty list and passes every positive test.
322
-
323
- ADR-047 is the same rule applied to what a profile *selects on*, and it refines ADR-013 ruling 1
324
- rather than overturning it. ADR-013 promised genericity from emitted facts and repo-local
325
- profiles, and said detection emits facts and profiles select on facts. But the shipped
326
- `simt-applies` lists were keyed on language tags — `typescript`, `gradle`, `react` — which name
327
- what a repo is *written in*, not what it *runs on*. So any TypeScript library received Cloudflare
328
- Workers rules (D1, Durable Objects, wrangler), a Spring backend on Gradle received Compose and
329
- Wear OS rules, a React Native app received web CSS rules, and a Poetry project received `uv`
330
- rules. The defect was invisible in the usual way: the selection was deterministic, every test
331
- passed, and the profile simply landed in the wrong ecosystem. The fix is data plus `has-*`
332
- facts, exactly as ADR-013 requires — no engine change — and the one piece that needed a mechanism
333
- was `has-android-manifest`, a nested path, which is the glob walk S07's dependency closed.
334
-
335
- ADR-048 is the first record here to withdraw a value rather than a mechanism, and it
336
- found it by reading a format's specification instead of its own source. The shared
337
- `.editorconfig` shipped `[prettier] singleQuote = true` under a comment explaining why
338
- that section was the right home for the estate's one formatting disagreement. An
339
- editorconfig section header is a glob over paths, so `[prettier]` matched a file named
340
- `prettier`; and `singleQuote` is not one of the nine keys the specification defines, nor
341
- one of the six properties Prettier maps. The specification says what an undefined key
342
- does — cores accept and report it, plugins ignore it — which is the worst possible
343
- outcome: a line that parses, in a file that was current, enforcing nothing. Nothing in
344
- this tool could have seen it, because the gate compares bytes and the bytes agreed with
345
- the shipped body. The spelling that does work is `quote_type`, and the survey says not to
346
- use it: three of the five repositories running Prettier already state `singleQuote` and
347
- two do not, so a shared value reformats every source file in those two on the day they
348
- adopt the tool. The lesson is the narrowest one in this file — a baseline earns its place
349
- by naming a key a reader honours, and the ability to hold a comment says nothing about
350
- whether anything reads what is inside.
351
-
352
- ADR-049 is the same failure one level down, and it is the reason this index exists: a
353
- citation has to be resolvable, or it is decoration. `rules why ADR-023` printed the status
354
- `ruling 2 superseded by` — a sentence with no object, because the status is a paragraph and
355
- the parser read one line of it — and then printed ruling 2 as a ruling in force, which is
356
- the reversal the module's own header names as its failure mode. Making the status a
357
- paragraph is half the fix and the other half is a trap: the obvious pattern for
358
- whole-record supersession then matches *ruling 2 superseded by ADR-024*, and five rulings in
359
- that record that the status line itself says stand would have been dropped by the field
360
- that exists to stop exactly that. Underneath both halves is the thing neither the finding
361
- nor the fix mentioned — the rulings are numbered in five different ways across the records
362
- and the extractor read one, so ADR-045 declared six rulings and printed one, and ADR-013
363
- printed the literal text `### 2.` to an agent. A supersession names a ruling by number, and
364
- a number that cannot be located cannot be reported as no longer in force. The record's
365
- ninth ruling is the mutation that earned its keep: dropping the ordinal from `**One.**`
366
- passes every test in the suite, because no record in the estate has both a word-numbered
367
- ruling and a partial supersession to catch it — the failure ADR-042 recorded, reproduced
368
- inside the fix for it.
369
-
370
- ADR-050 is the same habit in a command rather than a reader, and its finding named one line
371
- of code where the defect was two questions. `upgrade` decided a repository had no region by
372
- asking whether its `AGENTS.md` was empty, which a hand-written one never is — so a version
373
- bump wrote nine kilobytes of rules into a repository that had never asked for any. But the
374
- obvious repair, asking whether every *region* is absent, reproduces it exactly: the estate
375
- builds this state by adopting and then replacing `AGENTS.md` by hand, which leaves the
376
- baselines' regions in place, and a guard that sees two regions concludes the repository is
377
- adopted. The question was never about all the files. The second half is a trap of the same
378
- shape: ADR-037 made a correct body behind a wrong seam report as `updated` so that `sync`
379
- would repair it, which gave one field two meanings, and the command whose entire job is to
380
- say *why* a repository is behind was reporting a formatting repair as a change of policy.
381
- The reader is told to diff rules that did not move. Both are the same mistake: a field read
382
- for the thing it was not.
383
-
384
- ADR-051 is the same mistake about a *file*, and it is worth reading for where the belief
385
- came from. `CLAUDE.md` was classified as a convenience and a misaimed pointer made the gate
386
- go green, on the reasoning that "the editors that matter already read `AGENTS.md`" — which
387
- this repository's own pointer table refutes with a quotation from Claude Code's
388
- documentation: *"Claude reads CLAUDE.md by default and AGENTS.md only as a fallback."* A
389
- pointer is not a second copy of a file, it is the route to one, and the old test named
390
- DeepSeek's loader rendering a drifted copy beside its twin. That observation is true and it
391
- is about duplication; a symlink aimed elsewhere is not duplication, it is a reader looking
392
- at the wrong file. The belief was written down in a test, so the finding it produced could
393
- not see it. The second half was worse and quieter: a directory at `CLAUDE.md` — which is
394
- where Claude Code keeps per-project instructions — was classified as *absent*, so `check`
395
- said nothing and `sync` crashed with `EEXIST` after writing every other target, naming
396
- `simt-dev doctor`, which reports nothing about it either. The note that would have said so
397
- printed `undefined bytes`, and `undefined` in a report reads as nothing at a glance.
398
-
399
- ADR-052 is the same habit in the resolver, and it is the first record here where the *fix*
400
- was the second copy of the logic rather than the first. The budget loop existed in `skills
401
- brief` and in the MCP tool, and both tested `entry.via.size > 0` and inlined a dependency
402
- whatever it weighed — so `--skill parallel-feature-team --budget 2000` resolved **13,503
403
- bytes against a 2,000-byte budget**, with nothing in the output saying so. The comment gave
404
- the reason: *"a skill that is useless without its dependency is worse than a large context,
405
- because it silently misleads."* The premise is right and the conclusion does not follow: a
406
- missing dependency is fixed by a line in the output, and an unbounded budget is not a fix
407
- for anything. The copies had also drifted — one tested `deferred` first and never inlined
408
- one, the other tested it second and would inline 384 KB — so the same question had two
409
- answers and neither could see the other. ADR-035's sentence about a promise about a *set*
410
- of readers holds only while something checks the set; here the check is a test that drives
411
- both surfaces and compares them, because two copies asserted separately drift and two
412
- copies asserted against each other do not.
413
-
414
- ADR-054 is the same habit found in the stamp itself, and it is worth reading for the order
415
- the two defects arrived in. ADR-032 ruled that the digest covers `rules/` and `graph/` and
416
- deliberately excludes `src/`, on reasoning that still holds: a refactor that projects
417
- byte-identical bytes must not move a consumer's stamp. But the exclusion was drawn around a
418
- *directory*, and the shared `.editorconfig` and `.gitattributes` blocks are not in one — they
419
- are two string constants in `src/projection/baselines.mjs`, and every adopting repository
420
- receives them. By ADR-015's own rule a source is identified by its content rather than by the
421
- file it lives in, so those bodies were excluded content, not excluded code. What exposed it
422
- was an unrelated slice: deleting seven inert lines from a shipped baseline was the first
423
- change here that moved bytes out of `src/` without moving the digest. `check` caught it,
424
- because the gate compares bytes. `upgrade` did not, and printed a pin that was unchanged
425
- beside a restamped region, and then named the cause as *the rules changed* — two false
426
- sentences, one caused by the other. With the stamp silent about a baseline, the only cause
427
- left to report was the one least likely to be true, and the reader is sent to diff `rules/`
428
- when the change is in `.editorconfig`. So the fix is two halves that have to land together:
429
- the digest now covers the rendered baseline bodies and names them by the file they become,
430
- and `upgrade` reads its cause off the projected body with the two kinds of content counted
431
- apart. The second half is the one worth keeping, because it is what makes a stamp that
432
- cannot see a change stop being able to invent one.
433
-
434
- ADR-055 is the same rule applied to the record index, and it is worth reading for a finding
435
- that grew while it was being fixed. The review filed this as "two records out of
436
- forty-eight, pre-existing". Re-measuring the corpus said five — three of them written after
437
- that measurement, including two in this cycle, by the same convention each time: put the
438
- clause in `Status:`, because `Status:` is the line the tool reads. It is the one line
439
- guaranteed to travel, into repositories that own none of this package's files, so the path
440
- arrives there resolving against nothing. `Affects:` is the field for it and is deliberately
441
- not printed; five records had one available and used the other. What makes the record worth
442
- keeping is ruling four and its cost: the ruling covers `Status:` and deliberately not the
443
- record's own argument, because `docs/plans/` means this package's plan in one record and the
444
- reader's own plans in another, and four records use that exact string for both — so a
445
- redaction there would corrupt them to protect six. Six prose leaks therefore remain, and a
446
- test asserts the count and the ids rather than leaving them as an unmeasured shrug. The
447
- docstring that used to claim the whole output "never contains a path" is withdrawn: it
448
- asserted a property the function never had, which is the same defect as a citation that
449
- cannot be resolved — a sentence that reads like evidence and carries none.
450
-
451
- ADR-059 is the first record here whose subject is the version of the tool itself, and it
452
- exists because a check that runs from the wrong binary is a pass that never happened. ADR-010
453
- allowed a tool that is not a project dependency to be invoked directly, *provided its version
454
- is pinned* — and for a repository without npm that "pinned" half had no mechanism. The version
455
- on `PATH` was whatever the last global install left there, and the gate that ran on commit was
456
- the one in it: a green tick from a check running a different gate than CI is worse than a red
457
- build, because it is the failure that looks like evidence. The record rules that the version a
458
- repository adopted is recorded in the manifest, that the gate refuses when the running binary
459
- differs, and that the install and the remedy are per kind — so the check CI runs is the one the
460
- machine remedy names. Its most load-bearing consequence is the one that keeps it from becoming a
461
- trap: a repository adopted before the field existed has nothing to compare against, so it is
462
- skipped rather than failed, and reported as drift instead — because a gate that turns red on the
463
- day a check ships, for a mismatch nobody can resolve until they re-adopt, is a gate no one will
464
- trust again.
465
-
466
- ## The rule these records enforce
467
-
468
- Every shared rule has exactly **one** canonical home. Every other location is either a
469
- generated region or a thin pointer. Repeated policy text, duplicated source-of-truth, verbose
470
- prose and redundant examples are **review blockers**, not style nits.
471
-
472
- This ruling came out of the estate's own review agent, which already carries it as a checklist
473
- item — in exactly one file, aimed at exactly the duplication the audit found.
474
-
475
- ADR-017, ADR-018 and the one before them share a cause worth naming. Each was found by
476
- running the tool the way a consumer runs it — against a real repository, doing the thing a
477
- person would do — and not by a unit test. A test exercises the function; the defect lived in
478
- what the function was asked, in a location it never looked, or on a surface the JSON never
479
- carried. Two of the three were also cases of the same question being answered in two places:
480
- ADR-018's guard could not see the default hooks directory because it looked only at a config
481
- key, and `hooks status` carried its own copy of the read logic the shared module already had.
482
-
483
- A fourth joins them. ADR-019 is the same shape one layer over: `simt init` dropped all
484
- five gates on `repo-05` and told the reader to add a script to a `package.json` the
485
- repository will never have. The facts were right, the remedy was not followable, and once
486
- the repository declared what it does have, the dispatcher, `check` and `hooks status`
487
- gave three different answers about one manifest. Every one of these shipped green because
488
- the verification stopped at the tool's own gate.
489
-
490
- A fifth joins them, and it is the first about *where* the rules land rather than what they
491
- say. ADR-020 found that the tool's own conflict scanner read `.github/instructions/` while
492
- the projector wrote nothing there, so three of the four editors that read this repository's
493
- rules never received the always-on process rules at all — Cursor did. The fix was not a
494
- missing branch but a missing table: every editor is now a named row carrying the document it
495
- was verified against, and the test suite fails if that row emits a frontmatter key the vendor
496
- does not document. The failure it would have caught is quiet in both directions — an editor
497
- that ignores an unknown key, and an editor that discards a rule whose `trigger` it does not
498
- recognise, which is what Antigravity documents.
499
-
500
- A sixth is about a key rather than a byte, and it came from a question asked about this
501
- repository's own rule files rather than from a command anyone ran. A canonical `.mdc`
502
- frontmatter block holds Cursor's keys and simt-dev's in one list, and `alwaysApply: true`
503
- sat four lines away from `applies: always` with nothing to say which reader owned which.
504
- ADR-022 gives every key this tool reads a `simt-` prefix, leaves the vendors' spellings
505
- alone, and makes an unrecognised key a reported defect — because the mistake it looks like
506
- is the one ADR-016 already shipped: a rule that reaches no repository because its
507
- selection key was missing.
508
-
509
- A seventh is about the gate itself. Plan 1 promised a reusable workflow referenced by
510
- every consumer, and nothing in this repository had a `.github/` directory. A `uses:`
511
- line satisfies the promise by pointing every reader at bytes they do not have — the exact
512
- defect the rule at the top of this file exists to prevent — so ADR-023 copies the gate
513
- into `.github/workflows/` instead, writes it once, never rewrites it, and skips it
514
- entirely for a repo that does not run GitHub Actions. The record also states what the
515
- choice costs: a template improvement does not reach a repo that already has the file, so
516
- that limitation is written down rather than left for someone to rediscover as a bug.
517
-
518
- An eighth narrows it, and the reason it was needed is the shape of ADR-023's own cost.
519
- Write-once is right for a repo whose file may contain their deployment job, and wrong for
520
- the one repository that owns the template: a gate file that is a frozen copy of the gate is
521
- a second gate nobody maintains, and ADR-023 ruling 4 means nothing would ever report the
522
- gap. ADR-024 gives the exception exactly one boundary — a path, not a flag, because a flag
523
- is a spelling for the wrong answer — and refuses `simt-dev ci` everywhere else. Both copies
524
- say which world they are in, in their own header, because the reader of a diff in this
525
- repository should not have to guess who changed their CI.
526
-
527
- A ninth is about a file rather than a byte. The plan's tooling row asks for eight
528
- baselines and the same plan, eight sections earlier, already said how they should work:
529
- a generated region, so local content is never clobbered. Six of the eight are JSON or bare
530
- strings and cannot hold a region, which is not a reason to ship them anyway — it is the
531
- answer. `.editorconfig` can, so it is the baseline, and it goes in first so the repo's own
532
- settings keep winning underneath it. `end_of_line` is left out on purpose: it is a claim
533
- about line endings, which is `.gitattributes`' claim to make, and a repository that wanted
534
- CRLF could only opt out by deleting the indentation settings with it.
535
-
536
- A tenth supplies the counterexample the ninth predicted, and it arrives as a file that was
537
- already owed: no repository in the estate had a Dependabot config, and the plan named that
538
- as missing before any of this existed. The ninth said a config whose grammar cannot hold a
539
- comment is ruled out as a baseline, and left its consequences promising that the next such
540
- file would need a different mechanism. This is that mechanism, and it is not a new idea —
541
- it is the gate's own ownership rule, unchanged, pointed at a file whose `updates:` is a YAML
542
- list and therefore has nowhere to put a region. The lesson is narrow and worth stating
543
- plainly: partial ownership was never the reason the gate file is write-once, and a rule read
544
- as depending on mergeability will predict the wrong answer here. What detection buys is
545
- different — an entry per manifest the repo actually has, so the config never names an
546
- ecosystem that would sit there opening no pull requests.
547
-
548
- An eleventh goes back to a deferral and finds it was one line too broad. The ninth refused
549
- `.gitattributes` because every line that earns its place in a shared region changes what git
550
- does to the working tree, and concluded the region would be "either dangerous or empty" —
551
- which is true of every attribute worth sharing and false of the file. Thirteen of sixteen
552
- repositories had none at all; the three that did agreed about almost nothing. What survives
553
- is one line, and its safety is a single word: `text=auto` detects rather than instructs, so
554
- `* text eol=lf` — the usual way a repository quietly corrupts its own binaries — is the form
555
- the shared region refuses to use. Line endings were left unruled in the ninth because a
556
- repository wanting CRLF could only opt out by deleting the region; here it opts out with one
557
- line beneath it, which is what last-match-wins is for.
558
-
559
- A twelfth turns out to be about a limit rather than a mechanism, and the limit is the
560
- record. Row 5 named two tsconfig problems and they look like one: seven strictness flags
561
- missing from a repository, and one option spelled `Bundler` in three repos and `bundler` in
562
- a fourth. `tsconfig.base.json` fixes the first. It cannot touch the second, and no amount of
563
- thinking about it will make it able to — a child overrides every key its parent sets, so a
564
- base file is a floor for what is *missing* and is inert for what is *spelled differently*.
565
- Writing that limit down is what turned the second problem into a check, which is the only
566
- form of it a reader can act on. It also decided what the floor may contain: `noEmit` is
567
- inheritable and two of these repositories bundle elsewhere, so shipping it would have
568
- silenced the emit in a repository nobody had looked at.
569
-
570
- A thirteenth is the first one that finds the plan wrong. Row 5 offered to resolve "three
571
- disagreeing `.nvmrc` files", and reading them showed each one agrees perfectly with its own
572
- `engines`; what differs is three repositories choosing different node majors, which is a
573
- decision each has a reason for. There was no defect to resolve, and the useful half of the
574
- work was ruling out the check that would have reported it — with a test, so completeness
575
- does not put it back. What is left is one real defect, and it is the first shipped baseline
576
- with no correct value to write: the npm version is not in `package-lock.json`, and a node
577
- floor is as many answers as the team has reasons for. So this one ships no file at all. It
578
- reports, and every remedy is a command run where the answer exists, which is the only shape
579
- available when the tool can name the field and the manager but not the version.
580
-
581
- A fourteenth ships nothing at all, and that is the point of it. The first six baselines each
582
- hit a mechanism question — a region or a whole file, a floor or a check, a value to write or
583
- no value to derive — and each answer was waiting for somebody to find out what the format
584
- permits. The two items still open in the plan have no such question, because nobody has
585
- decided whether they should exist: commitlint is named by the plan and by no rule file and
586
- by no `package.json` in the estate, and the ESLint "block" cannot describe two of the four
587
- configurations because they have no TypeScript in them at all. Writing that down in the rows
588
- that asked for them costs less than shipping either one would, and it is the difference
589
- between a row that says "unfinished" and one that says "undecided". It also corrected two
590
- counts the plan got wrong, which is only possible because somebody read the estate rather
591
- than the plan.