simt-dev 0.1.1 → 0.2.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 (91) hide show
  1. package/CHANGELOG.md +209 -7
  2. package/README.md +32 -5
  3. package/docs/decisions/ADR-001-push-requires-approval.md +5 -5
  4. package/docs/decisions/ADR-002-refactor-blast-radius.md +1 -1
  5. package/docs/decisions/ADR-003-test-breadth.md +4 -4
  6. package/docs/decisions/ADR-004-hook-owns-format.md +5 -5
  7. package/docs/decisions/ADR-005-file-length.md +5 -5
  8. package/docs/decisions/ADR-006-coverage-bar.md +3 -3
  9. package/docs/decisions/ADR-007-section-skeleton.md +5 -5
  10. package/docs/decisions/ADR-008-verdict-vocabulary.md +1 -1
  11. package/docs/decisions/ADR-009-skill-layout.md +1 -1
  12. package/docs/decisions/ADR-010-runner-invocation.md +1 -1
  13. package/docs/decisions/ADR-012-drop-windows-support.md +2 -2
  14. package/docs/decisions/ADR-015-a-source-is-content-not-a-location.md +2 -2
  15. package/docs/decisions/ADR-016-a-divergent-rule-is-retired-not-merged.md +13 -13
  16. package/docs/decisions/ADR-017-a-declared-gate-must-be-runnable.md +2 -2
  17. package/docs/decisions/ADR-018-an-unset-hooks-path-is-not-an-absent-hook.md +9 -9
  18. package/docs/decisions/ADR-019-a-declared-command-is-the-runner.md +34 -7
  19. package/docs/decisions/ADR-023-the-gate-ships-as-a-file-the-repo-owns.md +2 -2
  20. package/docs/decisions/ADR-027-the-one-gitattributes-line-that-is-neither-dangerous-nor-empty.md +5 -5
  21. package/docs/decisions/ADR-028-a-base-file-is-a-floor-so-the-disagreement-it-cannot-repair-becomes-a-check.md +2 -2
  22. package/docs/decisions/ADR-029-the-pins-a-repository-declares-are-its-own.md +1 -1
  23. package/docs/decisions/ADR-030-what-a-plan-does-not-ship-is-a-decision-with-a-record.md +2 -2
  24. package/docs/decisions/ADR-031-the-suite-stages-the-environment-it-needs.md +3 -3
  25. package/docs/decisions/ADR-033-three-plan-rows-closed-by-decision-not-by-authoring.md +4 -4
  26. package/docs/decisions/ADR-041-the-suite-installs-the-package-in-order-to-test-it.md +2 -2
  27. package/docs/decisions/ADR-045-a-dashboard-that-counts-a-defect.md +3 -3
  28. package/docs/decisions/ADR-046-one-rule-one-copy.md +5 -5
  29. package/docs/decisions/ADR-047-a-profile-selects-on-what-a-repository-runs-on.md +4 -4
  30. package/docs/decisions/ADR-048-a-baseline-carries-only-keys-a-reader-honours.md +5 -5
  31. package/docs/decisions/ADR-057-an-identity-is-per-developer-and-a-repository-does-not-own-it.md +115 -0
  32. package/docs/decisions/ADR-058-one-tool-three-channels-and-the-order-is-forced.md +148 -0
  33. package/docs/decisions/ADR-059-the-version-a-repository-runs-is-the-one-it-pinned.md +75 -0
  34. package/docs/decisions/ADR-060-a-repository-with-nothing-to-run-is-adopted-and-says-so.md +131 -0
  35. package/docs/decisions/ADR-061-the-skill-registry-is-workspace-data.md +113 -0
  36. package/docs/decisions/ADR-062-a-fresh-adoption-seeds-the-gates-it-can-run.md +94 -0
  37. package/docs/decisions/ADR-063-the-adoption-escape-hatch-is-opt-in.md +69 -0
  38. package/docs/decisions/README.md +20 -1
  39. package/package.json +1 -2
  40. package/rules/stacks/dart.md +38 -0
  41. package/rules/stacks/deno.md +36 -0
  42. package/rules/stacks/dotnet.md +35 -0
  43. package/rules/stacks/elixir.md +39 -0
  44. package/rules/stacks/go.md +34 -0
  45. package/rules/stacks/ruby.md +36 -0
  46. package/rules/stacks/rust.md +34 -0
  47. package/rules/stacks/swift.md +37 -0
  48. package/src/argv.mjs +35 -6
  49. package/src/ci/dependabot.mjs +1 -1
  50. package/src/ci/workflow.mjs +33 -11
  51. package/src/commands/graph.mjs +13 -4
  52. package/src/commands/help.mjs +22 -4
  53. package/src/commands/hooks.mjs +183 -67
  54. package/src/commands/index.mjs +53 -45
  55. package/src/commands/init.mjs +156 -14
  56. package/src/commands/rules.mjs +54 -3
  57. package/src/commands/skills.mjs +143 -15
  58. package/src/commands/skillsinstall.mjs +4 -4
  59. package/src/commands/sync.mjs +153 -11
  60. package/src/compare/discover.mjs +1 -1
  61. package/src/compare/hooksstate.mjs +96 -9
  62. package/src/compare/row.mjs +36 -7
  63. package/src/decisions/index.mjs +51 -12
  64. package/src/graph/load.mjs +126 -15
  65. package/src/hooks/capability.mjs +49 -5
  66. package/src/hooks/dispatcher.mjs +51 -6
  67. package/src/hooks/gates.mjs +1 -3
  68. package/src/hooks/resolve.mjs +24 -25
  69. package/src/hooks/shim.mjs +29 -5
  70. package/src/hooks/where.mjs +1 -1
  71. package/src/identity.mjs +207 -0
  72. package/src/mcp/tools.mjs +2 -2
  73. package/src/output/index.mjs +8 -7
  74. package/src/package-version.mjs +74 -0
  75. package/src/projection/baselines.mjs +1 -1
  76. package/src/projection/conflicts.mjs +57 -6
  77. package/src/projection/manifest.mjs +248 -26
  78. package/src/projection/markers.mjs +3 -3
  79. package/src/projection/mdc.mjs +6 -15
  80. package/src/projection/project.mjs +1 -1
  81. package/src/projection/rules.mjs +21 -8
  82. package/src/projection/surfaces.mjs +2 -2
  83. package/src/projection/targets.mjs +53 -7
  84. package/src/resolve/eval.mjs +64 -0
  85. package/src/resolve/fingerprint.mjs +4 -3
  86. package/src/resolve/near.mjs +26 -7
  87. package/src/resolve/resolve.mjs +1 -1
  88. package/src/resolve/source.mjs +2 -2
  89. package/src/tsconfig.mjs +1 -1
  90. package/src/workspace.mjs +0 -9
  91. package/graph/skills.graph.json +0 -1622
