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,43 @@
1
+ {
2
+ "name": "simt-dev",
3
+ "version": "0.2.0",
4
+ "description": "Shared agent rules, skills and git hooks for a repository: one command adopts a repo, and every gate it declares is probed before it is written.",
5
+ "license": "Apache-2.0",
6
+ "author": "Said Elimam",
7
+ "private": false,
8
+ "type": "module",
9
+ "engines": {
10
+ "node": ">=22.20.0"
11
+ },
12
+ "os": [
13
+ "darwin",
14
+ "linux"
15
+ ],
16
+ "bin": {
17
+ "simt": "bin/simt-dev.mjs"
18
+ },
19
+ "files": [
20
+ "bin",
21
+ "src",
22
+ "graph",
23
+ "rules",
24
+ "docs/decisions",
25
+ "CHANGELOG.md"
26
+ ],
27
+ "keywords": [
28
+ "agent",
29
+ "agents",
30
+ "ai",
31
+ "codex",
32
+ "cursor",
33
+ "git-hooks",
34
+ "lint",
35
+ "llm",
36
+ "rules",
37
+ "skills"
38
+ ],
39
+ "scripts": {
40
+ "test": "node --test test/*.test.mjs",
41
+ "lint": "node bin/simt-dev.mjs doctor"
42
+ }
43
+ }
@@ -0,0 +1,76 @@
1
+ ---
2
+ simt-id: core
3
+ simt-title: Shared rules
4
+ simt-applies: always
5
+ ---
6
+
7
+ # Shared rules
8
+
9
+ Where a rule cites a decision, run `simt-dev rules why ADR-NNN` to read it,
10
+ including whether it is still in force.
11
+
12
+ These rules are stack-agnostic. Whatever is specific to your stack, your product or your
13
+ commands belongs in this repository, not here.
14
+
15
+ ## Truth
16
+
17
+ - Never claim a test you did not run, a check you did not execute, or a deploy you did not
18
+ perform.
19
+ - Read the real runner manifest before running anything. A command absent from it is not a
20
+ command. (Which file that is depends on the stack: `package.json` scripts, Gradle tasks,
21
+ `pyproject.toml` entry points.)
22
+ - Report what you left alone: unrelated dirty files, skipped checks, unreviewed scope.
23
+
24
+ ## Git
25
+
26
+ - Commit locally, report the SHA. **Push only on explicit approval.** (ADR-001)
27
+ - Before asking for push approval, state whether the push triggers a deployment, a migration
28
+ or any remote mutation.
29
+ - Never use `--no-verify`, amend, rebase, reset or rewrite history unless explicitly asked.
30
+ - Never commit failing, partial, secret-bearing or unrelated work.
31
+
32
+ ## Refactoring
33
+
34
+ - Outside the current change's blast radius, do not refactor. (ADR-002)
35
+ - Inside it, a second real use extracts, and the extraction is finished: no orphaned imports,
36
+ exports, styles, messages or files remain.
37
+ - A third copy of the same logic is a defect. So is an abstraction invented for one caller.
38
+
39
+ ## Validation
40
+
41
+ - Focused tests are the default gate. A full suite runs only against a named trigger: phase
42
+ exit, release gate, cross-system behaviour, a repo-declared numeric gate, explicit
43
+ instruction, or pre-push on a declared protected branch. (ADR-003)
44
+ - Name the exact commands and test files. Partial pass is a blocker; `6/8 pass` is the
45
+ canonical example of a blocked state. Never justify a skip without a pre-existing written
46
+ reason. (ADR-006)
47
+ - Evidence discipline is mandatory everywhere. A **numeric** bar is declared per repo in
48
+ `simt-dev.json`, never assumed centrally. (ADR-006)
49
+ - The pre-commit hook owns format and lint for staged files; do not re-run what it just ran.
50
+ Manual runs are correct when the hook is absent, when diagnosing a failure, or for a check
51
+ the hook does not cover. (ADR-004)
52
+ - Declare a gate only if this repository can run it — a script that exists, a tool that is
53
+ installed, a command you name. A gate that cannot run blocks every commit until someone
54
+ reaches for `--no-verify`. (ADR-017)
55
+ - Invoke tools through the repository's own runner — `npm run`, `uv run -m`, `./gradlew` —
56
+ never a package runner like `npx` or a bare console entrypoint. (ADR-010)
57
+
58
+ ## Code and review
59
+
60
+ - No type-system escapes, no unawaited async work, no debug printing in application code.
61
+ - 400 lines is a review trigger; 1000 lines is a hard ceiling. Generated files are exempt
62
+ when the hook names the generator. (ADR-005)
63
+ - Never weaken CSP, CORS, auth, audit, cache or validation controls to silence a test, warning
64
+ or alert.
65
+ - Review verdicts are exactly three: `BLOCK`, `APPROVE WITH RESIDUAL RISK` (must list what was
66
+ not reviewed), `APPROVE`. (ADR-008)
67
+ - Accessibility, correctness, privacy and security are hard gates, not subjective tradeoffs.
68
+ - Never direct two agents to edit the same files concurrently. Select the minimum viable team.
69
+ - Every agent works to a stated budget and stops at a concrete blocker rather than drifting.
70
+ Approval by budget never converts a known failure into an approval.
71
+
72
+ ## Scope of these rules
73
+
74
+ Product policy, stack-specific rule bodies, repo commands and paths stay in the repo. A rule
75
+ here states only what holds everywhere; the moment one repository needs an exception, it is that
76
+ repository's rule, not a widening of this one.
@@ -0,0 +1,50 @@
1
+ ---
2
+ simt-id: intake-questions
3
+ simt-target: .cursor/rules/intake-questions.mdc
4
+ description: Ask only unresolved business/technical decisions before work
5
+ alwaysApply: true
6
+ simt-applies: always
7
+ simt-substitutions:
8
+ - key: plansGlob
9
+ default: docs/plans/*
10
+ describe: glob for this repo's active plan tracker tables
11
+ - key: askTool
12
+ default: Ask the user, offering choices with the recommended one first
13
+ describe: how this repo asks a question; the default names no harness, because one body is written for every selected surface
14
+ ---
15
+
16
+ # Intake Questions
17
+
18
+ When starting, resuming, or scoping a feature slice or plan task, do not jump into code
19
+ without resolving open material decisions.
20
+
21
+ ## Agent Defaults (Do Not Ask)
22
+
23
+ Apply documented defaults without questions for:
24
+
25
+ - Operational/procedural choices (tracker updates, commit vs push, validation depth,
26
+ artifact shape).
27
+ - Slice sequencing and repository ownership when already defined in the active plan
28
+ tracker table (`{{plansGlob}}`).
29
+ - Standard engineering conventions.
30
+
31
+ ## When To Ask (1-5 Questions Max)
32
+
33
+ Ask only when a functionality, business, privacy, security, or technical decision is not
34
+ settled in authority docs, and the answer materially changes behavior, scope, contracts,
35
+ migrations, or risk.
36
+
37
+ Five is a ceiling, not a quota. Ask fewer when fewer decisions are genuinely open; never pad
38
+ the list to reach it, and never split one decision into several questions to fit under it.
39
+
40
+ - {{askTool}}.
41
+ - If that is not available, present numbered choices with `(recommended)` on the first option.
42
+ - Do not ask operational or procedural choices; apply the best documented option.
43
+
44
+ ## Required First Turn
45
+
46
+ 1. State the smallest independently valuable slice, the owning repo, the active plan
47
+ tracker task ID (from `{{plansGlob}}`), and the acceptance checks.
48
+ 2. Either ask the unresolved material decision questions, or state that the authority docs
49
+ leave no material open decision and proceed to implementation.
50
+ 3. Proceed without waiting when no material decision remains.
@@ -0,0 +1,61 @@
1
+ ---
2
+ simt-id: preview-postflight
3
+ simt-target: .cursor/rules/preview-postflight.mdc
4
+ description: Authenticated remote postflight uses dedicated preview Workers
5
+ alwaysApply: true
6
+ # Opt-in, not stack-detected. Detection cannot tell a Workers repo that deploys
7
+ # preview Workers from one that does not, so a stack tag would hand this rule to the
8
+ # latter. The repo declares it instead. See ADR-016 section 3.
9
+ simt-applies: []
10
+ simt-opt-in: true
11
+ simt-substitutions:
12
+ - key: previewWorkers
13
+ default: the dedicated preview Workers
14
+ describe: the preview Worker names this family deploys
15
+ - key: previewUrlHost
16
+ default: https://<preview-worker>.<account>.workers.dev
17
+ describe: the preview URL shape authenticated checks must target
18
+ - key: productionDomains
19
+ default: the repo's production domains
20
+ describe: domains authenticated postflight must never target
21
+ - key: productionDomainNote
22
+ default: ""
23
+ describe: one clause naming this repo's own production domain binding
24
+ # These two arrived as one slot in the divergent files: one repo put a build-config
25
+ # instruction where another put a domain-binding note, which read as a conflict. They
26
+ # are not alternatives, so the union carries both — but a repo that needs one, or
27
+ # neither, declares that. A worker that serves derivatives and calls no API has no
28
+ # API base URL to set, so it declares only its own custom-domain binding.
29
+ - key: previewApiBaseUrlNote
30
+ default: "- Point the preview build at the preview API Worker: set `SOCIAL_API_BASE_URL` in the Cloudflare Workers Builds preview environment to the preview API Worker URL."
31
+ describe: build-config instruction, when this repo actually has a preview API base URL to set
32
+ - key: googleOnlyNote
33
+ default: "- Production and public browser flows remain Google-only."
34
+ describe: the identity policy this repo enforces in production
35
+ ---
36
+
37
+ # Preview-Only Authenticated Postflight
38
+
39
+ Authenticated remote postflight and release checks use only {{previewWorkers}}, deployed
40
+ with `AUTH_PROVIDER_POLICY=preview_postflight_password` and a secret-bound Firebase password
41
+ identity (`POSTFLIGHT_PASSWORD_UID`).
42
+
43
+ ## Requirements
44
+
45
+ - Authenticated checks must target preview URLs (`{{previewUrlHost}}`).
46
+ - Postflight credentials live in the operator keychain only; never in source, chat, D1, or
47
+ logs.
48
+ {{googleOnlyNote}}
49
+ {{previewApiBaseUrlNote}}
50
+ {{productionDomainNote}}
51
+
52
+ ## Forbidden
53
+
54
+ - Authenticated postflight against production domains ({{productionDomains}}).
55
+ - Using real Social Google accounts for feature slice verification.
56
+ - Demanding, pasting, or storing production Google OAuth tokens in chat or tickets.
57
+
58
+ ## Allowed Without Account
59
+
60
+ - Unauthenticated production probes (`/health`, `/openapi.json`, a fail-closed `401`),
61
+ Cloudflare API inventory, D1 migration verification, and Worker deployment status.
@@ -0,0 +1,52 @@
1
+ ---
2
+ simt-id: slice-commit
3
+ simt-target: .cursor/rules/slice-commit.mdc
4
+ description: How a completed change becomes one commit, and what happens before anything is pushed
5
+ alwaysApply: true
6
+ # `simt-applies: always` is what makes a rule reachable at all. Without it this rule was
7
+ # authored, shipped, tested for its presence on disk -- and projected into no repo,
8
+ # silently. Reached by running `init` against a real repo, not by reading the file.
9
+ simt-applies: always
10
+ ---
11
+ # Slice Commit
12
+
13
+ A slice is the smallest change that is independently valuable on its own. Committing
14
+ one is a mechanical procedure with a fixed order, because every step after it depends
15
+ on the one before: you cannot review a diff you have not staged, and you cannot claim
16
+ evidence for a test you have not run.
17
+
18
+ ## Order
19
+
20
+ 1. **Run the focused test the change needs**, through the repository's own runner,
21
+ naming the exact command and the exact file — see `test-gate`. A full suite is
22
+ for a named trigger, not for progress.
23
+ 2. **Stage only what the slice touched.** `git status` first, and leave unrelated work
24
+ alone. Report what you left alone; silence about it reads as "I reverted it".
25
+ 3. **Read the staged diff.** Not the working tree — the diff. It is what will be
26
+ committed, and it is the last chance to notice a file that does not belong.
27
+ 4. **Write the message.** Conventional Commits, imperative subject, no trailing period:
28
+ `fix(gates): declare only gates a repo can run, and report the ones it cannot`.
29
+ The subject says what changed; the body says why, and what was deliberately not
30
+ changed.
31
+ 5. **Commit.** `git commit`, non-interactive. Report the SHA.
32
+ 6. **Stop.**
33
+
34
+ ## Pushing is a separate decision
35
+
36
+ **Never push because the work is finished.** Push is a separate act with its own
37
+ approval, and pushing the branch a remote treats as production can deploy it.
38
+
39
+ Before asking for approval, state what the push will do: which branch, how many
40
+ commits, and whether it triggers a deployment, a migration, or any other remote
41
+ mutation. Then wait. Approval to commit is not approval to push.
42
+
43
+ Never use `--no-verify`. A hook that fails is telling you something about the change;
44
+ skipping it turns a gate into a suggestion and the next person has no way to know it
45
+ was skipped.
46
+
47
+ ## What never belongs in a commit
48
+
49
+ - Failing, partial, or unrun work. A commit is a claim; a partial one is a false one.
50
+ - Secrets, tokens, or generated artefacts that drift.
51
+ - Work nobody asked for. Unrelated changes in a slice commit are invisible in review
52
+ and impossible to revert on their own.
@@ -0,0 +1,54 @@
1
+ ---
2
+ simt-id: test-gate
3
+ simt-target: .cursor/rules/test-gate.mdc
4
+ description: Full-pass tests and test deltas are mandatory before commit or reviewer approval
5
+ alwaysApply: true
6
+ simt-applies: always
7
+ simt-substitutions:
8
+ - key: exampleRunner
9
+ default: your test runner, through the repository's own script or task
10
+ describe: how this repo actually runs one named test file
11
+ - key: exampleTestPath
12
+ default: path/to/the.changed.test.ts
13
+ describe: one real test file for this repo, used only as the named example
14
+ - key: pathKinds
15
+ default: feature/contract/route
16
+ describe: this repo's executable path vocabulary
17
+ - key: producerNoun
18
+ default: API producer
19
+ describe: what produces a contract this repo consumes
20
+ ---
21
+
22
+ # Test Gate
23
+
24
+ Applies to every feature slice, bugfix, and plan tracker task. Docs/config-only chores are
25
+ exempt from test deltas but require named doc/format checks to pass.
26
+
27
+ ## Implementer Requirements
28
+
29
+ 1. **Name exact commands and test files**: {{exampleRunner}}, selecting
30
+ `{{exampleTestPath}}` on its own.
31
+ 2. **100% Pass Required**: the named commands must exit 0 with every test passing. A
32
+ partial pass (e.g. 6/8 passing) is a hard blocker, and so is quoting the passing subset.
33
+ 3. **Behavioral Test Deltas**:
34
+ - New {{pathKinds}} path -> new or extended test asserting the behavior.
35
+ - Bugfix -> regression test reproducing the failure mode.
36
+ - If no test file changed, justify why the existing tests fully prove the invariant.
37
+ 4. **Cross-Repo Order**: commit the {{producerNoun}} (contract/migration) before any
38
+ consumer generates against it. Never apply remote migrations or deploy from uncommitted
39
+ code.
40
+
41
+ ## Reviewer Mandatory Block
42
+
43
+ Return `BLOCK` when:
44
+
45
+ - Any test fails, is skipped (without pre-existing justification), or is unrun.
46
+ - An executable diff has no test delta and no explicit justification.
47
+ - The coordinator cites partial suite results or defers a failing test.
48
+ - **Consumer side:** a consumer requires a new API field with no backward-compatibility or
49
+ deploy-order evidence.
50
+ - **Producer side:** the {{producerNoun}} ships without a test asserting the new invariant
51
+ or field.
52
+
53
+ The last two are complementary, not alternatives. A reviewer that checks only one of them
54
+ misses half of the failure they exist to catch.
@@ -0,0 +1,63 @@
1
+ ---
2
+ simt-id: android
3
+ simt-title: Android
4
+ # Selected on the one thing that makes a repository an Android application: a
5
+ # module with an `AndroidManifest.xml`. `gradle` and `kotlin` are shared with every
6
+ # JVM backend, which is how a Spring or Ktor service used to receive this profile
7
+ # (S28, ADR-047).
8
+ simt-applies: [has-android-manifest]
9
+ ---
10
+
11
+ # Stack profile: Android
12
+
13
+ Applies to: `has-android-manifest` — some module has a
14
+ `src/main/AndroidManifest.xml`. A JVM backend with no Android module does not get
15
+ this profile; see `jvm`.
16
+
17
+ ## Build
18
+
19
+ - `./gradlew` only. Never a system `gradle`. Never `--configuration-cache` where a
20
+ repo documents that it breaks.
21
+ - `./gradlew spotlessApply` is the formatting entrypoint in repos that use Spotless.
22
+ - The manifest is not hand-edited for a build-level change: `applicationId`, `versionCode`
23
+ and `versionName` are declared in the module's build file and land in the merged
24
+ manifest. A value in two places is a value that will disagree.
25
+
26
+ ## Modules and layers
27
+
28
+ - `:core:domain` depends on no other internal module. Enforce it; do not add an
29
+ import that breaks the direction.
30
+ - Layer suffixes: `*Repository`, `*ViewModel`, `*UiState`, `*Screen`, `*Service`.
31
+ - Feature modules never import `androidx.compose.ui.window.Dialog`, M3 `AlertDialog`
32
+ or M3 `ModalBottomSheet`. The raw `Dialog` window belongs to allowlisted `core:ui`
33
+ surfaces, and `checkOverlayModalPolicy` fails `./gradlew check` when a feature
34
+ bypasses it.
35
+
36
+ ## Accessibility
37
+
38
+ - Every user-facing string is a resource, with a `cd_` content description where an
39
+ icon or image carries meaning. Decorative images declare `contentDescription = null`
40
+ explicitly.
41
+ - Touch targets meet the platform minimum, and the minimum is asserted rather than
42
+ eyeballed.
43
+ - Respect the system font scale and the display size the user has chosen; a fixed
44
+ `sp` value or a hard-coded cell height breaks both.
45
+
46
+ ## Wear OS
47
+
48
+ - `applicationId` in the wear module must equal the phone app's. Divergence makes the
49
+ Data Layer fail silently — no error, no delivery.
50
+ - Wear and phone target SDKs differ by design for Play Console reasons. Do not "align"
51
+ them.
52
+
53
+ ## Data
54
+
55
+ - Room: bump the version, add the migration, extend the migration test. Never edit an
56
+ applied migration.
57
+
58
+ ## Testing
59
+
60
+ - Unit tests for view models, repositories and mappers; instrumentation tests for UI.
61
+ - `Dispatchers.setMain` in a `@BeforeTest`, restored in `@AfterTest`.
62
+ - Assert behaviour, not implementation. Never weaken an assertion, an accessibility
63
+ check or a fixture to match current behaviour.
@@ -0,0 +1,65 @@
1
+ ---
2
+ simt-id: cloudflare-workers
3
+ simt-title: Cloudflare Workers (TypeScript)
4
+ # What the repo runs on, not what it is written in. `typescript` was here and put
5
+ # this profile on every TypeScript repository in the estate that had no more
6
+ # specific one; `hono` was here too, and Hono runs on Node, Bun and Deno as
7
+ # happily as on Workers. A wrangler config or the `wrangler` dependency is the
8
+ # only evidence that this is a Worker (S28, ADR-047).
9
+ simt-applies: [cloudflare-workers]
10
+ ---
11
+
12
+ # Stack profile: Cloudflare Workers (TypeScript)
13
+
14
+ Applies to: `cloudflare-workers` — a `wrangler.json`, `wrangler.jsonc` or
15
+ `wrangler.toml`, or a `wrangler` dependency.
16
+
17
+ ## Schema and config
18
+
19
+ - `wrangler.jsonc` is the single source of binding and environment truth. Do not read
20
+ configuration from a second file.
21
+ - Bindings are the integration surface. A Worker calls a service binding, not a REST endpoint
22
+ over the network to its own account.
23
+ - Secrets come from the runtime binding. Never commit them, never log them, never accept one
24
+ from a query parameter.
25
+
26
+ ## Data
27
+
28
+ - D1: one new sequential immutable migration per change. Never edit an applied migration.
29
+ Define coexistence order and forward repair; do not promise SQL rollback.
30
+ - Prefer D1 constraints and triggers over read-then-write in application code.
31
+ - Prepared, parameterised statements only. Never interpolate a value into SQL.
32
+ - Durable Objects: one owner per piece of state. Use alarms for scheduling, and RPC for
33
+ internal calls rather than self-fetch.
34
+ - Queues are at-least-once: consumers must be idempotent, keyed by an idempotency token that
35
+ is stable across retries.
36
+
37
+ ## Request handling
38
+
39
+ - Validate at the edge with the schema layer. Authorization is server-authoritative; a
40
+ client-side role, claim, cache entry or URL parameter grants nothing.
41
+ - `Request`/`Response` are globals. Do not pass them through as values into domain code.
42
+ - Caching defaults to `private, no-store`. Never cache token, account, block, reveal, admin
43
+ decisions or authenticated errors.
44
+ - Streaming is the default for large bodies; do not buffer without a stated reason.
45
+
46
+ ## Module state
47
+
48
+ - No module-scope mutable state. A Worker instance is reused across requests, so a counter or
49
+ cache at module scope leaks between users.
50
+
51
+ ## Observability
52
+
53
+ - Structured logs through the logger interface, with an allowlist. Never log bodies, tokens,
54
+ UIDs, user text, exact coordinates or full URLs.
55
+ - Use `Math.random` never for anything security-relevant; use Web Crypto.
56
+
57
+ ## Types and tests
58
+
59
+ - `strict` plus `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`,
60
+ `noImplicitOverride`, `noFallthroughCasesInSwitch`, `noImplicitReturns`, `isolatedModules`.
61
+ With `exactOptionalPropertyTypes`, pass optionals through conditional spreads or an explicit
62
+ `prop: value | undefined`; never `prop?: T` into a `prop: T | undefined` parameter.
63
+ - Generate Wrangler types from the config; do not hand-write binding types.
64
+ - Test with the real Workers runtime pool (`@cloudflare/vitest-pool-workers`) so Workers APIs,
65
+ D1 and Durable Objects behave as they will in production.
@@ -0,0 +1,62 @@
1
+ ---
2
+ simt-id: connectiq
3
+ simt-title: Connect IQ (Monkey C)
4
+ simt-applies: [connectiq]
5
+ ---
6
+
7
+ # Stack profile: Connect IQ (Monkey C)
8
+
9
+ Applies to: `connectiq`.
10
+
11
+ ## The platform is not the language you know
12
+
13
+ This profile exists because the most expensive failures in this stack are silent. Read the
14
+ repo's own known-defects table before assuming any platform behaviour; the entries there are
15
+ empirically verified and will otherwise be rediscovered one bug at a time.
16
+
17
+ Known traps to assume until verified otherwise:
18
+
19
+ - `String.toNumber()` can truncate rather than fail.
20
+ - `==` on two `String`s compares identity, not value.
21
+ - `Number` is 32-bit. Values outside that range are wrong, not approximate.
22
+ - `logger.error()` does not fail a test. A passing suite can contain a logged error.
23
+ - `getGlanceView()` is unavailable on the Simulator.
24
+
25
+ ## Memory
26
+
27
+ - Memory budgets are hard limits, not targets, and they are the repo's declared gate
28
+ (`simt-dev.json`). Zero allocation in `onUpdate`; no allocation in a draw callback.
29
+ - A memory check that "currently exits 1 by design" is not a gate — it is noise that teaches
30
+ everyone to ignore it. Declare the budget or drop the check.
31
+
32
+ ## Language and style
33
+
34
+ - Four-space indent, LF, 300-char line limit.
35
+ - `initialize()`, `_camelCase` for private members, `UPPER_SNAKE_CASE` for constants.
36
+ - `typeCheckLevel: "gradual"` — do not raise it to chase a build; fix the types instead.
37
+ - One responsibility per class. A class that draws, computes and persists is three classes.
38
+ - 400 lines is a review trigger, 1000 a ceiling (ADR-005). Generated `.mc` is exempt when the
39
+ generator is named.
40
+
41
+ ## Data and protocol
42
+
43
+ - A model that crosses the wire is **generated, never hand-written**. Hand edits are overwritten
44
+ by the next codegen run and the drift is discovered in production.
45
+ - Validate every field at construction. A target with `bearingDeg = 400` cannot be created.
46
+ - A positional parser makes field order part of the contract. Reordering a field is a protocol
47
+ change, not a refactor.
48
+ - `schemaVersion` is checked before parsing, never after.
49
+
50
+ ## Security
51
+
52
+ - Never commit the developer key, an app UUID hardcoded as a literal, or any credential.
53
+ The developer key is unrecoverable if lost — treat its loss as unrecoverable and rotate.
54
+ - Data minimisation: a field not needed on the device is not sent to it.
55
+ - No payload logging. Log the shape of a failure — field name and reason — never the data.
56
+
57
+ ## Build
58
+
59
+ - `monkeyc -f monkey.jungle` with the documented product ids. Verify with the identity and
60
+ settings-defaults checks before every build; they catch the two mistakes that otherwise reach
61
+ a device.
62
+ - Do not pass `--configuration-cache` to Gradle.
@@ -0,0 +1,31 @@
1
+ ---
2
+ simt-id: container
3
+ simt-title: Containers
4
+ simt-applies: [has-dockerfile]
5
+ simt-fallback: false
6
+ ---
7
+
8
+ ## Containers
9
+
10
+ A Dockerfile is the build. If a rule here and the repo's own instructions disagree, the
11
+ repo wins — but the disagreement is worth raising, because these are the mistakes that
12
+ survive to production.
13
+
14
+ - **Pin the base image by digest.** A floating `FROM node:22` means last night's build is
15
+ not reproducible and a compromised upstream tag is your problem. If the repo deliberately
16
+ tracks a tag, do not "fix" it silently.
17
+ - **Never bake a secret.** No `ARG` that holds a token, no `ENV` holding a key, no `COPY
18
+ .env`. Build args are recorded in image history, which is world-readable in most
19
+ registries. Read secrets from the runtime environment.
20
+ - **Copy as little as possible.** Copy manifests first, install, then copy source: a
21
+ dependency layer invalidates on every source edit otherwise. And never `COPY . .` when a
22
+ `.dockerignore` exists to be honoured.
23
+ - **Run as a non-root user**, and do not need root to write to the application directory.
24
+ - **One process per container.** Signals, restart policy and log collection all assume the
25
+ entrypoint is the app, not a shell wrapping it.
26
+ - **Expose only what is served.** An unpublished port is still reachable on the container
27
+ network; an `EXPOSE` is documentation, not a control.
28
+ - **Health endpoints are not debug endpoints.** A health check runs often, automatically,
29
+ and on every replica. It must not leak counts, versions, or stack traces.
30
+ - **The image is the unit of rollback.** A change you cannot rebuild byte-identically is a
31
+ change you cannot roll back, which is a worse position than not shipping it.
@@ -0,0 +1,54 @@
1
+ ---
2
+ simt-id: jvm
3
+ simt-title: JVM backend
4
+ # The build tool and the language, which is what a JVM backend is identified by.
5
+ # This profile used to be `jvm-android` and applied on `gradle` alone, so a Spring
6
+ # or Ktor service received rules about Compose, Wear OS application ids and
7
+ # instrumentation tests — advice with nothing to apply it to (S28, ADR-047).
8
+ simt-applies: [gradle, has-maven-pom, kotlin, java]
9
+ ---
10
+
11
+ # Stack profile: JVM backend
12
+
13
+ Applies to: `gradle`, `has-maven-pom`, `kotlin`, `java` — a JVM build. The Android
14
+ rules live in the `android` profile, which selects on `has-android-manifest`.
15
+
16
+ ## Build
17
+
18
+ - `./gradlew` only, never a system `gradle`; `./mvnw` where a wrapper is committed,
19
+ never a system `mvn`. Never `--configuration-cache` where a repo documents that it
20
+ breaks.
21
+ - `./gradlew spotlessApply` is the formatting entrypoint in repos that use Spotless.
22
+ - Pin the JVM toolchain in the build file (`java.toolchain`, `sourceCompatibility`).
23
+ A JDK on the developer's PATH is not a floor anything enforces.
24
+
25
+ ## Modules and layers
26
+
27
+ - `:core:domain` depends on no other internal module. Enforce it; do not add an
28
+ import that breaks the direction.
29
+ - Layer suffixes: `*Repository`, `*Service`, `*Mapper`, `*Controller`. A class named
30
+ `*Repository` that talks to HTTP is not a repository.
31
+
32
+ ## Kotlin
33
+
34
+ - Four-space indent, LF, 300-char line limit.
35
+ - No `!!`. Prefer a sealed `RepositoryResult<T>` over exceptions for expected failures.
36
+ - Expose `MutableStateFlow` as `StateFlow` via `.asStateFlow()`; update state with
37
+ `_state.update { }`.
38
+ - Java and Kotlin interop: `Optional` in a Java signature, a nullability annotation in
39
+ a Kotlin one, and never a platform type left untyped at the boundary.
40
+
41
+ ## Testing
42
+
43
+ - Unit tests for services, repositories and mappers; an integration test only when the
44
+ behaviour is genuinely cross-system.
45
+ - Assert behaviour, not implementation. Never weaken an assertion to match current
46
+ behaviour.
47
+ - Test the narrowest layer that proves the behaviour.
48
+
49
+ ## Data
50
+
51
+ - One new sequential immutable migration per change. Never edit an applied migration.
52
+ Define coexistence order and forward repair; do not promise SQL rollback.
53
+ - Prepared, parameterised statements only. Never interpolate a value into SQL, and
54
+ never assemble SQL by string concatenation from a caller-supplied identifier.
@@ -0,0 +1,45 @@
1
+ ---
2
+ simt-id: node
3
+ simt-title: Node (general)
4
+ simt-applies: [node]
5
+ simt-fallback: true
6
+ ---
7
+
8
+ # Stack profile: Node (general)
9
+
10
+ Applies to: `node`, `node-web`, `typescript` when no more specific profile matches.
11
+
12
+ ## Manifest
13
+
14
+ - One `packageManager` field, matching the committed lockfile. A repo with no declared
15
+ package manager has no enforced one.
16
+ - `engines.node` states a floor. A version floor nobody enforces is a comment.
17
+ - `.nvmrc` pins the development version and must agree with `engines` and with CI.
18
+
19
+ ## Scripts
20
+
21
+ - Run through `npm run <script>` (ADR-010). Never `npx` or `npm exec` for a declared
22
+ dependency: `npx` will fetch a version the project does not pin.
23
+ - A script name is the contract. Rename a script and rename every caller, including docs,
24
+ hooks and CI, in the same change.
25
+
26
+ ## Formatting and linting
27
+
28
+ - Prettier owns formatting. ESLint disables the stylistic rules Prettier already owns —
29
+ otherwise the two tools fight over every file.
30
+ - `format` and `format:check` are both present. `format:check` is what CI and hooks run.
31
+ - `.prettierignore` covers generated and vendored output: build directories, coverage,
32
+ generated clients, graph output. Formatting generated output is a review finding, not a fix.
33
+
34
+ ## Types
35
+
36
+ - `strict` plus the full strictness set, and `noEmit` for any project that bundles elsewhere.
37
+ A bare `tsc` in a bundler project writes JavaScript next to the sources.
38
+ - `moduleResolution` spelled consistently across every repo in the workspace.
39
+
40
+ ## Tests
41
+
42
+ - `vitest`, `jest` or `node --test` — one runner per repo, declared, not inherited.
43
+ - Focused selection is the default invocation. A full suite runs against the triggers in
44
+ `simt-dev.json` (ADR-003).
45
+ - No snapshot-only acceptance: a snapshot proves the code did not change, not that it is right.