simt-dev 0.2.0__py3-none-any.whl

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 (138) hide show
  1. python/simt_dev/__init__.py +32 -0
  2. python/simt_dev/cli.py +225 -0
  3. simt_dev/__init__.py +32 -0
  4. simt_dev/cli.py +225 -0
  5. simt_dev/vendored/CHANGELOG.md +166 -0
  6. simt_dev/vendored/bin/simt-dev.mjs +28 -0
  7. simt_dev/vendored/docs/decisions/ADR-001-push-requires-approval.md +42 -0
  8. simt_dev/vendored/docs/decisions/ADR-002-refactor-blast-radius.md +45 -0
  9. simt_dev/vendored/docs/decisions/ADR-003-test-breadth.md +46 -0
  10. simt_dev/vendored/docs/decisions/ADR-004-hook-owns-format.md +45 -0
  11. simt_dev/vendored/docs/decisions/ADR-005-file-length.md +42 -0
  12. simt_dev/vendored/docs/decisions/ADR-006-coverage-bar.md +59 -0
  13. simt_dev/vendored/docs/decisions/ADR-007-section-skeleton.md +54 -0
  14. simt_dev/vendored/docs/decisions/ADR-008-verdict-vocabulary.md +59 -0
  15. simt_dev/vendored/docs/decisions/ADR-009-skill-layout.md +48 -0
  16. simt_dev/vendored/docs/decisions/ADR-010-runner-invocation.md +56 -0
  17. simt_dev/vendored/docs/decisions/ADR-011-windows-support.md +52 -0
  18. simt_dev/vendored/docs/decisions/ADR-012-drop-windows-support.md +59 -0
  19. simt_dev/vendored/docs/decisions/ADR-013-genericity-by-facts-and-local-profiles.md +114 -0
  20. simt_dev/vendored/docs/decisions/ADR-014-workspace-is-configuration.md +211 -0
  21. simt_dev/vendored/docs/decisions/ADR-015-a-source-is-content-not-a-location.md +117 -0
  22. simt_dev/vendored/docs/decisions/ADR-016-a-divergent-rule-is-retired-not-merged.md +180 -0
  23. simt_dev/vendored/docs/decisions/ADR-017-a-declared-gate-must-be-runnable.md +89 -0
  24. simt_dev/vendored/docs/decisions/ADR-018-an-unset-hooks-path-is-not-an-absent-hook.md +183 -0
  25. simt_dev/vendored/docs/decisions/ADR-019-a-declared-command-is-the-runner.md +110 -0
  26. simt_dev/vendored/docs/decisions/ADR-020-a-rule-is-written-per-surface-and-pointed-not-copied.md +100 -0
  27. simt_dev/vendored/docs/decisions/ADR-021-one-surface-per-repo.md +94 -0
  28. simt_dev/vendored/docs/decisions/ADR-022-a-key-simt-dev-reads-is-prefixed.md +98 -0
  29. simt_dev/vendored/docs/decisions/ADR-023-the-gate-ships-as-a-file-the-repo-owns.md +106 -0
  30. simt_dev/vendored/docs/decisions/ADR-024-simt-dev-overwrites-its-own-gate-file.md +111 -0
  31. simt_dev/vendored/docs/decisions/ADR-025-a-baseline-is-a-region-in-a-file-the-repo-owns.md +153 -0
  32. simt_dev/vendored/docs/decisions/ADR-026-a-config-without-a-region-is-a-file-the-repo-owns.md +117 -0
  33. simt_dev/vendored/docs/decisions/ADR-027-the-one-gitattributes-line-that-is-neither-dangerous-nor-empty.md +130 -0
  34. simt_dev/vendored/docs/decisions/ADR-028-a-base-file-is-a-floor-so-the-disagreement-it-cannot-repair-becomes-a-check.md +131 -0
  35. simt_dev/vendored/docs/decisions/ADR-029-the-pins-a-repository-declares-are-its-own.md +120 -0
  36. simt_dev/vendored/docs/decisions/ADR-030-what-a-plan-does-not-ship-is-a-decision-with-a-record.md +114 -0
  37. simt_dev/vendored/docs/decisions/ADR-031-the-suite-stages-the-environment-it-needs.md +129 -0
  38. simt_dev/vendored/docs/decisions/ADR-032-provenance-is-a-content-digest-not-a-commit.md +141 -0
  39. simt_dev/vendored/docs/decisions/ADR-033-three-plan-rows-closed-by-decision-not-by-authoring.md +82 -0
  40. simt_dev/vendored/docs/decisions/ADR-034-a-staged-tool-refuses-a-partially-staged-file.md +91 -0
  41. simt_dev/vendored/docs/decisions/ADR-035-one-write-decision-and-one-json-document.md +119 -0
  42. simt_dev/vendored/docs/decisions/ADR-036-a-writer-that-writes-says-so-and-the-instructions-naming-it-move-with-it.md +103 -0
  43. simt_dev/vendored/docs/decisions/ADR-037-unchanged-means-writing-would-not-change-a-byte.md +100 -0
  44. simt_dev/vendored/docs/decisions/ADR-038-the-gate-filter-belongs-to-every-manifest-writer.md +95 -0
  45. simt_dev/vendored/docs/decisions/ADR-039-a-ci-step-runs-a-form-that-can-fail.md +101 -0
  46. simt_dev/vendored/docs/decisions/ADR-040-the-last-writer-that-wrote-by-default-was-not-the-one-named.md +158 -0
  47. simt_dev/vendored/docs/decisions/ADR-041-the-suite-installs-the-package-in-order-to-test-it.md +92 -0
  48. simt_dev/vendored/docs/decisions/ADR-042-a-declared-glob-must-match-a-path-built-from-it.md +94 -0
  49. simt_dev/vendored/docs/decisions/ADR-043-a-keyword-is-a-phrase-and-two-letters-is-a-word.md +90 -0
  50. simt_dev/vendored/docs/decisions/ADR-044-compatibility-is-not-evidence.md +116 -0
  51. simt_dev/vendored/docs/decisions/ADR-045-a-dashboard-that-counts-a-defect.md +119 -0
  52. simt_dev/vendored/docs/decisions/ADR-046-one-rule-one-copy.md +140 -0
  53. simt_dev/vendored/docs/decisions/ADR-047-a-profile-selects-on-what-a-repository-runs-on.md +141 -0
  54. simt_dev/vendored/docs/decisions/ADR-048-a-baseline-carries-only-keys-a-reader-honours.md +150 -0
  55. simt_dev/vendored/docs/decisions/ADR-049-a-ruling-that-a-later-record-moved-says-so-where-it-is-printed.md +153 -0
  56. simt_dev/vendored/docs/decisions/ADR-050-a-byte-count-is-not-a-region-and-updated-is-not-a-change-of-rules.md +102 -0
  57. simt_dev/vendored/docs/decisions/ADR-051-a-pointer-is-the-readers-only-route-so-it-is-not-a-convenience.md +134 -0
  58. simt_dev/vendored/docs/decisions/ADR-052-a-dependency-is-counted-against-the-budget-and-there-is-one-budget.md +101 -0
  59. simt_dev/vendored/docs/decisions/ADR-053-the-node-floor-is-22-20-0.md +49 -0
  60. simt_dev/vendored/docs/decisions/ADR-054-the-digest-covers-every-byte-that-leaves-the-package.md +100 -0
  61. simt_dev/vendored/docs/decisions/ADR-055-a-status-line-travels-so-it-may-not-name-a-location.md +98 -0
  62. simt_dev/vendored/docs/decisions/ADR-056-three-names-one-of-which-is-cheap-to-move.md +160 -0
  63. simt_dev/vendored/docs/decisions/ADR-057-an-identity-is-per-developer-and-a-repository-does-not-own-it.md +115 -0
  64. simt_dev/vendored/docs/decisions/ADR-058-one-tool-three-channels-and-the-order-is-forced.md +148 -0
  65. simt_dev/vendored/docs/decisions/README.md +530 -0
  66. simt_dev/vendored/graph/skills.graph.json +1622 -0
  67. simt_dev/vendored/package.json +43 -0
  68. simt_dev/vendored/rules/core.md +76 -0
  69. simt_dev/vendored/rules/mdc/intake-questions.mdc +50 -0
  70. simt_dev/vendored/rules/mdc/preview-postflight.mdc +61 -0
  71. simt_dev/vendored/rules/mdc/slice-commit.mdc +52 -0
  72. simt_dev/vendored/rules/mdc/test-gate.mdc +54 -0
  73. simt_dev/vendored/rules/stacks/android.md +63 -0
  74. simt_dev/vendored/rules/stacks/cloudflare-workers.md +65 -0
  75. simt_dev/vendored/rules/stacks/connectiq.md +62 -0
  76. simt_dev/vendored/rules/stacks/container.md +31 -0
  77. simt_dev/vendored/rules/stacks/jvm.md +54 -0
  78. simt_dev/vendored/rules/stacks/node.md +45 -0
  79. simt_dev/vendored/rules/stacks/python.md +48 -0
  80. simt_dev/vendored/rules/stacks/react-native.md +58 -0
  81. simt_dev/vendored/rules/stacks/react-web.md +61 -0
  82. simt_dev/vendored/rules/stacks/typescript.md +21 -0
  83. simt_dev/vendored/rules/stacks/uv.md +32 -0
  84. simt_dev/vendored/src/argv.mjs +116 -0
  85. simt_dev/vendored/src/ci/dependabot.mjs +268 -0
  86. simt_dev/vendored/src/ci/workflow.mjs +360 -0
  87. simt_dev/vendored/src/commands/ci.mjs +285 -0
  88. simt_dev/vendored/src/commands/compare.mjs +195 -0
  89. simt_dev/vendored/src/commands/graph.mjs +73 -0
  90. simt_dev/vendored/src/commands/help.mjs +108 -0
  91. simt_dev/vendored/src/commands/hooks.mjs +471 -0
  92. simt_dev/vendored/src/commands/index.mjs +241 -0
  93. simt_dev/vendored/src/commands/init.mjs +632 -0
  94. simt_dev/vendored/src/commands/mcp.mjs +63 -0
  95. simt_dev/vendored/src/commands/rules.mjs +374 -0
  96. simt_dev/vendored/src/commands/skills.mjs +647 -0
  97. simt_dev/vendored/src/commands/skillsinstall.mjs +515 -0
  98. simt_dev/vendored/src/commands/sync.mjs +331 -0
  99. simt_dev/vendored/src/commands/upgrade.mjs +202 -0
  100. simt_dev/vendored/src/compare/discover.mjs +212 -0
  101. simt_dev/vendored/src/compare/hooksstate.mjs +159 -0
  102. simt_dev/vendored/src/compare/row.mjs +299 -0
  103. simt_dev/vendored/src/decisions/index.mjs +536 -0
  104. simt_dev/vendored/src/graph/load.mjs +541 -0
  105. simt_dev/vendored/src/hooks/capability.mjs +129 -0
  106. simt_dev/vendored/src/hooks/dispatcher.mjs +268 -0
  107. simt_dev/vendored/src/hooks/gates.mjs +144 -0
  108. simt_dev/vendored/src/hooks/resolve.mjs +194 -0
  109. simt_dev/vendored/src/hooks/shim.mjs +140 -0
  110. simt_dev/vendored/src/hooks/where.mjs +118 -0
  111. simt_dev/vendored/src/identity.mjs +218 -0
  112. simt_dev/vendored/src/locate.mjs +75 -0
  113. simt_dev/vendored/src/mcp/server.mjs +167 -0
  114. simt_dev/vendored/src/mcp/tools.mjs +410 -0
  115. simt_dev/vendored/src/name.mjs +95 -0
  116. simt_dev/vendored/src/output/index.mjs +96 -0
  117. simt_dev/vendored/src/projection/baselines.mjs +209 -0
  118. simt_dev/vendored/src/projection/conflicts.mjs +205 -0
  119. simt_dev/vendored/src/projection/manifest.mjs +478 -0
  120. simt_dev/vendored/src/projection/markers.mjs +349 -0
  121. simt_dev/vendored/src/projection/mdc.mjs +327 -0
  122. simt_dev/vendored/src/projection/project.mjs +504 -0
  123. simt_dev/vendored/src/projection/rules.mjs +640 -0
  124. simt_dev/vendored/src/projection/surfaces.mjs +398 -0
  125. simt_dev/vendored/src/projection/targets.mjs +221 -0
  126. simt_dev/vendored/src/resolve/fingerprint.mjs +553 -0
  127. simt_dev/vendored/src/resolve/near.mjs +61 -0
  128. simt_dev/vendored/src/resolve/resolve.mjs +457 -0
  129. simt_dev/vendored/src/resolve/source.mjs +105 -0
  130. simt_dev/vendored/src/toolchain.mjs +202 -0
  131. simt_dev/vendored/src/tsconfig.mjs +314 -0
  132. simt_dev/vendored/src/upgrade/plan.mjs +203 -0
  133. simt_dev/vendored/src/workspace.mjs +289 -0
  134. simt_dev-0.2.0.dist-info/METADATA +150 -0
  135. simt_dev-0.2.0.dist-info/RECORD +138 -0
  136. simt_dev-0.2.0.dist-info/WHEEL +4 -0
  137. simt_dev-0.2.0.dist-info/entry_points.txt +2 -0
  138. simt_dev-0.2.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,98 @@