package/CHANGELOG.md CHANGED
@@ -4,6 +4,207 @@ All notable changes to this package are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project follows
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.1] — 2026-10-13
10
+
11
+ ### `init` writes in place; the backup tag and adopt branch are opt-in
12
+
13
+ `simt init --yes` used to always tag the pre-adoption commit and branch onto a dedicated
14
+ adopt branch before writing. The safety argument was sound, but consumers kept reporting
15
+ the branch switch as a surprise — a well-announced surprise is still a surprise.
16
+
17
+ The default now writes in place on the branch you already have: nothing is tagged, nothing
18
+ is branched, and the run says so in an `in place` line. The reviewable diff survives —
19
+ `git diff` shows the whole adoption, and discarding it is a checkout and a clean.
20
+
21
+ The old behaviour moves behind `--backup`: `simt init --yes --backup` tags the pre-adoption
22
+ commit and branches as before, for readers who want the named undo path. ADR-063 records
23
+ the decision and the one behaviour it invalidates: consumers who scripted against the old
24
+ default add `--backup`.
25
+
26
+ ### A fresh adoption seeds the gates it can run — and only those
27
+
28
+ The eight common ecosystems outside the JavaScript world — Rust, Go, .NET, Swift, Deno,
29
+ Ruby, Dart and Elixir — were recognised by the fingerprint and served by nothing: no
30
+ profile selected them, no gate was proposed for them. A fresh Rust repository received the
31
+ core essay and a manifest that runs nothing, while the ecosystems that emit stack tags got
32
+ the full treatment.
33
+
34
+ Each now has a profile that selects on its own `has-*` fact, so one marker file reaches
35
+ both the rules the repository reads and the gates its commits run. Maven's profile predates
36
+ this; its row is gates-only, wrapper-first, like `gradlew`.
37
+
38
+ `simt init` now seeds the canonical commands for a detected ecosystem — `cargo fmt
39
+ --check`, `go vet ./...`, `dotnet test`, and the rest of the table — into the manifest's
40
+ gates, but only where a probe found the tool: a binary on PATH, or a file in the repository
41
+ for the Maven wrapper. A marker says the ecosystem is here; the probe says its program can
42
+ run. A declared gate that cannot run fails closed on every commit, so the seed fires only
43
+ when both are true — and where the probe fails, the gate is dropped with a remedy that
44
+ names the install instead of blocking the first commit.
45
+
46
+ A seed is a default: a command the repository already declared is never re-seeded, and an
47
+ npm runner keeps its own scripts, because `package.json` is the repository's own answer to
48
+ "how do I test and format". ADR-062 rules the shape of all of it.
49
+
50
+ ### The resolver is measured against a gold corpus
51
+
52
+ `simt skills eval` scores the skill resolver against a corpus of real tasks × real
53
+ repositories, each case carrying a gold list of the skills it should select and a list
54
+ of the ones it must not. It reports precision and recall, prints a PASS/FAIL line per
55
+ case naming the skills it missed or selected that it should not have, and exits
56
+ non-zero on a regression — so it can be run from CI the way the gate is run.
57
+
58
+ The scoring lives in `src/resolve/eval.mjs`, which the command and
59
+ `test/eval.test.mjs` both call, so a test cannot drift from what the command measures.
60
+ The corpus lives under `test/` because test data does not ship in the package: an
61
+ installed copy names the path it would have read and says so instead of scoring the
62
+ author's.
63
+
64
+ ### The skill registry is workspace data; the package ships none of it
65
+
66
+ The npm tarball and the wheel carried `graph/skills.graph.json` — the directory
67
+ of skill sources for one workspace, naming the repositories whose bodies it
68
+ resolves. Every installed copy served that catalogue to readers who have none
69
+ of those skills, and `skills install` pointed at paths that exist only in the
70
+ workspace that wrote them. ADR-061 rules the registry out of the published set:
71
+ it is data about one workspace, not content of the package.
72
+
73
+ The default registry path now resolves in tiers, and every tier is file
74
+ existence plus configuration — nothing a pull request cannot diff:
75
+
76
+ 1. an explicit path, the positional of `simt graph lint`,
77
+ 2. the package's own `graph/skills.graph.json` — present in a source checkout,
78
+ absent from an installed copy,
79
+ 3. the member of a configured workspace that holds one — naming the workspace
80
+ it came from, and refusing when several members hold one, because picking
81
+ would be a guess.
82
+
83
+ An installed copy in a workspace with no registry says so, and names the three
84
+ ways to configure one (`--workspace`, `SIMT_DEV_WORKSPACE`, the user config
85
+ file) instead of failing on a path it does not have. `simt graph lint`'s
86
+ no-registry remedy names the path explicitly, because its default is the
87
+ registry it lints.
88
+
89
+ The provenance digest stops walking `graph/` for the same reason it no longer
90
+ leaves the package: the digest covers what a published copy ships, and the
91
+ registry is no longer among it.
92
+
93
+ ### No published file may name a repository from this estate
94
+
95
+ The decision records ship in all three channels — npm, the wheel and the sdist — so a
96
+ private repository name written into one is published to three registries. That happened:
97
+ the records were pseudonymised once, across 28 files, and nothing stopped the next one. The
98
+ sweep's own commit says why, and it is the right reason: the redaction it used runs on the
99
+ way *out*, at print time, and the bytes on disk are what get published.
100
+
101
+ `test/shipped.test.mjs` now fails on an estate name anywhere in a published file, and
102
+ asserts its own scope against `package.json` in **both** directions — a directory added to
103
+ `files` without being guarded fails, and so does one guarded that nothing publishes, because
104
+ a guard nobody can fail is one somebody eventually deletes. It is scoped to the published
105
+ set rather than a hand-written list for the same reason: the sweep took 28 files to undo by
106
+ hand, and the guard should not need undoing at all.
107
+
108
+ Names are not removed, they are described. The records that use a repository as *evidence* —
109
+ a table of how three repositories answer the same question — carry stable `repo-NN` labels,
110
+ so the comparison survives. Everything else is better off naming what the repository *is*:
111
+ "a Gradle module with no wrapper", "a repository with no package.json". That reads to
112
+ someone outside the estate without a lookup table they do not have.
113
+
114
+ The one place estate names remain is `docs/reviews/`, which is not published by either
115
+ channel. A review whose subject is fourteen repositories cannot pseudonymise them without
116
+ becoming a document about `repo-01` that never existed.
117
+
118
+ ### Four shipped strings named a command this package does not install
119
+
120
+ `0.2.0` installs one binary, `simt`, and `package.json`'s `bin` map says so. Four
121
+ places still said `simt-dev`, which a reader types and is met with `unknown command`:
122
+
123
+ - the default remedy on every bad invocation, `run: simt-dev --help` — so the advice
124
+ printed after a bad command could not be followed
125
+ - the usage line, `usage: simt-dev <command>`, sitting above a command list that spelled
126
+ the same tool `simt`
127
+ - `.github/dependabot.yml`'s header, which said `Yours from here: simt-dev` while the
128
+ gate beside it said `Yours from here: simt`
129
+ - the hook shim, whose own resolution list said `simt-dev on PATH` directly above the
130
+ `command -v simt` that does the looking
131
+
132
+ `test/naming.test.mjs` was supposed to prevent this and did not: its rule required a
133
+ verb after the project name, and none of the four is followed by one. It now also
134
+ catches a flag, a `<placeholder>`, the end of a line, and a program name in a
135
+ resolution list — while still accepting the sentences where the project is the
136
+ subject, which is the spelling that is correct. The two `.github` templates get their
137
+ own assertion, because the fourth of these was not a wrong word in a sentence; it was
138
+ two templates disagreeing with each other in the same position.
139
+
140
+ ### Fixed
141
+
142
+ - `hooks install` removes a shim whose gate was dropped from the manifest instead of leaving it to run nothing. A repository that removed its last gate was refused outright, with a remedy telling it to put the gate back; only un-routing git was left to the reader. install also no longer chains a hook to itself.
143
+
144
+ - **Dead exports and duplicated frontmatter, with a test that stops them returning (S21).**
145
+ Eight functions were exported and called by nothing (`gateKind`, `gateWhy`, `gateAdr`,
146
+ `resetWorkspace`, `tracksIdentity`, `isTty`, `surfaceFrontmatter`, `workspaceOrNull`),
147
+ three `__internals` testing seams had no importer, and thirteen more bindings were
148
+ exported while being used only inside their own file — `isExecutable` among them, which
149
+ a first pass through this list wrongly recorded as dead and which its own callers
150
+ proved otherwise. `KNOWN_SUBS` was a hand-kept second copy of the dispatch table, and
151
+ had already drifted: it carried `doctor`, a bare command the group lookup can never
152
+ reach. `mdcFrontmatter` was a second construction of frontmatter the writer now derives
153
+ itself, with a test asserting the copy rather than the behaviour.
154
+
155
+ - **"Did you mean" offered the shortest fragment first, and a misspelt skill was
156
+ suggested for a correctly spelled one (S22).** `nearMatches` had no test at all.
157
+ Both directions of substring scored 0 — the same score as an exact match — so the
158
+ alphabetical tiebreak decided the order, and `skills graphs` suggested `graph`
159
+ before `graphs`. Worse, the containment test had no length floor, so `test` matched
160
+ the candidate `e` and the message read `did you mean e, test-writer?`, which an
161
+ agent has every reason to install. A prefix now scores 1 rather than 0, a fragment
162
+ counts only when it is at least half the query, and the edit bound scales with the
163
+ query's length — three edits is a typo in `slice-commmit` and is most of a
164
+ four-character query.
165
+
166
+ - **The conflict scanner skipped two of the five rule surfaces, and one pointer file
167
+ (S22).** `rulePaths` enumerated filenames by hand, so `.claude/rules/` and
168
+ `.agents/rules/` — added to the surface table after the list was written — were
169
+ never scanned, and a hand-written rule contradicting a generated one there was
170
+ invisible. A conflict detector that only looks where it was pointed looks nowhere
171
+ new. The scan list is now derived from the surface table and the pointer table.
172
+
173
+ ## [0.2.0] — 2026-10-11
174
+
175
+ ### Publishable from PyPI and Homebrew as well as npm
176
+
177
+ simt-dev is a *repository* tool, and the people who adopt a repository are not
178
+ all Node developers. Somebody running `simt init` inside a repository with no
179
+ `package.json` has no reason to install a package manager, and a Homebrew user
180
+ has no reason to install Node to install a tool that needs Node.
181
+
182
+ So it now publishes to three channels, from one version number:
183
+
184
+ ```sh
185
+ npm i -D simt-dev # a tarball of .mjs files
186
+ pip install simt-dev # a wheel carrying those same bytes
187
+ brew install QuazarMedia/tap/simt-dev
188
+ ```
189
+
190
+ The wheel is not a wrapper around `npm install`. It carries the tool's own
191
+ source, and `scripts/verify-wheel.mjs` builds both artefacts and hashes every
192
+ file in both — a release fails when a single byte differs between them. That
193
+ check exists because the obvious defect in this arrangement is the wheel and the
194
+ tarball quietly shipping different code.
195
+
196
+ `simt` is the one command, on every channel. Where node comes from is
197
+ `SIMT_DEV_NODE`, then the bundled node from `pip install "simt-dev[node]"`,
198
+ then `node` on `PATH` — and if none of those resolve you get the remedy rather
199
+ than a placeholder path. There are no required dependencies on any channel.
200
+ *(ADR-058)*
201
+
202
+ The channels are published in a fixed order rather than in parallel, and the
203
+ reason is not taste: the Homebrew formula downloads the npm tarball at install
204
+ time, so a formula naming a version still sitting in npm's staging area
205
+ installs a 404. Both jobs fail with that stated, and are run again after
206
+ `npm stage approve`.
207
+
7
208
  ## [0.1.1] — 2026-10-11
