@erclx/canon 5.44.0 → 5.46.0

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 (253) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/REQUIREMENT.md +15 -31
  4. package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
  5. package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
  6. package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
  7. package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
  8. package/claude/skills/canon-cli/SKILL.md +0 -1
  9. package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
  10. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
  11. package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
  12. package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
  13. package/claude/skills/code-craft/REQUIREMENT.md +14 -28
  14. package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
  15. package/claude/skills/context-fold/REQUIREMENT.md +15 -39
  16. package/claude/skills/context-fold/references/context.md +3 -3
  17. package/claude/skills/create-rule/REQUIREMENT.md +10 -24
  18. package/claude/skills/create-rule/SKILL.md +3 -0
  19. package/claude/skills/create-skill/REQUIREMENT.md +10 -21
  20. package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
  21. package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
  22. package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
  23. package/claude/skills/design-identity/REQUIREMENT.md +14 -20
  24. package/claude/skills/design-taste/REQUIREMENT.md +16 -57
  25. package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
  26. package/claude/skills/document-health/REQUIREMENT.md +15 -29
  27. package/claude/skills/document-health/SKILL.md +2 -2
  28. package/claude/skills/document-repair/REQUIREMENT.md +32 -0
  29. package/claude/skills/document-repair/SKILL.md +76 -0
  30. package/claude/skills/document-repair/references/batches.md +44 -0
  31. package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
  32. package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
  33. package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
  34. package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
  35. package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
  36. package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
  37. package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
  38. package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
  39. package/claude/skills/git-branch/REQUIREMENT.md +12 -26
  40. package/claude/skills/git-commit/REQUIREMENT.md +11 -15
  41. package/claude/skills/git-followup/REQUIREMENT.md +11 -22
  42. package/claude/skills/git-issue/REQUIREMENT.md +9 -15
  43. package/claude/skills/git-pr/REQUIREMENT.md +13 -32
  44. package/claude/skills/git-pr/SKILL.md +10 -2
  45. package/claude/skills/git-pr/references/closing-issues.md +47 -0
  46. package/claude/skills/git-pr/references/pr.md +4 -0
  47. package/claude/skills/git-ship/REQUIREMENT.md +13 -26
  48. package/claude/skills/git-split/REQUIREMENT.md +10 -17
  49. package/claude/skills/git-stage/REQUIREMENT.md +12 -18
  50. package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
  51. package/claude/skills/make-deck/REQUIREMENT.md +13 -21
  52. package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
  53. package/claude/skills/pick-by-eye/REQUIREMENT.md +17 -67
  54. package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
  55. package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
  56. package/claude/skills/plan-groundwork/SKILL.md +5 -2
  57. package/claude/skills/plan-groundwork/references/output.md +47 -1
  58. package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
  59. package/claude/skills/plan-intake/references/intake.md +2 -2
  60. package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
  61. package/claude/skills/plan-intake-answer/SKILL.md +7 -1
  62. package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
  63. package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
  64. package/claude/skills/read-frames/REQUIREMENT.md +3 -8
  65. package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
  66. package/claude/skills/review-address/REQUIREMENT.md +14 -38
  67. package/claude/skills/review-craft/REQUIREMENT.md +14 -32
  68. package/claude/skills/review-pr/REQUIREMENT.md +15 -34
  69. package/claude/skills/review-ui/REQUIREMENT.md +14 -39
  70. package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
  71. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
  72. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
  73. package/claude/skills/role-planner/REQUIREMENT.md +15 -73
  74. package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
  75. package/claude/skills/role-reviewer/SKILL.md +5 -1
  76. package/claude/skills/role-worker/REQUIREMENT.md +13 -41
  77. package/claude/skills/role-worker/SKILL.md +2 -0
  78. package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
  79. package/claude/skills/search-craft/REQUIREMENT.md +12 -36
  80. package/claude/skills/search-craft/SKILL.md +1 -1
  81. package/claude/skills/search-craft/references/adopted.md +2 -2
  82. package/claude/skills/session-compact/REQUIREMENT.md +13 -23
  83. package/claude/skills/session-map/REQUIREMENT.md +13 -29
  84. package/claude/skills/session-relay/REQUIREMENT.md +14 -58
  85. package/claude/skills/session-relay/SKILL.md +6 -0
  86. package/claude/skills/session-resume/REQUIREMENT.md +13 -27
  87. package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
  88. package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
  89. package/claude/skills/target-check/REQUIREMENT.md +16 -23
  90. package/claude/skills/target-setup/REQUIREMENT.md +11 -34
  91. package/claude/skills/target-setup/SKILL.md +2 -2
  92. package/claude/skills/target-setup/references/detect.md +0 -1
  93. package/claude/skills/target-setup/references/verify.md +2 -2
  94. package/claude/skills/task-board/REQUIREMENT.md +13 -22
  95. package/claude/skills/task-board/SKILL.md +7 -0
  96. package/claude/skills/task-board/references/tasks.md +1 -1
  97. package/claude/skills/task-complete/REQUIREMENT.md +11 -24
  98. package/claude/skills/task-complete/references/archive.md +1 -0
  99. package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
  100. package/claude/skills/teach-workspace/references/promotion.md +5 -5
  101. package/claude/skills/test-craft/REQUIREMENT.md +15 -46
  102. package/claude/skills/test-first/REQUIREMENT.md +14 -20
  103. package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
  104. package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
  105. package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
  106. package/claude/skills/video-craft/REQUIREMENT.md +14 -27
  107. package/claude/skills/write-doc/REQUIREMENT.md +14 -24
  108. package/claude/skills/write-human/REQUIREMENT.md +15 -27
  109. package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
  110. package/docs/agents/context-audit.md +19 -12
  111. package/docs/agents/install-and-sync.md +2 -2
  112. package/docs/agents/markdown-audit.md +15 -10
  113. package/docs/agents/output-shape.md +1 -2
  114. package/docs/target/migrations.md +18 -0
  115. package/docs/target/projects.md +3 -2
  116. package/docs/target/scenarios.md +4 -1
  117. package/docs/workflow/skill-map-on-request.md +1 -1
  118. package/docs/workflow/skill-map.md +6 -5
  119. package/governance/detect.toml +4 -0
  120. package/governance/ledger/lang/go.md +61 -0
  121. package/governance/ledger/lang/php.md +50 -0
  122. package/governance/ledger/lang/python.md +68 -0
  123. package/governance/ledger/lang/typescript.md +64 -0
  124. package/governance/ledger/lib/database.md +65 -0
  125. package/governance/ledger/lib/e2e-reliability.md +57 -0
  126. package/governance/ledger/lib/pydantic.md +61 -0
  127. package/governance/ledger/lib/security-server.md +62 -0
  128. package/governance/ledger/lib/security-web.md +51 -0
  129. package/governance/ledger/lib/tanstack-query.md +57 -0
  130. package/governance/ledger/lib/test-scope.md +43 -0
  131. package/governance/ledger/lib/testing-go.md +57 -0
  132. package/governance/ledger/lib/testing-php.md +51 -0
  133. package/governance/ledger/lib/testing-py.md +67 -0
  134. package/governance/ledger/lib/testing-ts.md +63 -0
  135. package/governance/ledger/lib/zod.md +47 -0
  136. package/governance/ledger/tooling/ci-workflow.md +33 -0
  137. package/governance/ledger/tooling/code-comments.md +48 -0
  138. package/governance/ledger/tooling/config-comments.md +27 -0
  139. package/governance/ledger/tooling/dependencies.md +38 -0
  140. package/governance/ledger/ui/a11y.md +55 -0
  141. package/governance/ledger/ui/copy.md +49 -0
  142. package/governance/ledger/ui/design-reference.md +42 -0
  143. package/governance/ledger/ui/design-taste.md +19 -0
  144. package/governance/ledger/ui/forms.md +71 -0
  145. package/governance/ledger/ui/interface-casing.md +47 -0
  146. package/governance/ledger/ui/keyboard.md +68 -0
  147. package/governance/ledger/ui/link-behavior.md +29 -0
  148. package/governance/ledger/ui/motion.md +33 -0
  149. package/governance/ledger/ui/surface-capture.md +69 -0
  150. package/governance/ledger/ui/ux-completeness.md +79 -0
  151. package/governance/renames.toml +0 -2
  152. package/governance/rules/claude/output.md +5 -1
  153. package/governance/rules/code/routing.md +5 -1
  154. package/governance/rules/lang/go.md +7 -16
  155. package/governance/rules/lang/php.md +3 -3
  156. package/governance/rules/lang/python.md +9 -18
  157. package/governance/rules/lang/typescript.md +9 -19
  158. package/governance/rules/lib/database.md +5 -5
  159. package/governance/rules/lib/e2e-reliability.md +4 -6
  160. package/governance/rules/lib/pydantic.md +14 -16
  161. package/governance/rules/lib/security-server.md +4 -4
  162. package/governance/rules/lib/security-web.md +6 -10
  163. package/governance/rules/lib/tanstack-query.md +10 -12
  164. package/governance/rules/lib/test-scope.md +4 -4
  165. package/governance/rules/lib/testing-go.md +1 -2
  166. package/governance/rules/lib/testing-php.md +4 -5
  167. package/governance/rules/lib/testing-py.md +11 -19
  168. package/governance/rules/lib/testing-ts.md +7 -16
  169. package/governance/rules/lib/zod.md +6 -8
  170. package/governance/rules/tooling/code-comments.md +2 -4
  171. package/governance/rules/tooling/config-comments.md +1 -4
  172. package/governance/rules/tooling/dependencies.md +1 -1
  173. package/governance/rules/ui/a11y.md +16 -45
  174. package/governance/rules/ui/copy.md +6 -9
  175. package/governance/rules/ui/forms.md +13 -19
  176. package/governance/rules/ui/interface-casing.md +5 -7
  177. package/governance/rules/ui/keyboard.md +38 -0
  178. package/governance/rules/ui/link-behavior.md +3 -3
  179. package/governance/rules/ui/motion.md +3 -3
  180. package/governance/rules/ui/surface-capture.md +15 -27
  181. package/governance/rules/ui/ux-completeness.md +16 -39
  182. package/governance/stacks/base.toml +0 -1
  183. package/package.json +1 -1
  184. package/scripts/core/install-check.sh +1 -1
  185. package/src/claude/cases/workflow.ts +12 -0
  186. package/src/cli/help.ts +0 -1
  187. package/src/cli.ts +0 -2
  188. package/src/commands/context.ts +57 -3
  189. package/src/commands/gov.ts +4 -0
  190. package/src/commands/init.ts +2 -2
  191. package/src/commands/labels.ts +83 -3
  192. package/src/commands/markdown.ts +188 -21
  193. package/src/commands/sessions.ts +36 -3
  194. package/src/commands/tasks.ts +180 -0
  195. package/src/commands/tooling.ts +18 -5
  196. package/src/commands/worktrees.ts +2 -0
  197. package/src/context/coverage.ts +210 -0
  198. package/src/context/gate.ts +12 -3
  199. package/src/design/components.ts +1 -1
  200. package/src/gate/stages.ts +1 -1
  201. package/src/gov/audit.ts +22 -2
  202. package/src/init/plan.ts +1 -8
  203. package/src/init/steps.ts +44 -7
  204. package/src/intake/items.ts +14 -0
  205. package/src/inventory/subjects.ts +1 -1
  206. package/src/labels/closing.ts +46 -0
  207. package/src/markdown/gated.ts +250 -0
  208. package/src/markdown/scope.ts +119 -2
  209. package/src/migrate/rename.ts +6 -0
  210. package/src/migrate/scratch-evidence.ts +12 -4
  211. package/src/records/backup.ts +3 -3
  212. package/src/records/validate.ts +3 -3
  213. package/src/roots/record.ts +17 -8
  214. package/src/sessions/claim.ts +7 -0
  215. package/src/sessions/live.ts +53 -6
  216. package/src/sessions/registry.ts +11 -0
  217. package/src/sessions/resolve.ts +32 -5
  218. package/src/tasks/closes.ts +136 -0
  219. package/src/tasks/record.ts +1 -1
  220. package/src/tooling/inject.ts +26 -7
  221. package/src/tooling/package.ts +32 -0
  222. package/src/tooling/read.ts +46 -3
  223. package/src/tooling/scan.ts +8 -2
  224. package/src/worktrees/reclaim.ts +16 -1
  225. package/tooling/astro/reference.md +64 -93
  226. package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
  227. package/tooling/base/configs/scripts/verify.ts +2 -2
  228. package/tooling/base/reference.md +1 -9
  229. package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
  230. package/tooling/base/seeds/canon/context/development/index.md +11 -0
  231. package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
  232. package/tooling/base/seeds/canon/context/index.md +1 -2
  233. package/tooling/claude/manifest.toml +1 -5
  234. package/tooling/claude/reference.md +36 -59
  235. package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
  236. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
  237. package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
  238. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
  239. package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
  240. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
  241. package/tooling/claude/seeds/CLAUDE.md +2 -2
  242. package/tooling/nextjs/reference.md +0 -6
  243. package/tooling/php/reference.md +0 -4
  244. package/tooling/web/configs/.github/workflows/verify.yml +28 -0
  245. package/tooling/web/configs/.oxlintrc.json +7 -0
  246. package/tooling/web/configs/e2e/capture-types.ts +35 -0
  247. package/tooling/web/configs/e2e/screenshot.ts +23 -72
  248. package/tooling/web/manifest.toml +1 -1
  249. package/tooling/web/reference.md +77 -124
  250. package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
  251. package/governance/rules/canon/task-scope.md +0 -12
  252. package/src/commands/wiki.ts +0 -100
  253. package/src/wiki/init.ts +0 -85
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: End-to-end reliability rule ledger
3
+ description: Sources for governance/rules/lib/e2e-reliability.md, one row per bullet
4
+ ---
5
+
6
+ # End-to-end reliability rule ledger
7
+
8
+ The field is browser test automation. The authorities are the Playwright documentation at playwright.dev, MDN for the `scrollend` event, and the Chrome DevTools Protocol definition for CPU throttling. A guard bullet is a house choice wherever no page takes a side, and each such row names the false pass it prevents. None of the pages read names a Playwright major, so the rows record the read date alone.
9
+
10
+ ## Waiting
11
+
12
+ | Bullet | Source | Read |
13
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Settle, never `waitForTimeout` | [Page API](https://playwright.dev/docs/api/class-page): `waitForTimeout` is "Discouraged", since "Tests that wait for time are inherently flaky", and [assertions](https://playwright.dev/docs/test-assertions): "You can convert any synchronous `expect` to an asynchronous polling one using `expect.poll`" | 2026-10-18 |
15
+ | Fixed window for absence | House choice: an absence has no signal to settle on, so a web-first assertion of it passes before the thing it rules out has had time to happen | 2026-10-18 |
16
+ | Bound every settle | [Assertions](https://playwright.dev/docs/test-assertions): "by default `toPass` has timeout 0 and does not respect custom" expect timeouts | 2026-10-18 |
17
+ | No raised timeout under load | House choice: a longer timeout hides a race that the load exposed, and it returns on a slower runner | 2026-10-18 |
18
+ | `scrollend`, then stillness | [MDN scrollend](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollend_event): "If the scroll position did not change, then no scrollend event fires" | 2026-10-18 |
19
+ | Reduced motion by default | [Test options](https://playwright.dev/docs/api/class-testoptions): `reducedMotion` "Emulates `'prefers-reduced-motion'` media feature" | 2026-10-18 |
20
+
21
+ ## Falsifiable guards
22
+
23
+ | Bullet | Source | Read |
24
+ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
25
+ | Non-empty before every | House choice: a property asserted over an empty set holds vacuously, so the guard passes on the page that lost every member | 2026-10-18 |
26
+ | Raise when refused | House choice: an instrument returning a default on refusal hands the assertion a value it accepts, so the guard passes without measuring | 2026-10-18 |
27
+ | See the guard fail first | House choice: a guard never run against its defect may pass on the defect too, and nothing tells the two apart | 2026-10-18 |
28
+ | Never weaken to pass | House choice: a loosened assertion passes on the defect it was written to catch, where a narrowed wait keeps the check | 2026-10-18 |
29
+
30
+ ## Reproducing a failure that only appears in CI
31
+
32
+ | Bullet | Source | Read |
33
+ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
34
+ | CPU throttling to reproduce | [DevTools Protocol, Emulation](https://chromedevtools.github.io/devtools-protocol/tot/Emulation/): `setCPUThrottlingRate` "Enables CPU throttling to emulate slow CPUs", as a "slowdown factor" | 2026-10-18 |
35
+ | Read the trace | [Best practices](https://playwright.dev/docs/best-practices): "For CI failures, use the Playwright trace viewer instead of videos and screenshots" | 2026-10-18 |
36
+ | Vary one condition | House choice: two runs that differ in an uncontrolled condition cannot attribute a change in count to the one under suspicion | 2026-10-18 |
37
+
38
+ ## Authority
39
+
40
+ | Bullet | Source | Read |
41
+ | ----------------------- | --------------------------------------------------------------------------------------------------- | ---------- |
42
+ | Pointer to `testing-ts` | House choice: a pointer to the rule that owns placement and naming, claiming no practice of its own | 2026-10-18 |
43
+
44
+ ## Declined
45
+
46
+ Every bullet the rewrite removed or reshaped, grouped by why.
47
+
48
+ ### Cut from the subject
49
+
50
+ - Cut "read the check conclusion as its own act, since a green diff review reports nothing about the gate". It governs reading CI after a push, which the ship and review skills own, and an end-to-end file is the wrong trigger for it.
51
+
52
+ ### Merged or reworded
53
+
54
+ - Merged "do not read a value once after a pause, poll it" into the settle bullet, which now names `page.waitForTimeout` as the call it bans.
55
+ - Reworded "bound every settle with an explicit timeout" to name `toPass`, the one settle the docs leave unbounded.
56
+ - Reworded "run with motion reduced" to name the `reducedMotion` option.
57
+ - Reworded "read the state the assertion does not" to read it from the trace, which the best practices page names for a CI failure.
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Pydantic rule ledger
3
+ description: Sources for governance/rules/lib/pydantic.md, one row per bullet
4
+ ---
5
+
6
+ # Pydantic rule ledger
7
+
8
+ The field is Python data validation, and the authority is the Pydantic documentation at pydantic.dev, which moved from docs.pydantic.dev. Every page read is the Pydantic 2 docs, so a version-bound bullet opens with "On Pydantic 2" and a Pydantic 1 target is never told to call an API it lacks.
9
+
10
+ ## Models
11
+
12
+ | Bullet | Source | Read |
13
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
14
+ | `BaseModel` at boundaries | House choice: a standard library `dataclass` checks no type at runtime, so malformed input passes the boundary unvalidated | 2026-10-18, Pydantic 2 |
15
+ | `model_config`, not `Config` | [Migration guide](https://pydantic.dev/docs/validation/latest/get-started/migration/): "to specify config on a model, you should set a class attribute called `model_config`" | 2026-10-18, Pydantic 2 |
16
+ | `extra="forbid"` on input | [Models](https://pydantic.dev/docs/validation/latest/concepts/models/): "`'forbid'`: Providing extra data is not permitted", and "`'ignore'`: Providing extra data is ignored (the default)" | 2026-10-18, Pydantic 2 |
17
+ | Constraints in `Field(...)` | [Fields](https://pydantic.dev/docs/validation/latest/concepts/fields/): "The Field() function can also be used to add constraints to specific types" | 2026-10-18, Pydantic 2 |
18
+
19
+ ## Validation
20
+
21
+ | Bullet | Source | Read |
22
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
23
+ | `model_validate` and `model_validate_json` | [Models](https://pydantic.dev/docs/validation/latest/concepts/models/): for a JSON payload, `model_validate_json()` "is generally considered faster" than parsing it to a dictionary first | 2026-10-18, Pydantic 2 |
24
+ | v2 validator decorators | [Migration guide](https://pydantic.dev/docs/validation/latest/get-started/migration/): "`@validator` has been deprecated", and so has `@root_validator`, each replaced by its v2 decorator | 2026-10-18, Pydantic 2 |
25
+ | Cross-field checks after | [Validators](https://pydantic.dev/docs/validation/latest/concepts/validators/): after model validators "run after the whole model has been validated" | 2026-10-18, Pydantic 2 |
26
+
27
+ ## Types
28
+
29
+ | Bullet | Source | Read |
30
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
31
+ | `SecretStr` for credentials | [Pydantic Types](https://pydantic.dev/docs/validation/latest/api/pydantic/types/): "A string used for storing sensitive information that you do not want to be visible in logging or tracebacks" | 2026-10-18, Pydantic 2 |
32
+ | Constrained types over regex | [Pydantic Types](https://pydantic.dev/docs/validation/latest/api/pydantic/types/): `PositiveInt` is "An integer that must be greater than zero" | 2026-10-18, Pydantic 2 |
33
+ | `Annotated` for reuse | [Fields](https://pydantic.dev/docs/validation/latest/concepts/fields/): Pydantic "supports the Annotated typing construct", and "Types can be made reusable" | 2026-10-18, Pydantic 2 |
34
+ | No `Any` fields | [Standard Library Types](https://pydantic.dev/docs/validation/latest/api/standard_library_types/): `Any` "Allows any value, including `None`" | 2026-10-18, Pydantic 2 |
35
+
36
+ ## Settings
37
+
38
+ | Bullet | Source | Read |
39
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
40
+ | One `BaseSettings` model | [Settings Management](https://pydantic.dev/docs/validation/latest/concepts/pydantic_settings/): the initializer "will attempt to determine the values of any fields not passed as keyword arguments" from the environment | 2026-10-18, Pydantic 2 |
41
+
42
+ ## Serialization
43
+
44
+ | Bullet | Source | Read |
45
+ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
46
+ | `model_dump(mode="json")` | [Serialization](https://pydantic.dev/docs/validation/latest/concepts/serialization/): "The `mode` argument can be set to `'json'` to ensure JSON-compatible types are used", and the [migration guide](https://pydantic.dev/docs/validation/latest/get-started/migration/) says "The `.json()` method is deprecated" | 2026-10-18, Pydantic 2 |
47
+ | `by_alias=True` outward | [Fields](https://pydantic.dev/docs/validation/latest/concepts/fields/): "the by_alias keyword argument defaults to False, and must be specified explicitly" | 2026-10-18, Pydantic 2 |
48
+
49
+ ## Declined
50
+
51
+ Every bullet the rewrite removed or reshaped, grouped by why.
52
+
53
+ ### Merged or reworded
54
+
55
+ - Merged "use `@field_validator` over the legacy `@validator`" with the `@root_validator` swap, which the old rule never named.
56
+ - Merged "use `model.model_dump_json()` over `json.dumps(model.dict())`" into the serialization bullet beside `model_dump(mode="json")`.
57
+ - Merged "use `Model.model_validate_json(s)` over `json.loads`" into the `model_validate` bullet. `Model(**data)` validates too, so the old contrast named no bug.
58
+ - Merged "use `pydantic_settings.BaseSettings` for env-driven configuration" into the one-model bullet.
59
+ - Narrowed "use `AnyUrl`, `EmailStr`, `SecretStr`, and `PositiveInt` over hand-rolled regex" into a `SecretStr` bullet for the log leak and a constrained-type bullet.
60
+ - Prefixed every legacy-API swap with "On Pydantic 2", since the rule loads on every Python file and a Pydantic 1 target lacks the v2 names.
61
+ - Reworded "use `Field(...)` over docstring conventions" to name the enforcement a docstring lacks.
@@ -0,0 +1,62 @@
1
+ ---
2
+ title: Server security rule ledger
3
+ description: Sources for governance/rules/lib/security-server.md, one row per bullet
4
+ ---
5
+
6
+ # Server security rule ledger
7
+
8
+ The field is application security, and the authorities are the OWASP Cheat Sheet Series, the OWASP API Security Top 10 2023, and MDN for the CORS protocol. The CORS bullet is worded the way `framework/fastapi.md` states it, so a FastAPI target reads one rule twice rather than two.
9
+
10
+ ## Authorization
11
+
12
+ | Bullet | Source | Read |
13
+ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Authorize on the server | [Authorization](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html): "Developers must never rely on client-side access control checks", and "Permission should be validated correctly on every request" | 2026-10-18 |
15
+ | Identity from the verified token | House choice: an identity read from a field the client sets is one the client chooses, which turns every authorization check into a check of the attacker's claim | 2026-10-18 |
16
+ | Check the specific record | [Authorization](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html): "Perform access control checks on every request for the specific object or functionality being accessed" | 2026-10-18 |
17
+ | Deny by default | [Authorization](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html): "an application should be configured to deny access by default" | 2026-10-18 |
18
+
19
+ ## Credentials
20
+
21
+ | Bullet | Source | Read |
22
+ | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
23
+ | Argon2id and a salt | [Password Storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html): "If Argon2id is not available, use scrypt", a salt is "unique, randomly generated" per password, and "hashing is a one-way function" | 2026-10-18 |
24
+ | Constant-time comparison | [Authentication](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html): a comparison should return "in constant time, to protect against timing attacks" | 2026-10-18 |
25
+ | Expire and revoke on the server | [Session Management](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html): "Session timeout management and expiration must be enforced server-side", and "deleting a cookie alone does not invalidate a stolen copy" | 2026-10-18 |
26
+
27
+ ## Secrets
28
+
29
+ | Bullet | Source | Read |
30
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
31
+ | Secrets at runtime | [Secrets Management](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html): "It is even better when the consumer of the secret retrieves the secret", or an orchestrator injects it as an environment variable | 2026-10-18 |
32
+ | Never commit a secret | [Secrets Management](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) names the failure: secrets "hardcoded within the source code in plaintext" | 2026-10-18 |
33
+ | Nothing internal in a response | [Error Handling](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html): a response should "not provide any content as part of the response that would reveal implementation details" | 2026-10-18 |
34
+
35
+ ## Abuse limits
36
+
37
+ | Bullet | Source | Read |
38
+ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
39
+ | Rate-limit costly endpoints | [API4:2023](https://api-security.owasp.org/editions/2023/en/0xa4-unrestricted-resource-consumption): "Implement a limit on how often a client can interact with the API within a defined timeframe", and "Configure spending limits for all service providers" | 2026-10-18 |
40
+ | Body size and timeout | [API4:2023](https://api-security.owasp.org/editions/2023/en/0xa4-unrestricted-resource-consumption): "Define and enforce a maximum size of data on all incoming parameters and payloads", with missing "Execution timeouts" listed as a weakness | 2026-10-18 |
41
+ | Bound pagination | [API4:2023](https://api-security.owasp.org/editions/2023/en/0xa4-unrestricted-resource-consumption): validate the parameter "that controls the number of records to be returned in the response" | 2026-10-18 |
42
+
43
+ ## Transport
44
+
45
+ | Bullet | Source | Read |
46
+ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
47
+ | TLS, and fail plaintext API calls | [Transport Layer Security](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html): "API endpoints should fail requests made over unencrypted HTTP connections instead of redirecting them" | 2026-10-18 |
48
+ | Explicit CORS origins | [MDN CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS): for a credentialed request the server "must not specify the `*` wildcard", and reflecting the origin is a house choice, since it grants every origin the wildcard was refused for | 2026-10-18 |
49
+
50
+ ## Declined
51
+
52
+ Every bullet the rewrite removed or reshaped, grouped by why.
53
+
54
+ ### Contradicted by the docs
55
+
56
+ - Reworded "serve every route over TLS and reject plaintext requests". The TLS cheat sheet allows a public site to redirect port 80 to HTTPS, and requires the refusal for an API endpoint only.
57
+
58
+ ### Merged or reworded
59
+
60
+ - Narrowed "hash passwords with a memory-hard algorithm" to the order the password storage page gives, since bcrypt is not memory-hard and the page still lists it.
61
+ - Reworded "restrict CORS to an explicit origin list, never pair a wildcard with credentials" to the wording `framework/fastapi.md` uses, keeping the ban on reflecting the origin.
62
+ - Added stack traces to the response bullet, the leak the error handling page shows first.
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: Web security rule ledger
3
+ description: Sources for governance/rules/lib/security-web.md, one row per bullet
4
+ ---
5
+
6
+ # Web security rule ledger
7
+
8
+ The field is web application security in the browser, and the authorities are the OWASP Cheat Sheet Series and MDN. The two disagreed on `target="_blank"`, and MDN was kept, since it states what browsers do and the extra attribute adds nothing a current browser lacks.
9
+
10
+ ## Content sanitization
11
+
12
+ | Bullet | Source | Read |
13
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | DOMPurify before raw HTML | [XSS Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) lists "React's `dangerouslySetInnerHTML` without sanitizing the HTML" as an unsafe escape hatch, and "OWASP recommends DOMPurify for HTML Sanitization" | 2026-10-18 |
15
+ | Allow-list URL schemes | [XSS Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html): React blocking `javascript:` URLs "does not replace application-specific URL validation", which allows only http and HTTPS | 2026-10-18 |
16
+
17
+ ## Input validation
18
+
19
+ | Bullet | Source | Read |
20
+ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
21
+ | Parse URL params through a schema | House choice: a URL parameter is a string the visitor writes, and one read unparsed reaches rendering or a request in whatever shape it arrived | 2026-10-18 |
22
+
23
+ ## Storage and tokens
24
+
25
+ | Bullet | Source | Read |
26
+ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
27
+ | Nothing sensitive in web storage | [HTML5 Security](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html): "Do not store session identifiers in local storage as the data is always accessible by JavaScript" | 2026-10-18 |
28
+ | Tokens in `HttpOnly` cookies | [Session Management](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html): the `HttpOnly` flag "is mandatory to prevent session ID stealing through XSS attacks" | 2026-10-18 |
29
+
30
+ ## Third-party scripts
31
+
32
+ | Bullet | Source | Read |
33
+ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
34
+ | Pinned, with `integrity` | [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity): it lets browsers "verify that resources they fetch (for example, from a CDN) are delivered without unexpected manipulation" | 2026-10-18 |
35
+
36
+ ## Declined
37
+
38
+ Every bullet the rewrite removed or reshaped, grouped by why.
39
+
40
+ ### Contradicted by the docs
41
+
42
+ - Cut "add `rel="noopener noreferrer"` to all external links with `target="_blank"`". [MDN noopener](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener) says `target="_blank"` "implicitly provides the same `rel` behavior as setting `rel="noopener"`". The [HTML5 Security](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html) page still asks for it, and MDN was kept as the newer statement of browser behavior.
43
+
44
+ ### Merged or reworded
45
+
46
+ - Merged "never use `dangerouslySetInnerHTML` without sanitization" into the DOMPurify bullet, and named `innerHTML` and Astro's `set:html`, since the rule loads on `.html` and `.astro` files too.
47
+ - Reworded "audit and pin versions for all third-party scripts" to the `integrity` attribute, which makes the pin checkable.
48
+
49
+ ### Gaps filled
50
+
51
+ - Added the URL scheme bullet. The XSS page names `javascript:` URLs as the hole sanitizing markup leaves.
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: TanStack Query rule ledger
3
+ description: Sources for governance/rules/lib/tanstack-query.md, one row per bullet
4
+ ---
5
+
6
+ # TanStack Query rule ledger
7
+
8
+ The field is client-side data fetching in React, and the authority is the TanStack Query documentation at tanstack.com. The pages read are the latest docs, which name no major but deprecate `prefetchQuery`, so the prefetch bullet names the route loader rather than either method. `queryOptions()` needs TanStack Query 5 or later.
9
+
10
+ ## Query conventions
11
+
12
+ | Bullet | Source | Read |
13
+ | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
14
+ | `queryOptions()` at every site | [Query options](https://tanstack.com/query/latest/docs/framework/react/guides/query-options): it lets you "share `queryKey` and `queryFn` between multiple places", with "type inference and type safety for all of them" | 2026-10-18, latest |
15
+ | Every variable in the key | [Query keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys): "If your query function depends on a variable, include it in your query key" | 2026-10-18, latest |
16
+ | `staleTime` per query | [Important defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults): queries "consider cached data as stale" by default, and setting `staleTime` is "the recommended way to avoid excessive refetches" | 2026-10-18, latest |
17
+ | Throw on a non-`ok` response | [Query functions](https://tanstack.com/query/latest/docs/framework/react/guides/query-functions): a query function "must throw or return a rejected Promise", and `fetch` does not "throw errors by default" | 2026-10-18, latest |
18
+
19
+ ## Mutations
20
+
21
+ | Bullet | Source | Read |
22
+ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
23
+ | Writes through `useMutation` | House choice: a write outside a mutation has no pending or error state and invalidates nothing, so the cache keeps serving what the write replaced | 2026-10-18, latest |
24
+ | Invalidate in `onSuccess` | [Invalidations from mutations](https://tanstack.com/query/latest/docs/framework/react/guides/invalidations-from-mutations): "Returning a Promise on `onSuccess` makes sure the data is updated before the mutation is entirely complete" | 2026-10-18, latest |
25
+ | `onError` with visible feedback | House choice: a failed write with no handler leaves the screen showing the edit as if it saved | 2026-10-18, latest |
26
+
27
+ ## Cache management
28
+
29
+ | Bullet | Source | Read |
30
+ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
31
+ | Prefetch in the route loader | [Prefetching](https://tanstack.com/query/latest/docs/framework/react/guides/prefetching): a loader starts a route's data ahead of render, with "Fetch comments asap, but don't block or throw errors" | 2026-10-18, latest |
32
+
33
+ ## Separation of concerns
34
+
35
+ | Bullet | Source | Read |
36
+ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
37
+ | Pure query functions | [Important defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults): stale queries refetch when "The window is refocused" and "The network is reconnected", so a side effect fires on each | 2026-10-18, latest |
38
+ | `enabled`, not `useEffect` | [Dependent queries](https://tanstack.com/query/latest/docs/framework/react/guides/dependent-queries): "using the `enabled` option to tell a query when it is ready to run" | 2026-10-18, latest |
39
+
40
+ ## Declined
41
+
42
+ Every bullet the rewrite removed or reshaped, grouped by why.
43
+
44
+ ### Contradicted by the docs
45
+
46
+ - Reworded "prefetch predictable navigations with `queryClient.prefetchQuery`". The [prefetching guide](https://tanstack.com/query/latest/docs/framework/react/guides/prefetching) calls `prefetchQuery` "now deprecated", and a target on an older major still has it, so the bullet names the loader alone.
47
+
48
+ ### Merged or reworded
49
+
50
+ - Merged "define query keys as `readonly` tuple constants", "co-locate query keys with their query functions", and "encapsulate each query in a custom `use*Query` hook" into the `queryOptions()` bullet, the helper the docs name for sharing a key with its function.
51
+ - Merged "never mutate data outside the mutation lifecycle" into the `useMutation` bullet.
52
+ - Merged "use `invalidateQueries` over `setQueryData` unless implementing optimistic updates" into the `onSuccess` bullet.
53
+
54
+ ### Gaps filled
55
+
56
+ - Added the bullet putting every variable in the key, the stale-data bug the query keys page warns about.
57
+ - Added the bullet throwing on a response that is not `ok`, since a `fetch` query function otherwise caches an error body as data.
@@ -0,0 +1,43 @@
1
+ ---
2
+ title: Test scope rule ledger
3
+ description: Sources for governance/rules/lib/test-scope.md, one row per bullet
4
+ ---
5
+
6
+ # Test scope rule ledger
7
+
8
+ The field is browser test automation, and the authority is the Playwright documentation, read at playwright.dev and from its source in the microsoft/playwright repository. The rule ships to every Playwright target, so it names the Playwright CLI rather than a package script a target may not carry. None of the pages read names a Playwright major, so the rows record the read date alone.
9
+
10
+ ## Selecting a run
11
+
12
+ | Bullet | Source | Read |
13
+ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Narrow by path or name, never engine | House choice: a run narrowed to one engine passes while another engine fails, and the gap surfaces only in CI | 2026-10-18 |
15
+ | One test by name | [Command line](https://raw.githubusercontent.com/microsoft/playwright/main/docs/src/test-cli-js.md): `-g` will "Only run tests matching this regular expression" | 2026-10-18 |
16
+ | One surface by path | [Command line](https://raw.githubusercontent.com/microsoft/playwright/main/docs/src/test-cli-js.md): "Run a single test file" by passing its path | 2026-10-18 |
17
+ | `--only-changed` | [Command line](https://raw.githubusercontent.com/microsoft/playwright/main/docs/src/test-cli-js.md): "Only run test files that have been changed between 'HEAD' and 'ref'" | 2026-10-18 |
18
+ | Whole suite before push | House choice: a narrowed run skips the specs a change broke without touching, which the push would hand to CI | 2026-10-18 |
19
+ | `--project` only to reproduce | [Command line](https://raw.githubusercontent.com/microsoft/playwright/main/docs/src/test-cli-js.md): `--project` will "Only run tests from the specified list of projects", where the default is to "run all projects" | 2026-10-18 |
20
+ | No one-engine script | House choice: a script pinning one engine becomes the run everyone types, which is the engine narrowing the first bullet bans | 2026-10-18 |
21
+
22
+ ## Instruments
23
+
24
+ | Bullet | Source | Read |
25
+ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
26
+ | A script, not the suite | House choice: a suite run answers a question about the page only through assertions written for another question, and costs the whole run | 2026-10-18 |
27
+ | No `fullyParallel` | [Parallelism](https://playwright.dev/docs/test-parallel): by default "Tests in a single file are run in order, in the same worker process", and parallel tests "cannot share any state or global variables" | 2026-10-18 |
28
+ | Pointer to `surface-capture` | House choice: a pointer to the rule that owns capture scope, claiming no practice of its own | 2026-10-18 |
29
+ | Pointer to `e2e-reliability` | House choice: a pointer to the rule that owns waits and guards, claiming no practice of its own | 2026-10-18 |
30
+
31
+ ## Declined
32
+
33
+ Every bullet the rewrite removed or reshaped, grouped by why.
34
+
35
+ ### A script a target may lack
36
+
37
+ - Replaced `bun run test:e2e -- -g '<name>'` with `playwright test -g '<name>'`. The `test:e2e` scripts are this toolkit's alone, and the rule ships to every Playwright target.
38
+ - Replaced `bun run test:e2e -- e2e/<area>.spec.ts` with the CLI's path argument.
39
+ - Replaced `bun run test:e2e:changed`, which selected specs from the import graph, with `--only-changed`, the CLI's own selection by git diff.
40
+
41
+ ### Merged or reworded
42
+
43
+ - Named the Playwright config in the `fullyParallel` bullet rather than the `playwright.config.ts` filename, since a target may write the config in JavaScript.
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: Go testing rule ledger
3
+ description: Sources for governance/rules/lib/testing-go.md, one row per bullet
4
+ ---
5
+
6
+ # Go testing rule ledger
7
+
8
+ The field is Go testing, and the authorities are the `testing` and `net/http/httptest` package documentation at pkg.go.dev, the Go wiki at go.dev, and the race detector article. None of the pages read names a Go release beyond a 1.22 loop-variable note, so the rows record the read date alone.
9
+
10
+ ## Layer
11
+
12
+ | Bullet | Source | Read |
13
+ | ----------------------- | --------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Load `test-craft` first | House choice: a pointer to the skill that owns the choice of layer, claiming no practice of its own | 2026-10-18 |
15
+
16
+ ## Framework
17
+
18
+ | Bullet | Source | Read |
19
+ | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
20
+ | Standard `testing`, no assert library | [Go test comments](https://go.dev/wiki/TestComments): "Avoid the use of 'assert' libraries to help your tests", which "make it too easy to write imprecise tests" | 2026-10-18 |
21
+ | External `_test` package | [Package testing](https://pkg.go.dev/testing): a test file in a package with the "_test" suffix is black-box, where "the package being tested must be imported explicitly" | 2026-10-18 |
22
+
23
+ ## Table-driven cases
24
+
25
+ | Bullet | Source | Read |
26
+ | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
27
+ | Slice of structs through `t.Run` | [Table driven tests](https://go.dev/wiki/TableDrivenTests): "Each table entry is a complete test case with inputs and expected results" | 2026-10-18 |
28
+ | A `name` per case | [Package testing](https://pkg.go.dev/testing): "Run runs f as a subtest of t called name", which is how a failure names its case | 2026-10-18 |
29
+
30
+ ## Helpers and setup
31
+
32
+ | Bullet | Source | Read |
33
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
34
+ | `t.Helper()` first | [Package testing](https://pkg.go.dev/testing): "Helper marks the calling function as a test helper function", skipped when printing file and line | 2026-10-18 |
35
+ | `t.Cleanup` over `defer` | [Package testing](https://pkg.go.dev/testing): Cleanup runs "when the test (or subtest) and all its subtests complete" | 2026-10-18 |
36
+ | `t.TempDir` and `t.Setenv` | [Package testing](https://pkg.go.dev/testing): the directory is removed when the test finishes, and Setenv "uses Cleanup to restore the environment variable" | 2026-10-18 |
37
+ | `httptest` over a listener | [Package httptest](https://pkg.go.dev/net/http/httptest): "NewServer starts and returns a new Server listening on a local network loopback interface" | 2026-10-18 |
38
+
39
+ ## Concurrency
40
+
41
+ | Bullet | Source | Read |
42
+ | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
43
+ | No `time.Sleep` sync | House choice: a sleep long enough on one machine is too short on a loaded runner, so the test fails with no defect in the code | 2026-10-18 |
44
+ | `-race` | [Data race detector](https://go.dev/doc/articles/race_detector): "add the `-race` flag to the go command", as in `go test -race mypkg` | 2026-10-18 |
45
+ | `t.Parallel()` without shared state | [Table driven tests](https://go.dev/wiki/TableDrivenTests): "Parallelizing table tests is simple, but requires precision to avoid bugs" | 2026-10-18 |
46
+
47
+ ## Declined
48
+
49
+ Every bullet the rewrite removed or reshaped, grouped by why.
50
+
51
+ ### A default the toolchain already applies
52
+
53
+ - Cut "place a test beside the code it tests, in a `_test.go` file of the same package". The `go` tool finds tests only in `_test.go` files, and Claude writes them that way unprompted.
54
+
55
+ ### Merged or reworded
56
+
57
+ - Gave the `t.Cleanup` bullet its reason, a `defer` in a helper firing as the helper returns.
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: PHP testing rule ledger
3
+ description: Sources for governance/rules/lib/testing-php.md, one row per bullet
4
+ ---
5
+
6
+ # PHP testing rule ledger
7
+
8
+ The field is PHP testing, and the authority is the PHPUnit documentation at docs.phpunit.de with its release announcements at phpunit.de. The manual pages read are the PHPUnit 12.4 edition. Attributes arrived in PHPUnit 10, so the attribute bullet names that floor and a PHPUnit 9 target is never told to use them.
9
+
10
+ ## Layer
11
+
12
+ | Bullet | Source | Read |
13
+ | ----------------------- | --------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Load `test-craft` first | House choice: a pointer to the skill that owns the choice of layer, claiming no practice of its own | 2026-10-18 |
15
+
16
+ ## Framework
17
+
18
+ | Bullet | Source | Read |
19
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
20
+ | PHPUnit as the runner | House choice: the toolkit's PHP stack configures PHPUnit, so a test written for a second runner never runs in the gate | 2026-10-18, PHPUnit 12.4 |
21
+ | `final`, extending `TestCase` | [Writing tests](https://docs.phpunit.de/en/12.4/writing-tests-for-phpunit.html): "`GreeterTest` inherits from `PHPUnit\Framework\TestCase`", and every example class is declared `final` | 2026-10-18, PHPUnit 12.4 |
22
+
23
+ ## Attributes
24
+
25
+ | Bullet | Source | Read |
26
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
27
+ | Attributes over annotations | [PHPUnit 12 announcement](https://phpunit.de/announcements/phpunit-12.html): "Support for using annotations has now been removed", and the [PHPUnit 10 announcement](https://phpunit.de/announcements/phpunit-10.html): "PHPUnit 10 introduces support for PHP 8 attributes" | 2026-10-18, PHPUnit 12 |
28
+ | `public static` data provider | [Writing tests](https://docs.phpunit.de/en/12.4/writing-tests-for-phpunit.html): "A data provider method must be `public` and `static` and its name must not start with `test`" | 2026-10-18, PHPUnit 12.4 |
29
+
30
+ ## Assertions and doubles
31
+
32
+ | Bullet | Source | Read |
33
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
34
+ | `assertSame` over `assertEquals` | [Assertions](https://docs.phpunit.de/en/12.4/assertions.html): `assertSame()` fails when the values "do not have the same type and value", while `assertEquals()` compares with `==` | 2026-10-18, PHPUnit 12.4 |
35
+ | `expectException` first | [Writing tests](https://docs.phpunit.de/en/12.4/writing-tests-for-phpunit.html): "The `expectException()` method has to be used **before** the exception you expect to be thrown is thrown" | 2026-10-18, PHPUnit 12.4 |
36
+ | Stub unless asserting a call | [Test doubles](https://docs.phpunit.de/en/12.4/test-doubles.html): a stub "(optionally) returns configured return values", and a mock "verifies expectations, for instance asserting that a method has been called" | 2026-10-18, PHPUnit 12.4 |
37
+ | No real network calls | House choice: a test reaching the network fails on an outage or a rate limit with no defect in the code under test | 2026-10-18 |
38
+
39
+ ## Declined
40
+
41
+ Every bullet the rewrite removed or reshaped, grouped by why.
42
+
43
+ ### Cut without a source or a bug class
44
+
45
+ - Cut "place tests under `tests/`, mirroring the `src/` namespace layout, in files named `*Test.php`" as a layout call, which the `codebase-layout` skill owns. The PHPUnit manual shows the layout in examples and states no rule.
46
+
47
+ ### Merged or reworded
48
+
49
+ - Prefixed the attribute bullet with "On PHPUnit 10 or later", since attributes do not exist before it.
50
+ - Named `public static` in the data provider bullet, the signature the manual requires.
51
+ - Reworded the `expectException` bullet to the ordering the manual stresses.
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: Python testing rule ledger
3
+ description: Sources for governance/rules/lib/testing-py.md, one row per bullet
4
+ ---
5
+
6
+ # Python testing rule ledger
7
+
8
+ The field is Python testing, and the authorities are the pytest documentation at docs.pytest.org and the pytest-asyncio documentation. The pytest pages name no major beyond a feature added in 9.0, and the pytest-asyncio page names none, so the rows record the read date alone.
9
+
10
+ ## Framework
11
+
12
+ | Bullet | Source | Read |
13
+ | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | Plain functions, no `TestCase` | [unittest.TestCase support](https://docs.pytest.org/en/stable/how-to/unittest.html): in a `TestCase` subclass, regular fixtures and parametrization do not work, "and likely never will" | 2026-10-18 |
15
+
16
+ ## Fixtures
17
+
18
+ | Bullet | Source | Read |
19
+ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
20
+ | Yield fixtures for teardown | [Fixtures](https://docs.pytest.org/en/stable/how-to/fixtures.html): "yield fixtures are considered to be the cleaner and more straightforward option" | 2026-10-18 |
21
+ | Narrowest `conftest.py` | [Fixtures](https://docs.pytest.org/en/stable/how-to/fixtures.html): in a `conftest.py`, "tests from multiple test modules in the directory can access the fixture function" | 2026-10-18 |
22
+ | Widen scope only for unmutated state | [Fixtures](https://docs.pytest.org/en/stable/how-to/fixtures.html): "`function`: the default scope, the fixture is destroyed at the end of the test", so a wider scope hands one object to every test in it | 2026-10-18 |
23
+ | `tmp_path` and `monkeypatch` | [tmp_path](https://docs.pytest.org/en/stable/how-to/tmp_path.html) is "a temporary directory unique to each test function", and with [monkeypatch](https://docs.pytest.org/en/stable/how-to/monkeypatch.html) "All modifications will be undone after the requesting test function or fixture has finished" | 2026-10-18 |
24
+
25
+ ## Parametrize
26
+
27
+ | Bullet | Source | Read |
28
+ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
29
+ | `parametrize` for tables | [Parametrizing tests](https://docs.pytest.org/en/stable/how-to/parametrize.html): it "enables parametrization of arguments for a test function" | 2026-10-18 |
30
+
31
+ ## Async
32
+
33
+ | Bullet | Source | Read |
34
+ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
35
+ | Mark async tests or go auto | [pytest-asyncio concepts](https://pytest-asyncio.readthedocs.io/en/latest/concepts.html): "In strict mode pytest-asyncio will only run tests that have the _asyncio_ marker", and strict "is the default mode" | 2026-10-18 |
36
+ | The plugin's event loop | [pytest-asyncio concepts](https://pytest-asyncio.readthedocs.io/en/latest/concepts.html): "Pytest-asyncio provides one asyncio event loop for each pytest collector" | 2026-10-18 |
37
+
38
+ ## Assertions and mocks
39
+
40
+ | Bullet | Source | Read |
41
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
42
+ | Plain `assert` | [Assertions](https://docs.pytest.org/en/stable/how-to/assert.html): failure details come from "rewriting assert statements before they are run" | 2026-10-18 |
43
+ | `pytest.raises` | [Assertions](https://docs.pytest.org/en/stable/how-to/assert.html): you "can use pytest.raises() as a context manager" for an expected exception | 2026-10-18 |
44
+ | Patch through a fixture | [monkeypatch](https://docs.pytest.org/en/stable/how-to/monkeypatch.html): it "helps you to safely set/delete an attribute", undone after the test, where a hand assignment leaks into later tests | 2026-10-18 |
45
+ | No real network calls | House choice: a test reaching the network fails on an outage or a rate limit with no defect in the code under test | 2026-10-18 |
46
+
47
+ ## Declined
48
+
49
+ Every bullet the rewrite removed or reshaped, grouped by why.
50
+
51
+ ### A default pytest already applies
52
+
53
+ - Cut "name files `test_*.py` and test functions `test_*`". [Good practices](https://docs.pytest.org/en/stable/explanation/goodpractices.html) states it as pytest's default discovery, and Claude names tests that way unprompted.
54
+ - Narrowed "set `scope=` explicitly when reuse matters" to the one case a wider scope breaks, since `function` is already the default.
55
+
56
+ ### Cut without a source or a bug class
57
+
58
+ - Cut "place tests under `tests/`, mirroring the `src/` package layout" as a layout call, which the `codebase-layout` skill owns. Good practices says only that a separate directory "might be useful".
59
+ - Cut "use `ids=` to label parametrized cases when their repr is unclear" as readability naming no failure.
60
+ - Cut "arrange, act, assert per test, with one logical assertion group" as test structure, which the `test-craft` skill owns.
61
+ - Cut "use descriptive `test_*` names that read as the assertion, never `should_`" as naming style naming no failure.
62
+
63
+ ### Merged or reworded
64
+
65
+ - Merged "use `pytest` for all tests, never `unittest.TestCase`" with the reason the unittest page gives.
66
+ - Reworded "do not start a fresh event loop inside tests" to name the loop the plugin provides and the calls that bypass it.
67
+ - Replaced `httpx_mock`, a fixture name, with `pytest-httpx`, the package that provides it.