1
+ # ADR-022 — A key simt-dev reads is prefixed `simt-`
2
+
3
+ Status: accepted · 2026-10-08
4
+ **Affects:** `rules/*.md`, `rules/mdc/*.mdc`, `src/projection/mdc.mjs`, `src/projection/rules.mjs`, `test/shipped.test.mjs`. Supersedes the *spelling* of the keys named in ADR-013 and ADR-016; their rulings stand.
5
+
6
+ ## Context
7
+
8
+ A canonical `.mdc` frontmatter block carries two vocabularies in one place:
9
+
10
+ ```
11
+ id: test-gate
12
+ target: .cursor/rules/test-gate.mdc
13
+ description: ...
14
+ alwaysApply: true
15
+ applies: always
16
+ ```
17
+
18
+ `description` and `alwaysApply` are Cursor's, cited in the `cursor` row of
19
+ `src/projection/surfaces.mjs` and re-emitted per surface. `id`, `target`, `applies`,
20
+ `optIn` and `substitutions` are simt-dev's own and appear in no vendor's
21
+ documentation. In the file above, nothing says which is which: `alwaysApply: true` and
22
+ `applies: always` sit four lines apart, both read as "always", and both are consumed by
23
+ something. The question was asked of this repository and could only be answered by
24
+ reading the source rather than the file.
25
+
26
+ That is a legibility failure with teeth behind it. ADR-016 records finding S11: a rule
27
+ shipped, was tested for its presence on disk, and reached no repository, because
28
+ `applies` was absent from its frontmatter. A missing simt-owned key is silent. A bare
29
+ key that looks like the key beside it is one typo away from the same silence, and this
30
+ block is precisely where a reader editing one key is looking at the other.
31
+
32
+ The prefix does not exist to make the files tidy. It exists so that a bare key is
33
+ either an editor's key or a defect, and never a third thing.
34
+
35
+ ## Rulings
36
+
37
+ 1. **Every key simt-dev reads out of a canonical rule file carries `simt-`.**
38
+ `simt-id`, `simt-target`, `simt-title`, `simt-applies`, `simt-opt-in`,
39
+ `simt-substitutions`, `simt-fallback`.
40
+
41
+ | was | is |
42
+ |---|---|
43
+ | `id`, `target`, `title` (`.mdc`) | `simt-id`, `simt-target`, `simt-title` |
44
+ | `applies`, `optIn`, `substitutions` (`.mdc`) | `simt-applies`, `simt-opt-in`, `simt-substitutions` |
45
+ | `id`, `title`, `applies`, `fallback` (`rules/*.md`, `.simt-dev/profiles/`) | `simt-id`, `simt-title`, `simt-applies`, `simt-fallback` |
46
+
47
+ 2. **An editor's key keeps the vendor's spelling, unprefixed.** `description` and
48
+ `alwaysApply` are the only two keys in the estate with two owners: simt-dev reads
49
+ them and re-emits them mapped per surface (`alwaysApply` becomes Antigravity's
50
+ `trigger: always_on`). Prefixing them would be a lie in both directions — Cursor
51
+ would ignore `simt-alwaysApply`, and the projector would have to strip the prefix
52
+ before emitting. A key is prefixed when this tool is its only reader.
53
+
54
+ 3. **An unrecognised key is a defect, not an ignored line.** `applies:` in a file that
55
+ should say `simt-applies:` reports as a problem naming the prefixed spelling.
56
+ This is the ruling that turns the prefix from a convention into an invariant: the
57
+ failure mode ADR-016 hit is now loud, and loud before the rule reaches nobody.
58
+
59
+ 4. **The prefix binds settings read from files, not identifiers in code.** `rule.applies`
60
+ is still `rule.applies` in `src/`. Renaming the property would satisfy the sentence
61
+ and change nothing a reader of a rule file sees, which is the only reader the prefix
62
+ is for.
63
+
64
+ 5. **Inside `simt-substitutions:` the keys stay `key`, `default` and `describe`.** The
65
+ parent already namespaces them; `simt-key` reads as though the block were not there.
66
+
67
+ 6. **Out of scope, deliberately: `simt-dev.json` and `graph/skills.graph.json`.** Both
68
+ are namespaced by filename, neither contains a key any editor or agent reads, and
69
+ both are read by this tool's own commands rather than by a person opening a rule
70
+ file. The receiving repo's manifest is the one file a human edits by hand — to
71
+ declare a gate command or a substitution — and `simt-gates` there is noise in the
72
+ place noise costs the most.
73
+
74
+ ## Consequences
75
+
76
+ - **No receiving repository is affected.** These keys are stripped before projection:
77
+ `.md` frontmatter is dropped by `stripFrontmatter`, and a projected `.mdc` gets
78
+ frontmatter rebuilt from the surface row (`description` + `alwaysApply`) or preserves
79
+ whatever an adopted file already had, verbatim and unparsed. The change is
80
+ confined to the files in this repository, which is why touching shipped rule text is
81
+ cheap here and expensive in `rules/core.md`'s prose.
82
+ - A rule file that still says `applies:` now fails `check` with the prefixed spelling in
83
+ the message. That is the intended break: it fails at the file, loudly, on first run.
84
+ - ADR-013 and ADR-016 name the old spellings in their examples. They are left verbatim
85
+ — they are the record of what was ruled — and this record is the lookup from the old
86
+ spelling to the new one.
87
+ - `rules list` keeps an `applies` column. It labels a value, not a key, and the value
88
+ vocabulary (`always`, a tag list) is unchanged.
89
+
90
+ ## Rejected
91
+
92
+ - **Prefix the manifest keys too.** Rejected: `simt-dev.json` is already namespaced by
93
+ filename, and the keys a person edits by hand are the ones a prefix would obscure.
94
+ - **Prefix in code as well, for symmetry.** Rejected under ruling 4: it is a rename of
95
+ variables that satisfies the wording and defeats the purpose.
96
+ - **Accept both spellings for one release.** Rejected: a key that may be written two
97
+ ways is exactly the ambiguity this record exists to remove, and the failure it hides
98
+ is the unreachable rule ADR-016 already shipped once.
@@ -0,0 +1,106 @@
1
+ # ADR-023 — The gate ships as a file the repo owns
2
+
3
+ Status: accepted · 2026-10-06 · ruling 2 superseded by
4
+ [ADR-024](ADR-024-simt-dev-overwrites-its-own-gate-file.md), which carves out this
5
+ repository's own copy; rulings 3 and 4 narrowed by the same record to every repository
6
+ except this one. The text below is left as it was accepted.
7
+ **Affects:** `src/ci/workflow.mjs`, `src/locate.mjs`, `src/hooks/shim.mjs`, `src/commands/init.mjs`, `src/projection/project.mjs`, `test/ci.test.mjs`, `test/leaks.mjs`. Settles plan 1 §6 phase 3 ("Reusable workflow live").
8
+
9
+ ## Context
10
+
11
+ `simt-dev check` is the whole gate: projection drift, an unreadable rule, an unrunnable
12
+ gate, a stale manifest. `init` installs it as a `pre-commit` hook, which means it runs on
13
+ the machine of whoever remembers to run it, and a hook is a developer's machine. Every
14
+ review is somebody else's, and every merge is a machine nobody gated.
15
+
16
+ The plan called this "a reusable workflow", and named
17
+ `the organisation/simt-dev/.github/workflows/sync-check.yml` as a file "referenced by every
18
+ consumer". Nothing in this repository had a `.github/` at all. There were three ways to
19
+ close the gap, and they differ in who the resulting file belongs to:
20
+
21
+ - **`uses:` a reusable workflow.** One file, changed centrally, no copying. Every consumer
22
+ references a path inside a repository its team has no access to, cannot diff in review,
23
+ and cannot edit. The gate's own behaviour becomes a function of someone else's push, and
24
+ a red build becomes something the reader cannot diagnose from what they have.
25
+ - **Copy the bytes in.** Each repo gets a file it can read, edit, argue with and delete.
26
+ Improving the template does not reach repos that already have it.
27
+ - **Run the tool from the consumer's CI, configured by them.** No shipped file at all,
28
+ which means every repo writes the same three lines and none of them are checked.
29
+
30
+ This repository has one rule that settles it: **every byte that leaves this repository
31
+ must be readable and actionable by someone who has only the receiving repository.** A
32
+ `uses:` line points at bytes the reader does not have. That is not a style preference; it
33
+ is the failure this tool exists to stop having shipped, and it has shipped — the projected
34
+ rules once told readers to edit a source tree they did not have.
35
+
36
+ ## Rulings
37
+
38
+ 1. **The gate ships as copied bytes, written into `.github/workflows/simt-dev-check.yml`.**
39
+ A `uses:` reference is ruled out by the rule above. The file is fully readable in the
40
+ pull request that adopts it, which is the only review it ever gets.
41
+
42
+ 2. **It is written once and never rewritten.** From creation the file belongs to the repo:
43
+ their extra jobs, their triggers, their matrix. Overwriting it would delete work this
44
+ tool has no way to know about, which is the same defect as replacing a hand-written
45
+ `.mdc` body (ADR-016). `planWorkflow` reports an existing file as `unchanged` and never
46
+ reads its contents for comparison.
47
+
48
+ **The cost, stated rather than discovered later:** a template improvement does not
49
+ reach an adopted repo. There is no marker, no managed region, no way for `upgrade` to
50
+ tell their edit from ours. A repo that wants the newer template takes the diff by hand.
51
+ This is a deliberate trade, and ruling 4 is what keeps it cheap.
52
+
53
+ 3. **The gate only appears where GitHub Actions already runs.** `.github/workflows/` must
54
+ exist as a directory. Creating it silently would start running jobs on pull requests the
55
+ team did not ask for, which is the mirror image of the defect: a tool making a
56
+ decision for someone and reporting success. `init` prints `skip` with the reason and
57
+ the way out — "create `.github/workflows/` first if this repo is on GitHub Actions,
58
+ then rerun init" — so a skip is a decision they can reverse rather than an absence they
59
+ discover from a failing build.
60
+
61
+ 4. **`check` reports the absence; it never inspects a file's contents.** An Actions repo
62
+ with no simt-dev workflow is a blocking `absent` finding with the remedy
63
+ `simt-dev init --yes`. A workflow that exists is never diffed, never opened, never
64
+ counted. A gate that inspects a file it also owns would report its own drift forever,
65
+ and the reader's only fix would be to re-run `init` — the "permanently red check
66
+ nothing can fix" failure the code comments fear elsewhere. Their file, their content.
67
+
68
+ 5. **The binary resolution is one function, shared with the hook.** The hook shim already
69
+ resolved the dispatcher through `$SIMT_DEV_BIN` → `node_modules` → `PATH` → refuse. That
70
+ block moved to `src/locate.mjs` so the workflow could take it rather than re-spell it.
71
+ Two copies diverge the first time one is fixed, and the symptom is the worst available:
72
+ a gate that passes on a laptop and cannot start in CI.
73
+
74
+ 6. **A job that cannot find the tool fails.** Every resolution chain ends in a refusal with
75
+ a non-zero exit, and the file says so in its own header. A green tick from a check that
76
+ never ran is the one outcome worse than a red one.
77
+
78
+ ## Consequences
79
+
80
+ - `init` writes one more file, so one more line in its plan. Every file `init` creates is
81
+ named in the plan it prints: a file the reader was not shown is a file they approve by
82
+ reading the diff afterwards, which is the one review step this tool exists to make
83
+ unnecessary.
84
+ - The rendered bytes are subject to the same leak check as rule bodies, now shared as
85
+ `test/leaks.mjs`. This is the first thing simt-dev ships that a human has to *read and
86
+ argue with* in a review rather than merely receive, so the guard is a requirement and not
87
+ a courtesy.
88
+ - The workflow's `run:` body is checked with `sh -n`. A shell syntax error inside a YAML
89
+ block scalar is otherwise found on the adopting repo's first pull request, in public.
90
+ - A repo with no `.github/` sees no change at all: no finding, no file, no directory.
91
+ - The template is not a managed region and this record does not pretend otherwise. If a
92
+ future release changes what the gate does, existing repos keep what they have.
93
+
94
+ ## Rejected
95
+
96
+ - **`uses: the organisation/simt-dev/.github/workflows/sync-check.yml@main`.** Rejected under
97
+ ruling 1: it is the plan's own suggestion, and it points every reader at bytes they do
98
+ not have. Worth recording that the plan wrote it, because the next person to read §6
99
+ will find it there.
100
+ - **Maintain it as a marker-managed region, refreshed by `upgrade`.** Rejected: it needs a
101
+ merge strategy for a repo that added their own job, which is the problem ruling 2
102
+ declines to take on. A refreshed file that overwrites a deployment job is worse than a
103
+ stale one.
104
+ - **Create `.github/workflows/` when it is missing.** Rejected under ruling 3.
105
+ - **Ship a reusable workflow *and* copy it.** Rejected: two sources for one gate, and the
106
+ copy is the one nobody reads.
@@ -0,0 +1,111 @@
1
+ # ADR-024 — simt-dev overwrites its own gate file, and no repository else's
2
+
3
+ Status: accepted · 2026-10-06
4
+ **Affects:** `src/ci/workflow.mjs`, `src/commands/ci.mjs`, `src/commands/init.mjs`,
5
+ `src/commands/index.mjs`, `src/commands/help.mjs`, `src/projection/project.mjs`,
6
+ `.github/workflows/simt-dev-check.yml`, `test/ci.test.mjs`. Supersedes ruling 2 of
7
+ [ADR-023](ADR-023-the-gate-ships-as-a-file-the-repo-owns.md), and narrows its rulings 3 and
8
+ 4 to every repository except this one. ADR-023's rulings 1, 5 and 6 stand.
9
+
10
+ ## Context
11
+
12
+ ADR-023 copied the gate into `.github/workflows/` and wrote it once. For an adopting
13
+ repository that is the right call, and the cost was written down rather than discovered
14
+ later: a template improvement does not reach a repo that already has the file.
15
+
16
+ This repository is not an adopting repository. It is the tool. And a tool whose own gate is
17
+ a frozen copy of its own gate is a tool with two gates, one of which it does not maintain.
18
+ The file `.github/workflows/simt-dev-check.yml` in this repository was written by the
19
+ template, and every future change to the template would leave it behind — silently, because
20
+ ADR-023 ruling 4 says `check` never inspects a workflow's contents, so nothing would report
21
+ the gap. A gate that cannot report its own staleness is the failure mode ADR-017, ADR-018
22
+ and ADR-019 were each written about.
23
+
24
+ There is a second reason the exception is narrow rather than general. **A rule with one
25
+ exception is a rule with an exception; a rule with a flag is a rule with two behaviours
26
+ depending on who asked.** The write-once ruling is what protects a repo's deployment job
27
+ from being overwritten. "Unless the tool feels like it" is not a boundary anyone can check.
28
+ The only boundary that needs no judgement is a path, and this repository is one path.
29
+
30
+ ## Rulings
31
+
32
+ 1. **This repository's gate file is generated, refreshed, and generated bytes only.** It
33
+ lives at `PACKAGE_ROOT`, recognised by `resolve(root) === PACKAGE_ROOT` — not by a
34
+ flag, an env var, or a name in a config file, because all three can be set by a consumer
35
+ who would then have found the one path that overwrites their CI. `resolve`, not
36
+ `realpath`: a symlinked checkout that fails to match leaves it a consumer, which is the
37
+ direction a mistake is survivable in.
38
+
39
+ 2. **`simt-dev ci` is the only writer of that copy, and it is a dry run without `--yes`.**
40
+ `init` cannot be the writer, and this is not a design preference. `init` on this
41
+ repository would pin this repository's SHA into its own `AGENTS.md`, which is precisely
42
+ what the "Why this repository is not self-adopted" section of `AGENTS.md` exists to
43
+ prevent. A refresh reachable only through `init` is an exception that can never fire, and
44
+ an exception that cannot fire is worse than no exception: it reads in the code as though
45
+ the copy were maintained.
46
+
47
+ 3. **`simt-dev ci` outside this repository is a refusal, not an error.** It prints who owns
48
+ the file and the command that owns it (`simt-dev init --yes`), writes nothing, and exits
49
+ zero. A refusal is a report. Making it a failure would mean a CI job that runs `ci`
50
+ before it runs `check` breaks for every adopting repo, for a condition that is correct.
51
+
52
+ 4. **The header of each copy says which world it is in.** The consumer copy says it is
53
+ written once and never rewritten. The own copy says it is refreshed, that a diff means
54
+ the **gate** changed rather than that somebody hand-edited their CI, and that the way to
55
+ change it is `src/ci/workflow.mjs` in the same commit followed by `simt-dev ci --yes`.
56
+ Both sentences are tested against the rendered bytes. The alternative is a reader of this
57
+ repository's diff seeing their CI change and having to guess who did it.
58
+
59
+ 5. **This repository's copy is compared; every other repository's is not.** `planWorkflow`
60
+ computes `current` only when the root is this repository's, and `check` raises a
61
+ `drift` finding with the remedy `simt-dev ci --yes` only then. ADR-023 ruling 4 stands
62
+ unchanged for everyone else: their file, their content, never opened.
63
+
64
+ 6. **This repository's copy runs the gate this repository can actually pass.** The consumer
65
+ copy runs `simt-dev check`, which fails here by design — `check` reports
66
+ `UNMANAGED AGENTS.md` in a repository that has deliberately not adopted itself, so a copy
67
+ of the consumer workflow committed here would be red on its first run and every run after.
68
+ The own copy runs what `.githooks/pre-push` already runs — `npm test` and
69
+ `graph lint` — plus `simt-dev ci` itself, so the file is its own staleness check. A test
70
+ asserts both commands are in the hook and in `package.json`, because a gate that names a
71
+ command this repository does not have is ADR-019 again.
72
+
73
+ 7. **Both copies render from one skeleton.** Triggers, permissions, concurrency, runner and
74
+ timeout are written once in `skeleton(name, steps)`; the two renderings differ in the
75
+ header text, the job name and the steps. Two independently written YAML files are two
76
+ opinions about when a pull request is gated, and the copy that is wrong is the copy nobody
77
+ diffs.
78
+
79
+ ## Consequences
80
+
81
+ - `simt-dev ci` is a new command with one job. It is also the first command in this tool
82
+ that only makes sense in the tool's own repository, and that is deliberate: it is the
83
+ only honest way to ship a self-maintained generated file without giving the write-once
84
+ ruling a flag.
85
+ - `test/ci.test.mjs` now has one test that writes into this repository: it mutates the
86
+ committed workflow, asserts `check` reports the drift, runs `ci --yes`, asserts the bytes
87
+ are restored, and restores in a `finally`. No fixture can produce this case, because the
88
+ condition *is* this repository's path. The test is therefore the only one that can fail
89
+ for an environmental reason, which is why it restores rather than only asserting.
90
+ - The own copy is checked with the leak rules but not with the path rules. Naming
91
+ `src/ci/workflow.mjs` in this repository's own workflow is correct — it is the one place
92
+ that path resolves — so asserting against it would be asserting that this repository's
93
+ CI cannot mention its own source.
94
+ - If this repository is ever vendored or installed as a package, `PACKAGE_ROOT` becomes a
95
+ directory under `node_modules` with no `.git` and no workflows, and the copy simply stops
96
+ existing there. Nothing needs to detect that case.
97
+
98
+ ## Rejected
99
+
100
+ - **A `--managed` flag, or `init --refresh-ci`.** Rejected under ruling 1: it makes the
101
+ difference between "never overwrites your CI" and "will overwrite your CI" a value the
102
+ consumer sets. The ruling is worth more if there is no spelling for the wrong answer.
103
+ - **Let `upgrade` refresh the file in every repo.** Rejected: it is the merge-strategy
104
+ problem ADR-023 already declined, and adding a repository to the exception list is
105
+ strictly smaller than solving it for all of them.
106
+ - **One workflow file that detects which repo it is in at run time.** Rejected: a consumer's
107
+ file would then contain this repository's path and its commands, which is ADR-023 ruling 1
108
+ violated inside the very file ruling 1 was written for.
109
+ - **Give the own copy a managed region marker instead of full replacement.** Rejected: this
110
+ repository has no hand edits to preserve, so a merge strategy would be machinery for a
111
+ case that does not exist here and would leak into the consumer copy's design.
@@ -0,0 +1,153 @@
1
+ # ADR-025 — a baseline is a region in a file the repo owns, and only a file that can hold one
2
+
3
+ Status: accepted · 2026-10-06 · rulings 1 and 2 narrowed by ADR-026 · ruling 8 withdrawn by ADR-048
4
+ **Affects:** `src/projection/baselines.mjs`, `src/projection/markers.mjs`,
5
+ `src/projection/project.mjs`, `src/commands/init.mjs`, `test/baselines.test.mjs`,
6
+ `test/leaks.mjs`, `test/surfaces.test.mjs`. Settles §3.1 row 5 and row 7 of
7
+ `docs/plans/0001-centralise-agent-rules.md` for the files it names, and leaves the rest ruled
8
+ out by name rather than outstanding.
9
+
10
+ Rulings 1 and 2 did not survive whole: ADR-026 rules that a config whose grammar cannot
11
+ carry a comment is owned whole rather than not at all, and does so by reusing this record's
12
+ neighbour (ADR-023) rather than by overriding anything here. What rulings 1 and 2 still
13
+ settle is narrower and is not in dispute — a file that **can** hold a region is a region,
14
+ and no comment-capable file is to be taken over whole.
15
+
16
+ ## Context
17
+
18
+ §2.2 of the plan named the mechanism before any of the files existed: *"Same for
19
+ `.editorconfig`, `.prettierrc`, `.gitattributes`. Local content is never clobbered; shared
20
+ content can never drift silently."* Only the first file was ever built, and only for
21
+ `AGENTS.md`.
22
+
23
+ §3.1 row 5 asks for eight baselines and promises six concrete resolutions: the `singleQuote`
24
+ contradiction, the ten repos with no editorconfig, the missing strictness flags, the three
25
+ disagreeing `.nvmrc`, no `packageManager`, and eslint fighting prettier in three of five
26
+ configs. Row 7 asks `init` to scaffold them.
27
+
28
+ What is actually missing is not the files. `rules/stacks/node.md` already mandates their
29
+ shapes — *".nvmrc pins the development version"*, *"`moduleResolution` spelled consistently"*,
30
+ *"Prettier owns formatting"* — and mandates them **with no values**. Every line is a shape
31
+ with the value left to whoever reads it. That is the failure AGENTS.md names as "can the
32
+ reader act on it — command, not location?", except it is worse: the reader is told a file
33
+ exists and not what goes in it.
34
+
35
+ The same profile is where the plan's own resolutions point. `singleQuote` is a
36
+ `[prettier]`-section value, which prettier reads from `.editorconfig` — a file whose comment
37
+ character is `#`, and therefore a file that can hold a region.
38
+
39
+ **This paragraph is what ADR-048 withdraws.** A section header in editorconfig is a glob
40
+ over paths, so `[prettier]` matches a file named `prettier`, and `singleQuote` is not one of
41
+ the nine keys the specification defines — nor one of the six properties Prettier maps. The
42
+ reasoning below is sound and the conclusion does not follow from it: the file *can* hold a
43
+ region, and that is the whole of what makes it the right home for a shared claim. It says
44
+ nothing about whether a given claim is one a reader honours. Ruling 8 is withdrawn for that
45
+ reason and the record is kept, because the reasoning is what makes the withdrawal legible.
46
+
47
+ ## Rulings
48
+
49
+ 1. **A baseline is a marker-managed region, not a file simt-dev owns.** The repo keeps
50
+ `.editorconfig`; simt-dev owns the bytes between `# simt-dev:begin` and `# simt-dev:end`.
51
+ This is §2.2 as written. A whole-file baseline would overwrite the exact content the plan
52
+ says must never be clobbered, and the ten repos that already have an editorconfig are the
53
+ ones with the most to lose.
54
+
55
+ 2. **Only a file whose format can carry a comment may hold a region.** This is the whole
56
+ filter, and it is grammar rather than caution. `.editorconfig` qualifies: `#` is a comment
57
+ in INI and every editorconfig parser honours it. `tsconfig.base.json` and
58
+ `.prettierrc.json` do not — JSON has no comment syntax, and a "region" in a JSON file
59
+ would have to be a string literal that `tsc` and prettier both have to tolerate.
60
+ `.nvmrc` is a bare version string. A baseline for any of those is a whole-file write, and
61
+ ruling 1 forbids it. They are ruled out, not deferred.
62
+
63
+ 3. **The marker syntax is a property of the file, not of the module.** `markers.mjs` grew
64
+ `STYLES`: `html` for `AGENTS.md` and every `.mdc`, `hash` for `.editorconfig`. The HTML
65
+ rendering is byte-identical to what it was — asserted by the existing 36 tests — because a
66
+ change to those bytes would make every adopted repository drift. A third style is a row in
67
+ that table, not a second implementation, per the ADR-002 rule about a third copy being a
68
+ defect.
69
+
70
+ 4. **The region goes first, and `where` is a style property rather than a caller argument.**
71
+ editorconfig takes the last matching definition. An appended region would leave the repo's
72
+ `indent_size = 4` in the file and silently dead — no byte removed, nothing in `check` to
73
+ report, and a reader with no way to tell why their setting stopped working. Placing the
74
+ shared block first makes the repo win by construction. The placement belongs to the style
75
+ because the correct answer is a fact about the file's semantics, and a caller who has to
76
+ remember it is a caller who gets it wrong once.
77
+
78
+ 5. **A region that is not at the top is a finding of its own.** `check` raises `MISPLACED`
79
+ whenever bytes appear above `# simt-dev:begin`, with the reason and the fix. The bytes are
80
+ right and the meaning is wrong, which is the hardest drift to notice; a finding whose
81
+ detail said so is the only thing that makes it visible. `sync` repairs it by rewriting the
82
+ placement and leaving the content alone.
83
+
84
+ 6. **Absence blocks, the way absence of a rule file blocks.** An adopting repository ran
85
+ `init`; a baseline that has been deleted or a file whose region has been removed is drift,
86
+ and the remedy is one command. The alternative — silently reporting nothing for a file the
87
+ repo does not have — was rejected for the same reason ADR-023 ruling 4 exists: a check that
88
+ reports only what it can see is a check that cannot be relied on to report what it cannot.
89
+
90
+ 7. **`end_of_line` is deliberately absent.** It reads like an editor setting and is not one.
91
+ It decides whether a save rewrites every line of every file, which is a claim about what
92
+ belongs in the repository, and that claim is made in `.gitattributes` where git reads it.
93
+ Setting it here would change every checkout of every repository on the day it landed, and a
94
+ repository that wanted CRLF could only opt out by deleting the region — losing the
95
+ indentation baseline with it.
96
+
97
+ 8. **`[prettier] singleQuote = true` is in, `printWidth` is out.** `singleQuote` is the
98
+ contradiction the plan named first, it is the only comment-capable home prettier reads, and
99
+ a repository with its own prettier config overrides it — which is the right order, because
100
+ the nearer file wins. `printWidth` is absent because nobody has ruled on one. The
101
+ repository that already has `120` would be overruled by a number no one argued about, and a
102
+ baseline that picks a value the estate has not agreed to is not a baseline.
103
+
104
+ **The `singleQuote` half of this ruling is withdrawn by ADR-048**: `[prettier]` is a glob
105
+ that matches a file named `prettier`, and `singleQuote` is not a key the editorconfig
106
+ specification defines or that Prettier reads, so the block it ruled in applied to nothing.
107
+ The `printWidth` half stands and was never implemented — nothing has ruled on a number, and
108
+ that is unchanged.
109
+
110
+ 9. **`.gitattributes` is ruled out for now, for the reason in ruling 7.** It is
111
+ comment-capable and would qualify mechanically, but every line that earns its place in it
112
+ changes what git does to the working tree — `text=auto` rewrites every checkout,
113
+ `linguist-generated` and `export-ignore` need build directories, and build directories are
114
+ stack-specific, which §3.2 keeps local. A shared `.gitattributes` region today is either
115
+ dangerous or empty. It needs its own record, and this is not it.
116
+
117
+ **Ruling 9 is superseded by ADR-027**, which is the record this ruling asked for. The
118
+ deferral was sound and the conclusion was one line too broad: the shared region is neither
119
+ dangerous nor empty, it is exactly one line — `* text=auto eol=lf` — and the `auto` is
120
+ what makes it safe. The rest of this ruling stands, including ruling 7's refusal to
121
+ claim line endings from `.editorconfig`: they are claimed here instead, where a repository
122
+ can overrule the claim on one line without losing anything else.
123
+
124
+ ## Consequences
125
+
126
+ - `.editorconfig` is the only baseline. `BASELINES` is a list, so the next one is a row, and
127
+ `test/baselines.test.mjs` asserts the list is exactly `['.editorconfig']` with a real style,
128
+ a reason and a record number on every row — a baseline added without noticing that its file
129
+ cannot hold a comment would fail there rather than in someone's editor.
130
+ - The node profile's shapes now have values behind them for indentation. They still do not
131
+ for `singleQuote` — ADR-048 withdrew the claim that this file supplied one — nor for
132
+ `.nvmrc`, `packageManager` and `moduleResolution`, and the profile
133
+ still mandates the shapes. That gap is named in the plan's row 5 annotation rather than
134
+ hidden, because the next fix is three more JSON files and therefore a different mechanism.
135
+ - `init`'s plan now prints a third caption, because a reader told "frontmatter kept, body
136
+ replaced" about a file that keeps everything outside a region has been told the wrong thing
137
+ about the edit they are approving.
138
+ - This repository is not self-adopted and therefore has no `.editorconfig`. That is the same
139
+ reason it has no generated region in `AGENTS.md`.
140
+
141
+ ## Rejected
142
+
143
+ - **Ship whole template files for every baseline in §3.1 row 5.** Rejected under ruling 1:
144
+ it overwrites repo content, and eight of the files in that row are JSON or bare strings,
145
+ which is the whole problem.
146
+ - **A `tooling/` directory of template files, as §5 of the plan shows it.** Rejected for the
147
+ same reason: the directory was drawn before anyone checked which of those files can hold a
148
+ managed region, and four of the nine cannot.
149
+ - **A manifest key to opt out of a baseline.** Rejected for now: with one universal baseline
150
+ there is nothing to opt out of, and a key added before there is a choice is a key nobody
151
+ reads. If a second baseline turns out to be stack-specific, the opt-out question returns with
152
+ it.
153
+ - **`[prettier] printWidth = 100`.** Rejected under ruling 8.
@@ -0,0 +1,117 @@
1
+ # ADR-026 — a config whose grammar cannot hold a region is a file the repo owns
2
+
3
+ Status: accepted · 2026-10-06
4
+ **Affects:** `src/ci/dependabot.mjs`, `src/commands/ci.mjs`, `src/commands/init.mjs`,
5
+ `src/commands/help.mjs`, `src/projection/project.mjs`, `test/ci.test.mjs`.
6
+ **Narrows:** ADR-025 rulings 1 and 2. **Extends:** ADR-023 (bytes copied, written once),
7
+ ADR-024 (simt-dev's own copies are refreshed by `simt-dev ci`). Settles the Dependabot
8
+ item §3.1 row 8 of `docs/plans/0001-centralise-agent-rules.md` named as still missing.
9
+
10
+ ## Context
11
+
12
+ ADR-025 ruled that a baseline is a marker-managed region, and that only a file whose format
13
+ can carry a comment may hold one. Ruling 2 named `tsconfig.base.json`, `.prettierrc.json` and
14
+ `.nvmrc` as "ruled out, not deferred", and its consequences promised that "the next fix is
15
+ three more JSON files and therefore a different mechanism". That mechanism did not exist.
16
+
17
+ Dependabot arrived first, and not by accident: it was the one owed baseline that needed no
18
+ new mechanism at all, and the gap had been named and dated in the plan since before any of
19
+ this existed — row 8 says the Dependabot config "is still missing and is not part of that
20
+ ruling". A repo with no Dependabot config does not receive security patches as pull requests;
21
+ it finds out from an advisory.
22
+
23
+ Dependabot also supplied the missing counterexample to ADR-025's ruling 2, which is why
24
+ this record exists rather than a template file. `updates:` is a **YAML list**. Two lists
25
+ cannot be concatenated. There is no region shape that means "these entries are mine and
26
+ those are yours", so there is nothing to merge and nothing to preserve — the mechanism
27
+ ADR-025 chose does not apply to this file because the file's grammar has nowhere to put it.
28
+
29
+ That is a property of the file, not a reason to prefer a different file. The question worth
30
+ ruling on is what ownership means for a config simt-dev writes into a repo and must not
31
+ rewrite, and ADR-023/024 had already answered it for the file sitting next to this one in
32
+ the same directory.
33
+
34
+ ## Rulings
35
+
36
+ 1. **A config whose grammar cannot hold a region is a whole file the repo owns from the
37
+ moment it is written.** `simt-dev init` creates `.github/dependabot.yml` once and never
38
+ touches it again. There is no partial ownership to describe because there is nothing to
39
+ merge; the repo's own cadence, `ignore` rules, `groups` and private `registries` are
40
+ edits to a file simt-dev has already stopped writing.
41
+
42
+ 2. **Ownership does not depend on content being mergeable.** ADR-023's rule — copied bytes,
43
+ written once, the reader's from the first commit — extends from the CI gate to this file
44
+ unchanged. A reader of ADR-023 who assumed the rule depended on the file having a
45
+ place for a region was wrong, and this is the record that says so.
46
+
47
+ 3. **The content is detection-driven, from facts that already exist.** Each entry names an
48
+ ecosystem this tree has a manifest for, derived from `fingerprint`'s `has-*` facts and
49
+ stack tags. No new fact is declared, so ADR-013's "content is data, the engine is code"
50
+ holds without a profile change. The failure this prevents is an entry that looks
51
+ configured and configures nothing: Dependabot finds no manifest, opens no pull request,
52
+ and the config reads as though the repo's dependencies are watched.
53
+
54
+ 4. **One entry per ecosystem, not one per manifest.** `pyproject.toml` and `requirements.txt`
55
+ are two ways of declaring python dependencies and Dependabot reads both under `pip`. Two
56
+ `pip` entries is a duplicate the config rejects or silently collapses, and the reader has
57
+ no way to tell which won.
58
+
59
+ 5. **`has-build-system` is not mapped to an ecosystem.** Makefile, CMakeLists and
60
+ `meson.build` are build files, not dependency manifests, and Dependabot has no ecosystem
61
+ that reads them. Mapping the fact to `maven` would be a plausible-looking line that
62
+ watches nothing — ruling 3's failure mode, wearing a fact's name.
63
+
64
+ 6. **`github-actions` is the one unconditional entry,** and it is unconditional because of
65
+ what this package ships: simt-dev writes a workflow into every repo it adopts, so every
66
+ repo that adopted it has Actions to watch. A repo with no workflow has no Actions.
67
+
68
+ 7. **The file appears only where `.github/workflows` already exists,** for the same reason
69
+ ADR-023 ruled it for the gate: creating that directory silently would start opening
70
+ pull requests nobody asked for.
71
+
72
+ 8. **Both `.github` files are planned, written and refused together, by one command.**
73
+ `simt-dev ci` handles the workflow and the config because they answer the same question
74
+ the same way; a reader learning which command owns which file would be learning about
75
+ ownership twice to learn nothing new. `simt-dev ci` still refuses outside this
76
+ repository, naming `simt-dev init --yes` as the writer.
77
+
78
+ 9. **`check` reports absence and never contents,** as it does for the gate. A file whose
79
+ every byte is legitimately theirs cannot be diffed against a template without reporting
80
+ their work as drift.
81
+
82
+ ## Consequences
83
+
84
+ `.github/dependabot.yml` joins `.github/workflows/simt-dev-check.yml` as a second shipped
85
+ `.github` file with one ownership rule and one writer. `check` gains a second `absent`
86
+ finding whose remedy is the same `simt-dev init --yes`, so a repo that runs Actions with a
87
+ gate but no dependency updates is reported rather than left to find out from an advisory.
88
+
89
+ What this does **not** settle: `tsconfig.base.json`, `.prettierrc.json` and `.nvmrc` are
90
+ still regions that cannot exist. Ruling 1 answers the ownership question for them when
91
+ someone writes one, and it is deliberately the same answer as here, but no file has been
92
+ written and none should be inferred. The gap stays named in §3.1 row 5.
93
+
94
+ The estate consequence is the one that costs: no repository in it had a Dependabot config,
95
+ and the three pilot repositories from Phase 4 will each need `simt-dev upgrade` to receive
96
+ one. That is ADR-001's ordinary cost and is not a defect.
97
+
98
+ ## Rejected
99
+
100
+ - **A region inside `updates:`**, with entries above and below it. Rejected because it does
101
+ not exist: YAML lists have no interior, and a comment-delimited block in the middle of a
102
+ sequence is not a sequence. Shipping it would produce a config GitHub rejects.
103
+ - **Merging by rewriting the whole `updates:` list,** preserving the repo's entries by
104
+ parsing and re-emitting them. This is the one design that could give partial ownership,
105
+ and it is rejected for the same reason as a manifest merge: simt-dev would have to parse
106
+ and re-emit a config it does not own, and every round trip through this tool would be an
107
+ opportunity to drop a key this tool never understood. ADR-015's content-not-location
108
+ principle cuts the same way — the repo's config is identified by its bytes, and this tool
109
+ does not hold those bytes.
110
+ - **Prefixing the keys** to claim ownership, as ADR-022 does for rule frontmatter. Rejected
111
+ because these keys are GitHub's: Dependabot rejects `simt-package-ecosystem`. Ownership
112
+ here is expressed by not writing the file again, not by renaming what GitHub reads.
113
+ - **One fixed list for every repo,** `github-actions` plus `npm`. Rejected by ruling 3: it
114
+ writes an `npm` entry into a repo with no `package.json`.
115
+ - **A new `has-node-manifest` fact,** so the table reads uniformly. Rejected because `node`
116
+ is already a stack tag and `typescript` already a dependency name; a third name for one
117
+ observation is the duplication `fingerprint.mjs`'s own table header rules out.