8
209
 
9
210
  ### A foreign hook on an event this repo does not gate is chained
@@ -13,17 +214,17 @@ recommending. It chained on the event *vocabulary* — anything that was not
13
214
  `pre-commit` or `pre-push` — when the question worth asking is whether **this
14
215
  repository** declares a gate for that event.
15
216
 
16
- The difference is `simt-app`, whose `pre-push` is `git-lfs`. `pre-push` is an
217
+ The difference is a repository whose `pre-push` is `git-lfs`. `pre-push` is an
17
218
  event this tool gates in general, so `0.1.0` displaced that hook; and because
18
- `simt-app` declares no `pre-push` gate there was no shim for the event either, so
19
- git would have found no `pre-push` hook at all. LFS objects would have stopped
20
- being uploaded, with nothing to notice it — the exact silent failure chaining
21
- exists to prevent, reached by fixing the wrong half of it.
219
+ that repository declares no `pre-push` gate there was no shim for the event
220
+ either, so git would have found no `pre-push` hook at all. LFS objects would have
221
+ stopped being uploaded, with nothing to notice it — the exact silent failure
222
+ chaining exists to prevent, reached by fixing the wrong half of it.
22
223
 
23
224
  `0.1.1` asks the manifest. An event the repo declares a gate for is left to
