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,28 @@
1
+ #!/usr/bin/env node
2
+ // simt-dev - developer and agent tooling for the SIMT ecosystem.
3
+ //
4
+ // POSIX only (ADR-012). package.json declares os: [darwin, linux], so npm refuses
5
+ // the install elsewhere rather than letting a hook fail obscurely.
6
+
7
+ import { dispatch } from '../src/commands/index.mjs';
8
+ import { EXIT, fail } from '../src/output/index.mjs';
9
+ import { parse } from '../src/argv.mjs';
10
+
11
+ try {
12
+ const argv = process.argv.slice(2);
13
+ const parsed = parse(argv);
14
+ if (!parsed.ok) {
15
+ process.exit(parsed.code);
16
+ }
17
+ const { flags, positional } = parsed.value;
18
+
19
+ // No arguments at all is a usage error, not a silent help dump: an agent that
20
+ // ran the wrong thing should be told so rather than handed 40 lines of prose.
21
+ if (positional.length === 0 && !flags.help && !flags.version) {
22
+ process.exit(fail('no command given', EXIT.USAGE));
23
+ }
24
+
25
+ process.exit((await dispatch(argv)) ?? EXIT.OK);
26
+ } catch (error) {
27
+ process.exit(fail(error?.message ?? String(error), EXIT.FAIL));
28
+ }
@@ -0,0 +1,42 @@
1
+ # ADR-001 — Push requires explicit approval
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ The repos state a commit/push policy. They disagree on whether an agent may push.
8
+
9
+ - A repo outside this estate: "always create a focused Git commit… skip the commit only
10
+ when the user explicitly asks not to commit." Silent on push.
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
+ the commit SHA; **do not push**."
14
+ - `repo-04`, `repo-13`: silent.
15
+
16
+ The Social pair justify it: a push to the production branch triggers Cloudflare Workers Builds,
17
+ so "an approved push is therefore a production deployment action, not only source publication."
18
+ `repo-07` has no such coupling, and its rule asks for an autonomous push.
19
+
20
+ ## Ruling
21
+
22
+ Commit locally, report the SHA, **push only on explicit user approval**.
23
+
24
+ When a repo's push triggers a deployment, a migration, or any remote mutation, say so before
25
+ asking for approval — do not treat approval for the push as approval for the deploy.
26
+
27
+ `repo-07` DoD #8 changes to "committed with a conventional message; pushed on approval."
28
+ This is the single outlier, and the 4:1 majority is also the safe direction.
29
+
30
+ ## Consequences
31
+
32
+ - An agent that finishes a task ends at a reported SHA. Pushes become a separate, explicit step.
33
+ - `simt-dev init` and `upgrade` propose changes and never push, including for simt-dev itself.
34
+ - Repos whose CI deploys on push must state that consequence in their own AGENTS.md, which is
35
+ where the Social pair's rule already lives.
36
+
37
+ ## Rejected
38
+
39
+ - **Autonomous push (garmin's current rule).** Removes the only checkpoint between "the agent
40
+ thinks it is done" and "production changed".
41
+ - **Push on completion, as a commit-always contributor loop implies.** Same objection; its
42
+ PR step does not require an agent to open the PR unattended.
@@ -0,0 +1,45 @@
1
+ # ADR-002 — Blast radius bounds refactoring; a third copy is a defect
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ Two repos state opposite philosophies, and both are reasonable in isolation.
8
+
9
+ - `repo-14` / `repo-11`: "When a second real use or a near-duplicate already
10
+ exists, refactor the existing code to extract the shared part… A third copy of the same
11
+ logic is a defect, and so is an abstraction invented for a single caller."
12
+ - A repo outside this estate: "Match existing style, naming, and test layout. **Do not
13
+ refactor neighboring code unless the requested change requires it.** Do not add speculative
14
+ flexibility, configuration, or abstractions."
15
+
16
+ Neither can be an org rule as written. The Social rule mandates proactive refactoring;
17
+ the other forbids it.
18
+
19
+ ## Ruling
20
+
21
+ Both survive, split by scope:
22
+
23
+ - **Outside the current change's blast radius** — do not refactor. Unrelated code is not
24
+ collateral.
25
+ - **Inside the blast radius** — a second real use extracts, and the extraction is *finished*:
26
+ no orphaned imports, exports, styles, messages, files, feature flags or compatibility
27
+ aliases remain anywhere in the affected dependency graph.
28
+ - **A third copy of the same logic is a defect.** So is an abstraction invented for a single
29
+ caller.
30
+
31
+ ## Consequences
32
+
33
+ - "Do not refactor neighbours" survives verbatim as a reviewer's objection to drive-by changes.
34
+ - "A third copy is a defect" survives verbatim as a reviewer's objection to copy-paste.
35
+ - Refactor completion becomes a checkable state, not an intention: the reviewer greps for
36
+ orphans rather than trusting the claim.
37
+ - The "no speculative flexibility" half is restated as the single-caller half of this
38
+ ruling rather than as a blanket ban.
39
+
40
+ ## Rejected
41
+
42
+ - **Social's rule verbatim.** Sanctions unrelated refactors, which is how a 10-line fix turns
43
+ into a 400-line diff nobody can review.
44
+ - **The opposite rule verbatim.** Sanctions the third copy, which is how a codebase grows four
45
+ subtly different implementations of the same validation.
@@ -0,0 +1,46 @@
1
+ # ADR-003 — Focused tests are the default; a full suite needs a named trigger
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ - `repo-14` / `repo-11`: "Focused tests are the default gate, and full suites are
8
+ the exception… **absent a named trigger, running a full suite is a defect, not diligence.**"
9
+ - A repo outside this estate: `fail_under = 100` plus a full-suite script as the pre-push
10
+ default, and a contributor loop that says "run the full gate locally (lint + tests +
11
+ coverage)."
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
+
15
+ The Social pair make a full suite a sin. media presents it as unremarkable. The hard-gate
16
+ repo makes it mandatory. These cannot all be org rules as stated.
17
+
18
+ ## Ruling
19
+
20
+ Focused tests are the default gate. Running a full suite is legitimate **only** against a
21
+ named trigger:
22
+
23
+ 1. Phase exit.
24
+ 2. Release gate.
25
+ 3. Behaviour that crosses a system boundary.
26
+ 4. A repo-declared numeric gate (see ADR-006 for where that number lives).
27
+ 5. Explicit user or caller instruction.
28
+ 6. Pre-push on a protected branch, in a repo that declares this trigger in `simt-dev.json`.
29
+
30
+ Re-running a full suite as a progress meter is a defect. Repos outside this estate already
31
+ say exactly this ("do not run the full gate repeatedly as a progress meter"); the principle is
32
+ adopted as canonical.
33
+
34
+ ## Consequences
35
+
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; one repository activate 1, 2 and 3.
38
+ - A reviewer can ask "which trigger?" and get a number, not an opinion.
39
+ - media gains an explicit policy instead of an implicit one that contradicts its siblings.
40
+
41
+ ## Rejected
42
+
43
+ - **"A full suite is a defect."** Wrong for a release gate and wrong for a repo whose coverage
44
+ floor is a hard number; it makes the rule get ignored rather than followed.
45
+ - **Full suite by default.** Re-pays the whole cost on every iteration; the Social pair are
46
+ right that an inflated brief is a defect in the brief, not thoroughness.
@@ -0,0 +1,45 @@
1
+ # ADR-004 — The hook owns format and lint for staged files
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ - `repo-11`: "lint and format are enforced by the pre-commit hook — **do not run them
8
+ manually.**"
9
+ - `repo-14`: "the local pre-push hook republishes opportunistically when a token happens to
10
+ be present." Never says the hook is the gate; instructs agents to run static checks directly.
11
+ - A repo outside this estate: tells agents to run its linter and `git diff --check` by hand,
12
+ and its contributor guide repeats it.
13
+ - `repo-04`, and 11 repos with no hooks at all: silent.
14
+
15
+ The audit also found the estate's hook reality: 4 incompatible conventions, and
16
+ `repo-05/hooks/pre-push` is **0 bytes** while the real git-lfs pre-push sits unused in
17
+ `scripts/hooks/`.
18
+
19
+ ## Ruling
20
+
21
+ The pre-commit hook owns format and lint **for staged files**. Do not re-run what the hook
22
+ just ran on the same files.
23
+
24
+ Manual runs are correct when:
25
+
26
+ 1. The hook is not installed in this checkout, or
27
+ 2. A check failed and you are diagnosing it, or
28
+ 3. The check is not hook-covered (typecheck, migration verification, contract generation).
29
+
30
+ A repo with no hook installed still runs its checks manually. Silence is not permission to
31
+ skip.
32
+
33
+ ## Consequences
34
+
35
+ - The shared hook dispatcher from plan 0001 lands in every repo that has one, which also
36
+ delivers the dead `repo-05/hooks/pre-push` fix.
37
+ - `simt-dev doctor` reports hook installation state, so "the hook will cover it" is a
38
+ verifiable claim rather than an assumption.
39
+ - The 11 hook-less repos get a pre-commit on adoption, which ends the silent case entirely.
40
+
41
+ ## Rejected
42
+
43
+ - **"Never run lint manually."** False whenever the hook is absent, which is most of the
44
+ estate today.
45
+ - **"Always run lint manually."** Re-runs what a hook already verified, on every iteration.
@@ -0,0 +1,42 @@
1
+ # ADR-005 — File length is two tiers: 400 review trigger, 1000 hard ceiling
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ - `repo-14` / `repo-11`: "**Split any file once it exceeds 1000 lines**; extract
8
+ along the nearest cohesive boundary instead of growing the file further."
9
+ - `repo-07`: "**File length: 400 lines is a smell threshold, not a hard gate.**" Generated
10
+ `.mc` files are exempt, with a named exception for a 408-line template.
11
+ - Several repos: no file-length rule stated at all.
12
+
13
+ The two numbers are not in conflict — they measure different things. 400 is where a human
14
+ should start asking questions; 1000 is where the file must already have been split.
15
+
16
+ ## Ruling
17
+
18
+ Two tiers, both advisory in wording but checkable in `simt-dev check`:
19
+
20
+ - **400 lines — review trigger.** Crossing it requires a stated reason to keep the file whole.
21
+ - **1000 lines — hard ceiling.** `simt-dev check` fails. Extract along the nearest cohesive
22
+ boundary.
23
+ - **Generated files are exempt**, declared per repo in `simt-dev.json`. The hook must name the
24
+ generator.
25
+
26
+ Per-repo overrides are permitted via `limits.fileLines` in `simt-dev.json`.
27
+
28
+ ## Consequences
29
+
30
+ - one repository' hard 1000 gate and garmin's soft 400 both survive unchanged in force.
31
+ - The generated-file exemption that garmin had to state in prose becomes a declared property,
32
+ so the hook can honour it without hardcoding `.mc`.
33
+ - `repo-14`'s pre-commit file-size check (currently inlined as 1000 lines of shell, and
34
+ duplicating `scripts/check-file-sizes.ts`) becomes one implementation in the shared
35
+ dispatcher.
36
+
37
+ ## Rejected
38
+
39
+ - **One number org-wide.** Either it is too tight for legitimately long declarative files or
40
+ too loose to prompt a human at 400.
41
+ - **No rule.** one repository' pre-commit check exists precisely because a rule was missing,
42
+ and it is now implemented twice.
@@ -0,0 +1,59 @@
1
+ # ADR-006 — Evidence discipline is central; the numeric bar is per-repo
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ The coverage bar is the one concept that is mutually incompatible *in kind* across the estate:
8
+
9
+ | Repo | Bar |
10
+ |---|---|
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
+ | `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
+
16
+ You cannot average these. 100 % line coverage is unreachable for Kotlin/Compose UI code and for
17
+ Monkey C memory budgets; a memory ceiling is not a coverage proxy; "no number" is not a weaker
18
+ version of 100 %, it is a different instrument.
19
+
20
+ ## Ruling
21
+
22
+ **The central rule mandates evidence discipline. The numeric threshold is a declared,
23
+ per-repo constant.**
24
+
25
+ Central, mandatory, portable — for every repo regardless of stack:
26
+
27
+ 1. Name the exact commands and the exact test files.
28
+ 2. Those commands must exit 0 with **all** selected tests passing. Partial pass is a hard
29
+ blocker; "6/8 pass" is the canonical worked example of a blocked state.
30
+ 3. No test is skipped without a pre-existing written justification.
31
+ 4. Every executable change carries a test delta: new or extended test for new behaviour, a
32
+ regression test reproducing the failure mode for a bugfix, or a stated reason existing tests
33
+ fully prove the invariant.
34
+ 5. Never claim a test you did not run. Never cite a partial suite as evidence.
35
+ 6. Approval by budget never converts a known failure into an approval.
36
+
37
+ Per-repo, declared in `simt-dev.json` under `limits`: the numeric gate, if any — coverage
38
+ percentage, memory budget, size ceiling. The central rule specifies *how to declare it*, never
39
+ the value.
40
+
41
+ ## Consequences
42
+
43
+ - A repo that declares `coverage: 100` keeps it and its "untested paths are typed holes"
44
+ framing intact; the ruling constrains only what a new repo declares.
45
+ - garmin declares its memory budgets in the same slot, and its "layer-conditional 5a–5m matrix"
46
+ becomes a declared gate list rather than 12 prose sentences.
47
+ - The three social repos declare no number and keep their evidence discipline verbatim — which
48
+ is now shared rather than independently re-invented in each.
49
+ - A new repo inherits a real policy from `simt-dev init` with no configuration, and can opt into a
50
+ number later without changing the rule.
51
+
52
+ ## Rejected
53
+
54
+ - **Hard 100 % coverage org-wide.** Unreachable in Kotlin/Compose and meaningless for Monkey C;
55
+ would push repos to delete the rule rather than meet it.
56
+ - **No number anywhere.** Leaves a genuinely strong gate unenforced org-wide and invites
57
+ every new repo to skip the question.
58
+ - **One number for coverage and a separate slot for memory.** Two slots invite a repo to declare
59
+ only the one it likes.
@@ -0,0 +1,54 @@
1
+ # ADR-007 — One canonical section skeleton
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ Six `AGENTS.md` files use the same conceptual sections under three different headings:
8
+
9
+ | File | Authority | Invariants |
10
+ |---|---|---|
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
+
15
+ At least one repo outside this estate uses a numbered 12-part layout with no equivalent
16
+ sections at all.
17
+
18
+ The deeper difference is in what "non-negotiable" means. Garmin's are **platform physics**
19
+ ("breaking any of these produces a product that is wrong, crashes, or cannot be shipped"); the
20
+ Social pair's are **product and privacy policy**; api/media's are **data and schema
21
+ invariants**. Those are three different kinds of claim wearing one heading, which is why the
22
+ naming drifted — nobody could tell whether the sections were meant to align.
23
+
24
+ ## Ruling
25
+
26
+ One canonical skeleton, sentence case:
27
+
28
+ ```
29
+ ## Authority and ownership
30
+ ## Non-negotiable invariants
31
+ ## Engineering conventions
32
+ ## Workflow and validation
33
+ ```
34
+
35
+ Repos may add sections after these; they may not rename them. A repo that arrives with its
36
+ own numbered layout keeps it during adoption and maps each part onto a canonical section in
37
+ `simt-dev.json`, so both structures remain navigable while it migrates.
38
+
39
+ Each invariant states **which kind of claim it is** — platform, policy, or data — so a reader
40
+ knows immediately what breaking it costs and who may change it.
41
+
42
+ ## Consequences
43
+
44
+ - Cross-repo reading becomes possible: section N means the same class of thing everywhere.
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 `repo-11` earned it by being the only
47
+ file that enumerates ownership explicitly.
48
+
49
+ ## Rejected
50
+
51
+ - **Standardise on Title Case** (`repo-04`'s variant). Capitalisation in headings is noise;
52
+ three repos already use sentence case.
53
+ - **Normalise a differently-shaped layout immediately.** A mechanical conversion of 12
54
+ numbered parts would produce a worse document than a mapping.
@@ -0,0 +1,59 @@
1
+ # ADR-008 — One review verdict vocabulary: three values
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ The estate has two incompatible verdict vocabularies.
8
+
9
+ `.cursor/rules/test-gate.mdc` — used by all three one repository — allows one outcome:
10
+
11
+ > Return `BLOCK` when: any test fails, is skipped without pre-existing justification, or is
12
+ > unrun; the executable diff has no test delta without explicit justification; the coordinator
13
+ > cites partial suite results or defers failing tests.
14
+
15
+ `principal-milestone-reviewer.agent.md` — the final pre-commit gate — uses three:
16
+
17
+ > `APPROVE` / `APPROVE WITH RESIDUAL RISK` / `BLOCK`
18
+
19
+ With only two values, a reviewer who finds no blocker but did not finish has no honest answer
20
+ and is pushed toward `APPROVE` by omission or toward `BLOCK` by exaggeration. With three, the
21
+ budget mechanism works: "Use one focused pass, normally no more than 5 minutes or 8 targeted
22
+ tool calls… If the budget is reached without a concrete blocker, stop and return `APPROVE WITH
23
+ RESIDUAL RISK`. List what was not reviewed."
24
+
25
+ The agent also re-embeds the `.mdc` text verbatim as its checklist item 1, so the vocabulary
26
+ mismatch propagates from the rule into the gate.
27
+
28
+ ## Ruling
29
+
30
+ Adopt the three-value vocabulary everywhere:
31
+
32
+ | Verdict | Meaning |
33
+ |---|---|
34
+ | `BLOCK` | A concrete defect, missing mandatory gate, partial test pass, or missing test delta. Always paired with a file:line or command reference. |
35
+ | `APPROVE WITH RESIDUAL RISK` | No blocker found within the review budget. **Must** list what was not reviewed. |
36
+ | `APPROVE` | Fully reviewed, no blocker. |
37
+
38
+ `APPROVE WITH RESIDUAL RISK` never converts a known failure into an approval — that constraint
39
+ travels with the verdict, verbatim from the review agent.
40
+
41
+ The `.mdc` files are updated to the three-value vocabulary. `BLOCK` remains the only value that
42
+ stops work; the other two do not weaken the block conditions, which are stated identically in
43
+ all three rules.
44
+
45
+ ## Consequences
46
+
47
+ - A reviewer who runs out of budget has a correct answer, so the budget stops being a reason to
48
+ over-search.
49
+ - Rule text and agent text stop diverging, because they now share a vocabulary and the agent no
50
+ longer has to paraphrase the rule.
51
+ - Output format is uniform across the 15 agent files: severity-ordered findings, clickable
52
+ file:line references, a verdict, and — when not fully reviewed — the unreviewed list.
53
+
54
+ ## Rejected
55
+
56
+ - **`BLOCK` only.** Loses the honest "I did not finish" answer and makes the strict review
57
+ budget unusable as written.
58
+ - **Four values** (adding `NEEDS WORK`). Three already distinguishes blocked from
59
+ budget-limited; a fourth would be chosen on judgement and collapse back into two.
@@ -0,0 +1,48 @@
1
+ # ADR-009 — Skills are `<name>/SKILL.md` with mandatory frontmatter
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ All 37 skill entries in the estate use `<name>/SKILL.md`. A wider audit that included repos
8
+ now out of scope found exactly one entry that did not: a flat 7 266-byte file that also omitted
9
+ the `name` frontmatter key. The layout ruling exists because that defect class is real, not
10
+ because this estate still has it.
11
+
12
+ Frontmatter field usage across the wider audit's 46 entries: `name` 45, `description` 46,
13
+ `argument-hint` 14, `disable-model-invocation` 2, `references` 1, `compatibility` 1, and
14
+ **`globs` zero**. No skill in any audited repo scopes itself by file pattern.
15
+
16
+ That last point matters for discovery. A skill that could declare `globs: "migrations/**"`
17
+ would let the resolver select it from the diff alone. Since none do, path-based resolution has
18
+ to come from the graph registry instead — which is why `paths` lives in
19
+ `graph/skills.graph.json` (plan 0002 §3.2) rather than in frontmatter.
20
+
21
+ ## Ruling
22
+
23
+ - A skill is a directory `<name>/` containing `SKILL.md`.
24
+ - `name` and `description` are **mandatory** in frontmatter.
25
+ - `argument-hint` is recommended for any skill invoked by hand, and is optional otherwise —
26
+ repo-05's 7 skills omit it legitimately, since they are task-shaped rather than
27
+ user-invoked.
28
+ - Body size and reference-file count are declared in `graph/skills.graph.json`, not in
29
+ frontmatter, so the registry stays the single source of truth for resolution metadata.
30
+
31
+ The one flat file found in the wider audit was wrapped into `coverage-hunt/SKILL.md` with
32
+ its `name` added. This estate has no such entry left to migrate.
33
+
34
+ ## Consequences
35
+
36
+ - Every skill becomes addressable by one stable name across all 16 repos, which is a
37
+ precondition for `simt-dev skills find/show/install` and for `variant-of` edges.
38
+ - The registry in `graph/skills.graph.json` becomes the one place resolution metadata lives,
39
+ instead of metadata split across frontmatter, prose and directory size.
40
+ - `simt-dev skills eval` can key on skill names, because every skill has one.
41
+
42
+ ## Rejected
43
+
44
+ - **Require `globs` in frontmatter.** Attractive, but it would put resolution metadata in two
45
+ places and drift from the graph — the exact failure mode that produced the 8 divergent
46
+ `.mdc` files. Recorded as considered and rejected.
47
+ - **Keep flat `.md` as an accepted form.** Two layouts means two resolver paths and two sets of
48
+ conventions to police.
@@ -0,0 +1,56 @@
1
+ # ADR-010 — Invoke tools through the repo's own runner, never a package runner
2
+
3
+ Status: **accepted** · 2026-10-05 · affects all repos
4
+
5
+ ## Context
6
+
7
+ Four repos independently arrived at the same rule, in two ecosystems, with the same rationale.
8
+
9
+ - `repo-14` / `repo-11`: "Run tests and quality checks through repository `npm run
10
+ ...` scripts… **Do not invoke local package binaries through `npx` or `npm exec`** unless no
11
+ repository script supports the required operation."
12
+ - A Python repo outside this estate, in the same form: "**Do not use `uv run pytest`**; the
13
+ console entrypoint can miss the `uv` import path and fail to import dependencies." Its
14
+ contributor guide states the same rule with a stronger failure description: it "can
15
+ **silently** run against the wrong environment."
16
+
17
+ The failure mode is identical: a package runner resolves a binary outside the project's
18
+ configured environment, so the tool runs, the import path is wrong, and the result is either an
19
+ obvious import error or — worse — a pass against the wrong interpreter.
20
+
21
+ Note the severity disagreement on that last point: "fail to import" versus "silently run
22
+ against the wrong environment." The second is far worse and is treated as canonical below.
23
+
24
+ ## Ruling
25
+
26
+ Invoke tools through the repository's own declared runner, in every ecosystem:
27
+
28
+ - Node: `npm run <script>`. Never `npx` or `npm exec` for a binary that is a declared
29
+ dependency.
30
+ - Python: the module form, `uv run -m pytest`, or the repo's own wrapper. Never the bare
31
+ console entrypoint.
32
+ - Gradle: `./gradlew`, never a system `gradle`.
33
+ - Any other ecosystem: the repo's declared entrypoint, never a bare global binary.
34
+
35
+ **Read the actual runner manifest before running anything.** A command that does not exist in
36
+ `package.json` is not a command. This is stated because it is the other half of the failure:
37
+ guessing a script name is how an agent concludes a check "passed" when it never ran.
38
+
39
+ Exception: a tool that is genuinely not a project dependency (a one-off inspector, a global
40
+ formatter) may be invoked directly, provided its version is pinned.
41
+
42
+ ## Consequences
43
+
44
+ - The estates' two ecosystems converge on one rule, so an agent moving between a Python repo
45
+ and a TypeScript repo does not have to learn the rule twice.
46
+ - The stronger failure description is canonical: silently running against the wrong environment
47
+ is worse than failing, and the rule exists to prevent it.
48
+ - Repos with no declared scripts get them from the tooling baseline (plan 0001 §3.1), so this
49
+ ruling is always actionable.
50
+
51
+ ## Rejected
52
+
53
+ - **Adopt only the npm half.** Leaves the identical failure unguarded in Python, Gradle and
54
+ every future ecosystem.
55
+ - **Permit `npx` for convenience.** `npx` will fetch a package that is not the project's
56
+ version, which reintroduces exactly the environment drift the rule prevents.
@@ -0,0 +1,52 @@
1
+ # ADR-011 — Windows is supported from v1
2
+
3
+ Status: **superseded by [ADR-012](ADR-012-drop-windows-support.md)** · 2026-10-05
4
+ Affects: the `simt-dev` CLI
5
+
6
+ > Superseded the same day. The cost table below is retained because it is what ADR-012's
7
+ > reasoning turns on: three of the five obligations are permanent tax on the hook dispatcher
8
+ > and the projection injector, not one-off work. See ADR-012 for the weighing.
9
+
10
+ ## Context
11
+
12
+ No Windows developer currently appears in the estate, and the cheap alternative was
13
+ `"os": ["darwin", "linux"]` in `package.json`, which makes npm refuse to install on Windows
14
+ with a clear message instead of failing obscurely inside a git hook.
15
+
16
+ That option was put to you and declined in favour of full v1 support.
17
+
18
+ The cost is real and is recorded here so it is paid deliberately rather than discovered:
19
+
20
+ | Obligation | Why |
21
+ |---|---|
22
+ | Hook scripts must not assume POSIX | `core.hooksPath` hooks run under Git for Windows' bundled sh, which does exist — but the dispatcher cannot assume a POSIX `#!/bin/sh` shebang alone is sufficient. Hook entrypoints are `.cmd`-aware or invoked through `node` explicitly. |
23
+ | The projection injector must normalise line endings | The audit found **10 of 16 repos have no `.editorconfig`**, so a generated region written with the host's EOL would produce a whole-file diff on Windows checkouts. The injector writes the canonical EOL from `.gitattributes` (`* text=auto eol=lf`), defaulting to LF. |
24
+ | Path handling must not assume `/` | Resolver globs, `paths` matching and every emitted file reference must normalise separators. |
25
+ | npm bin shim | The published package must rely on npm's generated shim rather than a hand-written launcher. |
26
+ | CI must actually run it | A macOS-only CI run cannot verify a Windows claim. GitHub Actions gains a `windows-latest` job for the CLI itself — not for the repos it serves, which stay macOS/Linux as their own tooling dictates. |
27
+
28
+ ## Ruling
29
+
30
+ Windows is a supported v1 platform for the `simt-dev` CLI itself. `package.json` declares no
31
+ `os` restriction, and CI verifies on `windows-latest`.
32
+
33
+ Scope is deliberately limited: this covers the CLI running *on* Windows. It does not imply that
34
+ any repo's own toolchain is Windows-ready — Python packaging, Monkey C, and Android Gradle
35
+ builds are governed by their own repos.
36
+
37
+ ## Consequences
38
+
39
+ - The shared hook dispatcher ships with a Windows-safe entrypoint from day one. Retrofitting
40
+ this after 16 repos have installed the dispatcher is far more expensive than building it now.
41
+ - The EOL normalisation in the projection injector becomes a correctness requirement rather
42
+ than a nicety — which is worth doing regardless, given 10 repos lack `.editorconfig`.
43
+ - `windows-latest` CI costs minutes per run and buys an install story that does not break on the
44
+ first non-Mac contributor.
45
+
46
+ ## Rejected
47
+
48
+ - **`os: ["darwin", "linux"]`.** Cheapest, and a defensible engineering call on estate
49
+ evidence — declined because the hook dispatcher's Windows-safety is substantially harder to
50
+ retrofit across 16 installed repos than to build.
51
+ - **Windows via WSL only.** Avoids the native path work but leaves a Windows contributor
52
+ needing a Linux environment, which is the failure this ruling exists to prevent.
@@ -0,0 +1,59 @@
1
+ # ADR-012 — Windows support is dropped; POSIX only
2
+
3
+ Status: **accepted** · 2026-10-05 · supersedes [ADR-011](ADR-011-windows-support.md)
4
+ Affects: the `simt-dev` CLI
5
+
6
+ ## Context
7
+
8
+ ADR-011 committed to supporting Windows in the CLI from v1, against the recommendation to
9
+ declare `"os": ["darwin", "linux"]` and let npm refuse the install elsewhere. The reasoning
10
+ for that decision was sound but the weighing was wrong.
11
+
12
+ ADR-011's own cost table listed five obligations, three of which are permanent tax on
13
+ every future change to the hook dispatcher and the projection injector rather than one-off
14
+ work:
15
+
16
+ 1. Hook entrypoints must be `.cmd`-aware instead of relying on a POSIX shebang.
17
+ 2. The projection injector must normalise line endings on every write.
18
+ 3. Glob matching and every emitted path reference must normalise separators.
19
+ 4. npm's generated bin shim must be relied on rather than a hand-written launcher.
20
+ 5. CI must carry a permanent `windows-latest` job.
21
+
22
+ Against that: **no Windows developer appears anywhere in the repos**, and no repo's own
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
+ *only* Windows-ready artefact in the estate, serving nobody.
26
+
27
+ The deciding argument is not the cost, it is the shape: obligations 1–3 are correctness
28
+ constraints that every contributor must keep satisfying forever. Adopting them to serve a
29
+ population of zero is how a codebase accumulates permanent complexity nobody can evaluate.
30
+
31
+ ## Ruling
32
+
33
+ **POSIX only: macOS and Linux.** `package.json` declares `"os": ["darwin", "linux"]`, so npm
34
+ refuses to install on Windows with a clear message instead of failing obscurely inside a git
35
+ hook. CI verifies on `macos-latest` and `ubuntu-latest` only.
36
+
37
+ The code obligations of ADR-011 are withdrawn, with one exception that stands on its own
38
+ merits rather than on Windows: **the projection injector still normalises line endings to the
39
+ canonical EOL.** 10 of 16 repos have no `.editorconfig`, so a generated region written with
40
+ whatever the host produced would cause whole-file diffs on checkouts whose
41
+ `core.autocrlf` differs. That is a cross-platform problem among POSIX hosts and has nothing
42
+ to do with Windows.
43
+
44
+ ## Consequences
45
+
46
+ - `bin/simt-dev.mjs` keeps its shebang as a plain POSIX entrypoint; no `.cmd` shim handling.
47
+ - Glob matching and emitted paths assume `/`. The existing forward-slash normalisation in
48
+ `fingerprint.mjs` is retained as cheap insurance, not as a Windows requirement.
49
+ - The permanent `windows-latest` CI job is not added.
50
+ - Revisit only when a Windows developer joins the estate — at which point the deciding
51
+ argument is gone and the cost table in ADR-011 becomes the deciding one.
52
+
53
+ ## Rejected
54
+
55
+ - **Keeping Windows v1 (ADR-011).** Permanent correctness constraints in the dispatcher and
56
+ injector, serving zero users, in the only part of the estate that would have been
57
+ Windows-ready.
58
+ - **Deferring rather than dropping.** A deferred platform is an unbounded promise; the
59
+ obligations would still shape the code.