24
225
  `gates.commands`, where the hook runs as a gate and its verdict appears in the
25
- report; every other foreign hook is chained. That also picks up
26
- `simt-landing`'s Lighthouse pre-push, which declares no gates at all.
226
+ report; every other foreign hook is chained. That also picks up a static
227
+ site's Lighthouse pre-push, which declares no gates at all.
27
228
  *(ADR-018, as amended)*
28
229
 
29
230
  Upgrade with `npm i -D simt-dev@0.1.1`, then `simt hooks install --yes`. Any
@@ -126,5 +327,6 @@ never ran `simt hooks install` again will find nothing until the dependency is r
126
327
  and `simt hooks install --yes` is re-run. That is a real upgrade step and it is called out
127
328
  here rather than discovered.
128
329
 
330
+ [0.2.0]: https://github.com/QuazarMedia/simt-dev/releases/tag/v0.2.0
129
331
  [0.1.1]: https://github.com/QuazarMedia/simt-dev/releases/tag/v0.1.1
130
332
  [0.1.0]: https://github.com/QuazarMedia/simt-dev/releases/tag/v0.1.0
package/README.md CHANGED
@@ -19,19 +19,46 @@ that refuses a commit which breaks a gate that repo can genuinely run.
19
19
 
20
20
  ## Install
21
21
 
22
- Requires **Node >= 22.20.0**.
22
+ Requires **Node >= 22.20.0** (the PyPI install can supply it, see below).
23
23
 
24
24
  ```sh
25
25
  # pinned, per repository - what CI and a teammate both get
26
- npm i -D simt-dev@0.1.1
26
+ npm i -D simt-dev@0.2.1
27
27
 
28
28
  # or globally, if you would rather not add a dependency
29
- npm i -g simt-dev@0.1.1
29
+ npm i -g simt-dev@0.2.1
30
30
 
31
31
  # or with no install at all, for a one-off
32
- npx -y simt-dev@0.1.1 check
32
+ npx -y simt-dev@0.2.1 check
33
33
  ```
34
34
 
35
+ ### From PyPI
36
+
37
+ The same tool, from the same bytes. The wheel carries the exact contents the npm
38
+ tarball carries — the wheel is not a wrapper around `npm install`, so nothing is
39
+ fetched when you install it.
40
+
41
+ ```sh
42
+ pip install simt-dev
43
+
44
+ # and if this machine has no node at all
45
+ pip install "simt-dev[node]"
46
+ ```
47
+
48
+ `simt` is the command on both channels. Where node comes from is resolved in
49
+ this order, and the first one that answers wins: `SIMT_DEV_NODE`, the bundled
50
+ node from the `node` extra, then `node` on your `PATH`. If none of them resolve,
51
+ you get a message naming the remedy rather than a placeholder node path.
52
+
53
+ ### From Homebrew
54
+
55
+ ```sh
56
+ brew install QuazarMedia/homebrew-tap/simt-dev
57
+ ```
58
+
59
+ The formula declares its own `node` dependency, so `brew install` gives you a
60
+ working command on a machine that has never had Node.
61
+
35
62
  Pin the version. The tool writes a content digest into the files it generates, and an
36
63
  unpinned upgrade changes them under you.
37
64
 
@@ -54,7 +81,7 @@ simt compare # what changed across every repository that adopted it
54
81
  | Path | What |
55
82
  | --- | --- |
56
83
  | `AGENTS.md` | the projection, between `<!-- simt:begin -->` and `<!-- simt:end -->` (renamed from `simt-dev:`; the old markers are still read, and a region migrates on its next write) |
57
- | `simt.json` | your manifest: which gates to declare, which substitutions to fill (renamed from `simt-dev.json`; the old name is still read, and moves on the next write) |
84
+ | `simt.json` | your manifest: which gates to declare, which substitutions to fill |
58
85
  | `.cursor/rules/*.mdc`, `.claude/rules/*.md`, `.agents/rules/*.md`, `.github/instructions/*.instructions.md` | one file per rule, written only for the harnesses that read their own directory |
59
86
  | `.editorconfig`, `.gitattributes` | baseline regions |
60
87
  | `.simt-hooks/` and `core.hooksPath` | the shared dispatcher, fail-closed |
@@ -8,14 +8,14 @@ The repos state a commit/push policy. They disagree on whether an agent may push
8
8
 
9
9
  - A repo outside this estate: "always create a focused Git commit… skip the commit only
10
10
  when the user explicitly asks not to commit." Silent on push.
11
- - `simt-garmin/AGENTS.md` DoD #8: "**Committed and pushed** with a conventional message."
12
- - `simt-social` and `simt-social-api`: "create a non-interactive Conventional Commit. Report
11
+ - `repo-07/AGENTS.md` DoD #8: "**Committed and pushed** with a conventional message."
12
+ - `repo-14` and `repo-11`: "create a non-interactive Conventional Commit. Report
13
13
  the commit SHA; **do not push**."
14
- - `simt-api`, `simt-social-media`: silent.
14
+ - `repo-04`, `repo-13`: silent.
15
15
 
16
16
  The Social pair justify it: a push to the production branch triggers Cloudflare Workers Builds,
17
17
  so "an approved push is therefore a production deployment action, not only source publication."
18
- `simt-garmin` has no such coupling, and its rule asks for an autonomous push.
18
+ `repo-07` has no such coupling, and its rule asks for an autonomous push.
19
19
 
20
20
  ## Ruling
21
21
 
@@ -24,7 +24,7 @@ Commit locally, report the SHA, **push only on explicit user approval**.
24
24
  When a repo's push triggers a deployment, a migration, or any remote mutation, say so before
25
25
  asking for approval — do not treat approval for the push as approval for the deploy.
26
26
 
27
- `simt-garmin` DoD #8 changes to "committed with a conventional message; pushed on approval."
27
+ `repo-07` DoD #8 changes to "committed with a conventional message; pushed on approval."
28
28
  This is the single outlier, and the 4:1 majority is also the safe direction.
29
29
 
30
30
  ## Consequences
@@ -6,7 +6,7 @@ Status: **accepted** · 2026-10-05 · affects all repos
6
6
 
7
7
  Two repos state opposite philosophies, and both are reasonable in isolation.
8
8
 
9
- - `simt-social` / `simt-social-api`: "When a second real use or a near-duplicate already
9
+ - `repo-14` / `repo-11`: "When a second real use or a near-duplicate already
10
10
  exists, refactor the existing code to extract the shared part… A third copy of the same
11
11
  logic is a defect, and so is an abstraction invented for a single caller."
12
12
  - A repo outside this estate: "Match existing style, naming, and test layout. **Do not
@@ -4,13 +4,13 @@ Status: **accepted** · 2026-10-05 · affects all repos
4
4
 
5
5
  ## Context
6
6
 
7
- - `simt-social` / `simt-social-api`: "Focused tests are the default gate, and full suites are
7
+ - `repo-14` / `repo-11`: "Focused tests are the default gate, and full suites are
8
8
  the exception… **absent a named trigger, running a full suite is a defect, not diligence.**"
9
9
  - A repo outside this estate: `fail_under = 100` plus a full-suite script as the pre-push
10
10
  default, and a contributor loop that says "run the full gate locally (lint + tests +
11
11
  coverage)."
12
- - `simt-garmin`: reframes the axis entirely as a layer-conditional 5a–5m matrix.
13
- - `simt-social-media`: no policy — it just lists `npm run test:unit && npm run test:e2e`.
12
+ - `repo-07`: reframes the axis entirely as a layer-conditional 5a–5m matrix.
13
+ - `repo-13`: no policy — it just lists `npm run test:unit && npm run test:e2e`.
14
14
 
15
15
  The Social pair make a full suite a sin. media presents it as unremarkable. The hard-gate
16
16
  repo makes it mandatory. These cannot all be org rules as stated.
@@ -34,7 +34,7 @@ adopted as canonical.
34
34
  ## Consequences
35
35
 
36
36
  - Each repo's `simt-dev.json` declares which of the six triggers are active for it. A repo
37
- with a declared numeric gate activates 4 and 6; the Social repos activate 1, 2 and 3.
37
+ with a declared numeric gate activates 4 and 6; one repository activate 1, 2 and 3.
38
38
  - A reviewer can ask "which trigger?" and get a number, not an opinion.
39
39
  - media gains an explicit policy instead of an implicit one that contradicts its siblings.
40
40
 
@@ -4,16 +4,16 @@ Status: **accepted** · 2026-10-05 · affects all repos
4
4
 
5
5
  ## Context
6
6
 
7
- - `simt-social-api`: "lint and format are enforced by the pre-commit hook — **do not run them
7
+ - `repo-11`: "lint and format are enforced by the pre-commit hook — **do not run them
8
8
  manually.**"
9
- - `simt-social`: "the local pre-push hook republishes opportunistically when a token happens to
9
+ - `repo-14`: "the local pre-push hook republishes opportunistically when a token happens to
10
10
  be present." Never says the hook is the gate; instructs agents to run static checks directly.
11
11
  - A repo outside this estate: tells agents to run its linter and `git diff --check` by hand,
12
12
  and its contributor guide repeats it.
13
- - `simt-api`, and 11 repos with no hooks at all: silent.
13
+ - `repo-04`, and 11 repos with no hooks at all: silent.
14
14
 
15
15
  The audit also found the estate's hook reality: 4 incompatible conventions, and
16
- `simt-app/hooks/pre-push` is **0 bytes** while the real git-lfs pre-push sits unused in
16
+ `repo-05/hooks/pre-push` is **0 bytes** while the real git-lfs pre-push sits unused in
17
17
  `scripts/hooks/`.
18
18
 
19
19
  ## Ruling
@@ -33,7 +33,7 @@ skip.
33
33
  ## Consequences
34
34
 
35
35
  - The shared hook dispatcher from plan 0001 lands in every repo that has one, which also
36
- delivers the dead `simt-app/hooks/pre-push` fix.
36
+ delivers the dead `repo-05/hooks/pre-push` fix.
37
37
  - `simt-dev doctor` reports hook installation state, so "the hook will cover it" is a
38
38
  verifiable claim rather than an assumption.
39
39
  - The 11 hook-less repos get a pre-commit on adoption, which ends the silent case entirely.
@@ -4,9 +4,9 @@ Status: **accepted** · 2026-10-05 · affects all repos
4
4
 
5
5
  ## Context
6
6
 
7
- - `simt-social` / `simt-social-api`: "**Split any file once it exceeds 1000 lines**; extract
7
+ - `repo-14` / `repo-11`: "**Split any file once it exceeds 1000 lines**; extract
8
8
  along the nearest cohesive boundary instead of growing the file further."
9
- - `simt-garmin`: "**File length: 400 lines is a smell threshold, not a hard gate.**" Generated
9
+ - `repo-07`: "**File length: 400 lines is a smell threshold, not a hard gate.**" Generated
10
10
  `.mc` files are exempt, with a named exception for a 408-line template.
11
11
  - Several repos: no file-length rule stated at all.
12
12
 
@@ -27,10 +27,10 @@ Per-repo overrides are permitted via `limits.fileLines` in `simt-dev.json`.
27
27
 
28
28
  ## Consequences
29
29
 
30
- - The Social repos' hard 1000 gate and garmin's soft 400 both survive unchanged in force.
30
+ - one repository' hard 1000 gate and garmin's soft 400 both survive unchanged in force.
31
31
  - The generated-file exemption that garmin had to state in prose becomes a declared property,
32
32
  so the hook can honour it without hardcoding `.mc`.
33
- - `simt-social`'s pre-commit file-size check (currently inlined as 1000 lines of shell, and
33
+ - `repo-14`'s pre-commit file-size check (currently inlined as 1000 lines of shell, and
34
34
  duplicating `scripts/check-file-sizes.ts`) becomes one implementation in the shared
35
35
  dispatcher.
36
36
 
@@ -38,5 +38,5 @@ Per-repo overrides are permitted via `limits.fileLines` in `simt-dev.json`.
38
38
 
39
39
  - **One number org-wide.** Either it is too tight for legitimately long declarative files or
40
40
  too loose to prompt a human at 400.
41
- - **No rule.** The Social repos' pre-commit check exists precisely because a rule was missing,
41
+ - **No rule.** one repository' pre-commit check exists precisely because a rule was missing,
42
42
  and it is now implemented twice.
@@ -9,9 +9,9 @@ The coverage bar is the one concept that is mutually incompatible *in kind* acro
9
9
  | Repo | Bar |
10
10
  |---|---|
11
11
  | Repos with a declared numeric bar (outside this estate) | Quantitative. `fail_under = 100`, branch coverage, "a behavioural coverage gate, not a line-count scoreboard" |
12
- | `simt-garmin` | Quantitative, but a different quantity. Memory: 64 KB app / 24 KB Glance against a 32 KB ceiling, plus 12 named lint scripts |
13
- | `simt-social`, `simt-social-api`, `simt-social-media` | Qualitative. No number anywhere. Evidence discipline: named commands, 100 % pass, no unjustified skips, behavioural test delta |
14
- | `simt-api` | Neither. Three verification commands. |
12
+ | `repo-07` | Quantitative, but a different quantity. Memory: 64 KB app / 24 KB Glance against a 32 KB ceiling, plus 12 named lint scripts |
13
+ | `repo-14`, `repo-11`, `repo-13` | Qualitative. No number anywhere. Evidence discipline: named commands, 100 % pass, no unjustified skips, behavioural test delta |
14
+ | `repo-04` | Neither. Three verification commands. |
15
15
 
16
16
  You cannot average these. 100 % line coverage is unreachable for Kotlin/Compose UI code and for
17
17
  Monkey C memory budgets; a memory ceiling is not a coverage proxy; "no number" is not a weaker
@@ -8,9 +8,9 @@ Six `AGENTS.md` files use the same conceptual sections under three different hea
8
8
 
9
9
  | File | Authority | Invariants |
10
10
  |---|---|---|
11
- | `simt-api`, `simt-social-media` | "Authority and Scope" | "Non-Negotiable Invariants" |
12
- | `simt-garmin`, `simt-social` | "Authority and scope" | "Non-negotiable invariants" |
13
- | `simt-social-api` | "Authority and **ownership**" | "Non-negotiable invariants" |
11
+ | `repo-04`, `repo-13` | "Authority and Scope" | "Non-Negotiable Invariants" |
12
+ | `repo-07`, `repo-14` | "Authority and scope" | "Non-negotiable invariants" |
13
+ | `repo-11` | "Authority and **ownership**" | "Non-negotiable invariants" |
14
14
 
15
15
  At least one repo outside this estate uses a numbered 12-part layout with no equivalent
16
16
  sections at all.
@@ -43,12 +43,12 @@ knows immediately what breaking it costs and who may change it.
43
43
 
44
44
  - Cross-repo reading becomes possible: section N means the same class of thing everywhere.
45
45
  - A future grep for "what are the invariants" returns a comparable list across all 16 repos.
46
- - "Ownership" is kept in the heading because `simt-social-api` earned it by being the only
46
+ - "Ownership" is kept in the heading because `repo-11` earned it by being the only
47
47
  file that enumerates ownership explicitly.
48
48
 
49
49
  ## Rejected
50
50
 
51
- - **Standardise on Title Case** (`simt-api`'s variant). Capitalisation in headings is noise;
51
+ - **Standardise on Title Case** (`repo-04`'s variant). Capitalisation in headings is noise;
52
52
  three repos already use sentence case.
53
53
  - **Normalise a differently-shaped layout immediately.** A mechanical conversion of 12
54
54
  numbered parts would produce a worse document than a mapping.
@@ -6,7 +6,7 @@ Status: **accepted** · 2026-10-05 · affects all repos
6
6
 
7
7
  The estate has two incompatible verdict vocabularies.
8
8
 
9
- `.cursor/rules/test-gate.mdc` — used by all three Social repos — allows one outcome:
9
+ `.cursor/rules/test-gate.mdc` — used by all three one repository — allows one outcome:
10
10
 
11
11
  > Return `BLOCK` when: any test fails, is skipped without pre-existing justification, or is
12
12
  > unrun; the executable diff has no test delta without explicit justification; the coordinator
@@ -23,7 +23,7 @@ to come from the graph registry instead — which is why `paths` lives in
23
23
  - A skill is a directory `<name>/` containing `SKILL.md`.
24
24
  - `name` and `description` are **mandatory** in frontmatter.
25
25
  - `argument-hint` is recommended for any skill invoked by hand, and is optional otherwise —
26
- simt-app's 7 skills omit it legitimately, since they are task-shaped rather than
26
+ repo-05's 7 skills omit it legitimately, since they are task-shaped rather than
27
27
  user-invoked.
28
28
  - Body size and reference-file count are declared in `graph/skills.graph.json`, not in
29
29
  frontmatter, so the registry stays the single source of truth for resolution metadata.
@@ -6,7 +6,7 @@ Status: **accepted** · 2026-10-05 · affects all repos
6
6
 
7
7
  Four repos independently arrived at the same rule, in two ecosystems, with the same rationale.
8
8
 
9
- - `simt-social` / `simt-social-api`: "Run tests and quality checks through repository `npm run
9
+ - `repo-14` / `repo-11`: "Run tests and quality checks through repository `npm run
10
10
  ...` scripts… **Do not invoke local package binaries through `npx` or `npm exec`** unless no
11
11
  repository script supports the required operation."
12
12
  - A Python repo outside this estate, in the same form: "**Do not use `uv run pytest`**; the
@@ -20,8 +20,8 @@ work:
20
20
  5. CI must carry a permanent `windows-latest` job.
21
21
 
22
22
  Against that: **no Windows developer appears anywhere in the repos**, and no repo's own
23
- toolchain is Windows-ready either — `simt-garmin` drives the Monkey C toolchain, and
24
- `simt-app`/`wakt-app`/`app-ui` drive Gradle and Android tooling. So the CLI would have been the
23
+ toolchain is Windows-ready either — `repo-07` drives the Monkey C toolchain, and
24
+ `repo-05`/`repo-03`/`repo-01` drive Gradle and Android tooling. So the CLI would have been the
25
25
  *only* Windows-ready artefact in the estate, serving nobody.
26
26
 
27
27
  The deciding argument is not the cost, it is the shape: obligations 1–3 are correctness
@@ -9,9 +9,9 @@ Affects: `resolve/source.mjs`, `skills install`, `skills show`, `skills brief`
9
9
  single-repo use first class. It fixed resolution, not lookup, and the next defect was found
10
10
  immediately by the user who asked for the previous one.
11
11
 
12
- Someone who cloned **only `simt-social`** has the `simt-social` body of `slice-commit` on disk at
12
+ Someone who cloned **only `repo-14`** has the `repo-14` body of `slice-commit` on disk at
13
13
  `.agents/skills/slice-commit`. They have no workspace. The registry entry
14
- `simt-social/.agents/skills/slice-commit` is satisfied by that file. Both commands refused:
14
+ `repo-14/.agents/skills/slice-commit` is satisfied by that file. Both commands refused:
15
15
 
16
16
  ```
17
17
  $ simt-dev skills install slice-commit
@@ -15,8 +15,8 @@ Affects: `rules/mdc/*.mdc`, `projection/mdc.mjs`, `projection/project.mjs`, `pro
15
15
  The estate carried three always-on `.mdc` rule families across three repos, in eight
16
16
  files, with no two byte-identical.
17
17
 
18
- The worst pair differed by **one byte** (`simt-social/.cursor/rules/intake-questions.mdc`
19
- at 1280 against `simt-social-api`'s at 1281) while hiding three semantically loaded line
18
+ The worst pair differed by **one byte** (`repo-14/.cursor/rules/intake-questions.mdc`
19
+ at 1280 against `repo-11`'s at 1281) while hiding three semantically loaded line
20
20
  changes: a plan-tracker path rewritten to point at the other repo, `migrations` added to the
21
21
  list of decisions worth asking about, and a requirement silently dropped. No size-, hash-,
22
22
  hash-adjacency- or line-count-based duplicate detector could ever have flagged that pair. The
@@ -26,18 +26,18 @@ difference, it is a semantic loss**, and the smaller copy is the one missing a r
26
26
  Reading all eight produced three findings that a variant mechanism cannot represent:
27
27
 
28
28
  1. `test-gate`'s fourth `BLOCK` bullet is **complementary across the pair, not alternative**.
29
- `simt-social` blocks a consumer that requires an API field with no backward-compatibility
30
- or deploy-order evidence; `simt-social-api` blocks a producer that ships without a test
29
+ `repo-14` blocks a consumer that requires an API field with no backward-compatibility
30
+ or deploy-order evidence; `repo-11` blocks a producer that ships without a test
31
31
  asserting the new invariant. Each repo's reviewer was told to check only its own half.
32
32
  2. `preview-postflight`'s second Requirements bullet is likewise complementary, and looks
33
- like a conflict because the two files put different rules in the same slot: `simt-social`
33
+ like a conflict because the two files put different rules in the same slot: `repo-14`
34
34
  says set `SOCIAL_API_BASE_URL` in the Cloudflare Workers Builds preview environment;
35
- `simt-social-api` says credentials live in the operator keychain only, never in source,
35
+ `repo-11` says credentials live in the operator keychain only, never in source,
36
36
  chat, D1 or logs.
37
- 3. Two deletions left no trace. `simt-social-api` dropped `simt-social`'s worked example
37
+ 3. Two deletions left no trace. `repo-11` dropped `repo-14`'s worked example
38
38
  (`Partial pass (e.g. 6/8 pass) is a hard blocker`) — the example is what does the work,
39
39
  and its removal is invisible in a diff review because the rule's normative force looks
40
- unchanged. `simt-social-media` dropped the entire `## Allowed Without Account` section, so
40
+ unchanged. `repo-13` dropped the entire `## Allowed Without Account` section, so
41
41
  it has no documented set of probes that are legal without credentials.
42
42
 
43
43
  A variant mechanism models "these are the same rule, rendered per stack". None of these three
@@ -79,7 +79,7 @@ the rule would either hard-code one repo's paths for everyone or push the decisi
79
79
  prose, which is the drift this mechanism exists to remove.
80
80
 
81
81
  An **empty** value, or an empty default, drops the line it sits on. That is how one canonical
82
- file reaches `simt-social-media` (no plan-tracker note) and `simt-space` (not a Workers repo
82
+ file reaches `repo-13` (no plan-tracker note) and `repo-15` (not a Workers repo
83
83
  at all) without printing a blank bullet. A placeholder with neither a default nor a
84
84
  declaration is a **gate failure**, because a rule shipping a literal `{{key}}` reads as
85
85
  finished and is not.
@@ -88,7 +88,7 @@ finished and is not.
88
88
 
89
89
  `preview-postflight` declares `applies: []` and `optIn: true`. It names specific preview
90
90
  Workers, `AUTH_PROVIDER_POLICY`, `POSTFLIGHT_PASSWORD_UID` and specific production domains.
91
- Selecting it on `cloudflare-workers` would hand it to `simt-space` and `simt-goto` — Workers
91
+ Selecting it on `cloudflare-workers` would hand it to `repo-15` and `repo-08` — Workers
92
92
  repos with no preview Workers and no Social identity — which is the same over-match bug that
93
93
  `rules/stacks/react-web.md` had when it declared `typescript` and `vitest`.
94
94
 
@@ -128,7 +128,7 @@ Silent deletion is the one thing a reviewer cannot audit.
128
128
 
129
129
  `RULE_FILES` named only `AGENTS.md`, `CLAUDE.md` and `CONTRIBUTING.md` for the whole life of
130
130
  the tool. `simt-dev init` therefore reported **`CONFLICTS none detected`** on
131
- `simt-social-api` — the repo holding the worst-drifted content in the estate — because it
131
+ `repo-11` — the repo holding the worst-drifted content in the estate — because it
132
132
  never looked at the `.mdc` files at all.
133
133
 
134
134
  A detector that only knows the filenames it was written for will quietly miss a whole rule
@@ -144,7 +144,7 @@ the same failure, one level down.
144
144
 
145
145
  ### 6. An autonomous-push probe must match every phrasing the estate actually used
146
146
 
147
- The probe matched `committed and pushed`, which is `simt-garmin`'s exact DoD wording. A
147
+ The probe matched `committed and pushed`, which is `repo-07`'s exact DoD wording. A
148
148
  different author wrote `Always commit and pushed`; another would write `commit and push`. The
149
149
  first version matched only the first form and reported a real autonomous-push rule as clean.
150
150
 
@@ -168,7 +168,7 @@ the estate's real text, not against text written to match the probe.**
168
168
 
169
169
  - **A variant mechanism per stack** (one `test-gate.mdc` per repo). This is what produced the
170
170
  drift; modelling it as intended behaviour would make the drift permanent and legitimate.
171
- - **Picking the "best" copy per family and adopting it as canonical.** `simt-social`'s
171
+ - **Picking the "best" copy per family and adopting it as canonical.** `repo-14`'s
172
172
  `test-gate` is the better copy only by accident; it is missing the producer-side `BLOCK`
173
173
  bullet that social-api has. Choosing one per family would have discarded a real rule.
174
174
  - **Deleting the 8 files outright** rather than generating over them. A repo with no
@@ -5,7 +5,7 @@ Affects: `hooks/capability.mjs`, `projection/manifest.mjs`, `commands/init.mjs`,
5
5
 
6
6
  ## Context
7
7
 
8
- The first real adoption wrote a manifest declaring five gates into `simt-social-media`.
8
+ The first real adoption wrote a manifest declaring five gates into `repo-13`.
9
9
  Three of them could not run:
10
10
 
11
11
  | Gate | Kind | Why it could not run |
@@ -25,7 +25,7 @@ user does after adopting simt-dev is discover that the tool makes committing imp
25
25
  the only escape any of them will find is `--no-verify`.
26
26
 
27
27
  That is the exact spiral the dispatcher was built to prevent. Step 8's design note says a gate
28
- that cannot run must be a failure rather than a skip, precisely because `simt-space` removed
28
+ that cannot run must be a failure rather than a skip, precisely because `repo-15` removed
29
29
  tests from `pre-commit` for being slow and the team's answer was `--no-verify`. Failing closed
30
30
  is right; declaring an unrunnable gate is wrong.
31
31