@event4u/agent-config 14.10.0 → 14.11.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 (399) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +335 -0
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/design.md +88 -0
  7. package/dist/agent-src/commands/project/analyze.md +47 -0
  8. package/dist/agent-src/commands/review/changes.md +67 -6
  9. package/dist/agent-src/commands/roadmap/create.md +49 -0
  10. package/dist/agent-src/commands/roadmap/next.md +27 -11
  11. package/dist/agent-src/commands/roadmap/process-full.md +14 -0
  12. package/dist/agent-src/commands/video/from-script.md +60 -3
  13. package/dist/agent-src/commands/video/stitch.md +14 -0
  14. package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
  15. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
  16. package/dist/agent-src/rules/active-remediation.md +3 -3
  17. package/dist/agent-src/rules/code-provenance.md +2 -2
  18. package/dist/agent-src/rules/context-hygiene.md +13 -33
  19. package/dist/agent-src/rules/council-availability.md +2 -2
  20. package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
  21. package/dist/agent-src/rules/design-fidelity.md +18 -0
  22. package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
  23. package/dist/agent-src/rules/evaluator-independence.md +56 -44
  24. package/dist/agent-src/rules/fix-what-you-see.md +9 -1
  25. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  26. package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
  27. package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
  28. package/dist/agent-src/rules/playbook-precedence.md +105 -0
  29. package/dist/agent-src/rules/recurring-criticism.md +3 -1
  30. package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
  31. package/dist/agent-src/rules/scale-discipline.md +24 -0
  32. package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
  33. package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
  34. package/dist/agent-src/rules/ui-audit-gate.md +27 -15
  35. package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
  36. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
  37. package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
  38. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
  39. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
  40. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
  41. package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
  42. package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
  43. package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
  44. package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
  45. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
  46. package/dist/agent-src/skills/brand/SKILL.md +3 -0
  47. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
  48. package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
  49. package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
  50. package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
  51. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
  52. package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
  53. package/dist/agent-src/skills/code-review/SKILL.md +11 -0
  54. package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
  55. package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
  56. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  57. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
  58. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
  59. package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
  60. package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
  61. package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
  62. package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
  63. package/dist/agent-src/skills/design-review/SKILL.md +79 -1
  64. package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
  65. package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
  66. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
  67. package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
  68. package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
  69. package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
  70. package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
  71. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
  72. package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
  73. package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
  74. package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
  75. package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
  76. package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
  77. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  78. package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
  79. package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
  80. package/dist/agent-src/skills/iconography/SKILL.md +3 -0
  81. package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
  82. package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
  83. package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
  84. package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
  85. package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
  86. package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
  87. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
  88. package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
  89. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
  90. package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
  91. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
  92. package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
  93. package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
  94. package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
  95. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
  96. package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
  97. package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
  98. package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
  99. package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
  100. package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
  101. package/dist/agent-src/skills/override-management/SKILL.md +3 -0
  102. package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
  103. package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
  104. package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
  105. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
  106. package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
  107. package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
  108. package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
  109. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
  110. package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
  111. package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
  112. package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
  113. package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
  114. package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
  115. package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
  116. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  117. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  118. package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
  119. package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
  120. package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
  121. package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
  122. package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
  123. package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
  124. package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
  125. package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
  126. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
  127. package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
  128. package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
  129. package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
  130. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
  131. package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
  132. package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
  133. package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
  134. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  135. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
  136. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
  137. package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
  138. package/dist/agent-src/skills/terraform/SKILL.md +3 -0
  139. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
  140. package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
  141. package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
  142. package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
  143. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
  144. package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
  145. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
  146. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
  147. package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
  148. package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
  149. package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
  150. package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
  151. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  152. package/dist/agent-src/templates/playbook.md +75 -0
  153. package/dist/agent-src/templates/roadmaps.md +37 -0
  154. package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  155. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  156. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  157. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  158. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  159. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  160. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  161. package/dist/cli/commands/uiAudit.js +221 -0
  162. package/dist/cli/commands/uiAudit.js.map +1 -0
  163. package/dist/cli/commands/uiRender.js +206 -0
  164. package/dist/cli/commands/uiRender.js.map +1 -0
  165. package/dist/cli/main.js +22 -1
  166. package/dist/cli/main.js.map +1 -1
  167. package/dist/cli/mcp/content.js +64 -1
  168. package/dist/cli/mcp/content.js.map +1 -1
  169. package/dist/cli/mcp/dispatch.js +175 -10
  170. package/dist/cli/mcp/dispatch.js.map +1 -1
  171. package/dist/cli/registry.js +3 -0
  172. package/dist/cli/registry.js.map +1 -1
  173. package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
  174. package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
  175. package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
  176. package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
  177. package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
  178. package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
  179. package/dist/cli-delegate/cmd_brand_status.js +8 -6
  180. package/dist/cli-delegate/cmd_conformance.js +3 -3
  181. package/dist/cli-delegate/cmd_doctor.js +3 -3
  182. package/dist/cli-delegate/cmd_export.js +4 -4
  183. package/dist/cli-delegate/cmd_handoff.js +1 -1
  184. package/dist/cli-delegate/cmd_preflight.js +2 -2
  185. package/dist/cli-delegate/cmd_prune.js +4 -4
  186. package/dist/cli-delegate/cmd_session_recycle.js +70 -9
  187. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  188. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  189. package/dist/cli-delegate/cmd_sync.js +4 -4
  190. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  191. package/dist/cli-delegate/cmd_validate.js +4 -4
  192. package/dist/discovery/deprecation-report.md +1 -1
  193. package/dist/discovery/discovery-manifest.json +359 -124
  194. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  195. package/dist/discovery/discovery-manifest.summary.md +4 -4
  196. package/dist/discovery/dormancy-report.md +1 -1
  197. package/dist/discovery/orphan-report.md +1 -1
  198. package/dist/discovery/packs.json +18 -8
  199. package/dist/discovery/trust-report.md +3 -3
  200. package/dist/discovery/workspaces.json +16 -6
  201. package/dist/hooks/dispatch.js +2337 -1436
  202. package/dist/install/install.mjs +795 -708
  203. package/dist/mcp/registry-manifest.json +3 -3
  204. package/dist/mcp/server.json +2 -2
  205. package/dist/mcp/server.mjs +1685 -1250
  206. package/dist/router.json +1 -1
  207. package/dist/scripts/_lib/lean_projection_mode.js +40 -0
  208. package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
  209. package/dist/scripts/_lib/scoped_projection.js +84 -0
  210. package/dist/scripts/_lib/scoped_projection.js.map +1 -1
  211. package/dist/scripts/_lib/ui_surface.js +89 -0
  212. package/dist/scripts/_lib/ui_surface.js.map +1 -0
  213. package/dist/scripts/condense.js +6 -10
  214. package/dist/scripts/condense.js.map +1 -1
  215. package/dist/scripts/project_thin_rules.js +40 -2
  216. package/dist/scripts/project_thin_rules.js.map +1 -1
  217. package/dist/server/schemas/settings.js +3 -0
  218. package/dist/server/schemas/settings.js.map +1 -1
  219. package/dist/shared/skillRanking.js +159 -0
  220. package/dist/shared/skillRanking.js.map +1 -0
  221. package/docs/contracts/provider-lifecycle.md +47 -18
  222. package/docs/contracts/settings-classes.md +14 -4
  223. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
  224. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  225. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
  226. package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  227. package/docs/guidelines/design-antipatterns.md +4 -2
  228. package/docs/guidelines/design-asset-discipline.md +38 -0
  229. package/docs/guidelines/design-fidelity-mechanics.md +45 -29
  230. package/docs/guidelines/design-handover-extraction.md +35 -5
  231. package/docs/guidelines/design-modes.md +41 -1
  232. package/docs/guidelines/monorepo-antipatterns.md +141 -0
  233. package/llms.txt +50 -39
  234. package/package.json +1 -1
  235. package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  236. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  237. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  238. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  239. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  240. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  241. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  242. package/src/config/agent-settings.template.yml +28 -0
  243. package/src/config/assurance-capability-registry.json +223 -0
  244. package/src/config/assurance-threshold-budget.json +65 -0
  245. package/src/config/ci-local-parity.yml +14 -0
  246. package/src/config/discovery/unassigned-artefacts.yml +2 -0
  247. package/src/config/dispatch-economy-metrics.json +4 -2
  248. package/src/config/evaluator-budgets.json +14 -14
  249. package/src/config/gate-coverage.yml +207 -8
  250. package/src/config/gate-violation-baselines.json +76 -72
  251. package/src/config/hook-latency-budget.json +1 -0
  252. package/src/config/hook-token-budget.json +137 -125
  253. package/src/config/pack-size-budget.json +4 -2
  254. package/src/config/quorum-attendance-budget.json +12 -4
  255. package/src/config/rule-activation-census.json +7 -3
  256. package/src/config/rule-enforcement-baseline.json +0 -1
  257. package/src/config/rule-stub-ceilings.json +112 -91
  258. package/src/scripts/_cli/cmd_doctor.ts +15 -16
  259. package/src/scripts/_cli/doctor_install_mode.ts +49 -0
  260. package/src/scripts/_cli/doctor_overrides.ts +154 -0
  261. package/src/scripts/_dispatch.bash +17 -0
  262. package/src/scripts/_lib/as_of.ts +412 -0
  263. package/src/scripts/_lib/exec_evidence.ts +7 -0
  264. package/src/scripts/_lib/hook_settings.ts +33 -0
  265. package/src/scripts/_lib/host_listing_model.ts +192 -0
  266. package/src/scripts/_lib/lean_projection_mode.ts +44 -0
  267. package/src/scripts/_lib/mcp_bridge.ts +199 -0
  268. package/src/scripts/_lib/review_independence.ts +62 -10
  269. package/src/scripts/_lib/rule_injection.ts +239 -0
  270. package/src/scripts/_lib/run_checkpoint.ts +54 -1
  271. package/src/scripts/_lib/scoped_projection.ts +96 -0
  272. package/src/scripts/_lib/session_register.ts +44 -2
  273. package/src/scripts/_lib/skill_catalogue.ts +38 -2
  274. package/src/scripts/_lib/transcript_reads.ts +207 -0
  275. package/src/scripts/_lib/ui_authority.test.ts +251 -0
  276. package/src/scripts/_lib/ui_authority.ts +343 -0
  277. package/src/scripts/ai-video/adapters/fal.sh +8 -3
  278. package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
  279. package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
  280. package/src/scripts/ai-video/adapters/kling.sh +10 -0
  281. package/src/scripts/ai-video/adapters/sora.sh +10 -0
  282. package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
  283. package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
  284. package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
  285. package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
  286. package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
  287. package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
  288. package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
  289. package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
  290. package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
  291. package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
  292. package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
  293. package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
  294. package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
  295. package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
  296. package/src/scripts/ai-video/smoke-trace.sh +450 -2
  297. package/src/scripts/ai-video/stitch.sh +191 -10
  298. package/src/scripts/ai-video/test-pipeline.sh +84 -6
  299. package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
  300. package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
  301. package/src/scripts/ai_council/clients.ts +3 -2
  302. package/src/scripts/ai_council/consensus.ts +63 -6
  303. package/src/scripts/ai_council/events_log.ts +46 -1
  304. package/src/scripts/ai_council/orchestrator.ts +103 -108
  305. package/src/scripts/ai_council/orchestrator_results.ts +166 -0
  306. package/src/scripts/ai_council/prompts.ts +12 -5
  307. package/src/scripts/ai_council/quorum.ts +82 -1
  308. package/src/scripts/ai_council/quorum_wiring.ts +82 -5
  309. package/src/scripts/ai_council/stance_tally.ts +22 -0
  310. package/src/scripts/bench_hook_latency.ts +62 -0
  311. package/src/scripts/build_proof.ts +12 -1
  312. package/src/scripts/capture_skill_catalogue.ts +21 -0
  313. package/src/scripts/check_always_budget.ts +2 -1
  314. package/src/scripts/check_augmentignore.ts +2 -1
  315. package/src/scripts/check_beta_review_markers.ts +2 -1
  316. package/src/scripts/check_composite_arming.ts +364 -0
  317. package/src/scripts/check_corpus_staleness.ts +2 -1
  318. package/src/scripts/check_council_pin_staleness.ts +3 -1
  319. package/src/scripts/check_enforcement_coverage.ts +116 -3
  320. package/src/scripts/check_enforcement_denominator.ts +365 -0
  321. package/src/scripts/check_gate_coverage.ts +2 -1
  322. package/src/scripts/check_hook_bundle_freshness.ts +13 -1
  323. package/src/scripts/check_knowledge_cards.ts +2 -1
  324. package/src/scripts/check_knowledge_pages.ts +3 -2
  325. package/src/scripts/check_memory.ts +2 -1
  326. package/src/scripts/check_no_automerge_key.ts +287 -0
  327. package/src/scripts/check_pack_conformance_fixture.ts +565 -0
  328. package/src/scripts/check_proposal.ts +2 -1
  329. package/src/scripts/check_reach_staleness.ts +2 -1
  330. package/src/scripts/check_release_adjacent_health.ts +2 -1
  331. package/src/scripts/check_release_pr_shape.ts +5 -0
  332. package/src/scripts/check_review_schema.ts +34 -1
  333. package/src/scripts/check_roadmap_trackable.ts +48 -3
  334. package/src/scripts/check_source_size_budget.ts +2 -1
  335. package/src/scripts/check_standing_payload_delta.ts +505 -0
  336. package/src/scripts/check_trigger_evals.ts +2 -1
  337. package/src/scripts/classify_change_risk.ts +281 -0
  338. package/src/scripts/compute_skill_tiers.ts +186 -0
  339. package/src/scripts/condense.ts +8 -13
  340. package/src/scripts/council_attendance_metrics.ts +183 -0
  341. package/src/scripts/council_cli.ts +10 -8
  342. package/src/scripts/council_parse_rate.ts +116 -0
  343. package/src/scripts/derive_playbooks.ts +406 -0
  344. package/src/scripts/design_slop_rules.test.ts +7 -0
  345. package/src/scripts/design_slop_rules.ts +56 -2
  346. package/src/scripts/dispatch_r2_reviewer.ts +16 -0
  347. package/src/scripts/frontend_corpus_hash.ts +116 -0
  348. package/src/scripts/grade_target_readiness.ts +478 -0
  349. package/src/scripts/hook_manifest.json +1 -1
  350. package/src/scripts/hook_manifest.yaml +97 -16
  351. package/src/scripts/hooks/concern_registry.ts +4 -0
  352. package/src/scripts/hooks/design_pass_hook.ts +356 -0
  353. package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
  354. package/src/scripts/hooks/rule_inject_hook.ts +318 -0
  355. package/src/scripts/hot_context_hook.ts +74 -7
  356. package/src/scripts/install.ts +40 -89
  357. package/src/scripts/lint_adapter_tier.ts +663 -0
  358. package/src/scripts/lint_archived_skills.ts +93 -0
  359. package/src/scripts/lint_budget_ownership.ts +2 -1
  360. package/src/scripts/lint_deterministic_time.ts +470 -0
  361. package/src/scripts/lint_framework_leakage.ts +5 -0
  362. package/src/scripts/lint_handoffs.ts +525 -1
  363. package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
  364. package/src/scripts/lint_marketplace.ts +88 -0
  365. package/src/scripts/lint_media_policy_linkage.ts +140 -1
  366. package/src/scripts/lint_one_off_age.ts +6 -1
  367. package/src/scripts/lint_override_kernel_guard.ts +87 -5
  368. package/src/scripts/lint_roadmap_complexity.ts +56 -0
  369. package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
  370. package/src/scripts/lint_rule_norm_pin.ts +321 -0
  371. package/src/scripts/lint_spawn_payload.ts +42 -5
  372. package/src/scripts/lint_symptom_intake.ts +2 -1
  373. package/src/scripts/mcp_parity_smoke.ts +30 -4
  374. package/src/scripts/mcp_render.ts +66 -1
  375. package/src/scripts/mcp_tool_fingerprint.ts +241 -0
  376. package/src/scripts/measure_risk_class_drift.ts +140 -0
  377. package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
  378. package/src/scripts/media/lib/adapter-common.sh +211 -1
  379. package/src/scripts/media/lib/adapter-contract.md +74 -6
  380. package/src/scripts/model_rule_injection.ts +907 -0
  381. package/src/scripts/project_thin_rules.ts +45 -2
  382. package/src/scripts/release.ts +66 -860
  383. package/src/scripts/release_drill.ts +59 -3
  384. package/src/scripts/release_env.ts +298 -0
  385. package/src/scripts/release_publication.ts +720 -0
  386. package/src/scripts/roadmap_context.ts +778 -0
  387. package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
  388. package/src/scripts/schemas/rule.schema.json +24 -2
  389. package/src/scripts/schemas/skill.schema.json +39 -0
  390. package/src/scripts/schemas/ui-authority.schema.json +114 -0
  391. package/src/scripts/session_register_hook.ts +29 -3
  392. package/src/scripts/sessions_cli.ts +67 -3
  393. package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
  394. package/src/scripts/token_sink_report.ts +239 -0
  395. package/src/scripts/trigger_coverage.ts +122 -3
  396. package/src/scripts/update_counts.ts +7 -3
  397. package/src/scripts/validate_frontmatter.ts +66 -0
  398. package/src/server/schemas/settings.ts +5 -0
  399. package/src/shared/skillRanking.ts +183 -0
@@ -37,8 +37,9 @@ import {
37
37
  type QuorumCommand,
38
38
  type QuorumDispatch,
39
39
  type QuorumEventPhase,
40
+ type StanceAgreement,
40
41
  } from './events_log.js';
41
- import { evaluateQuorum, SOLO_FLOOR_MIN_PRESENT, type QuorumResult } from './quorum.js';
42
+ import { evaluateQuorum, formatAttendanceCaveats, SOLO_FLOOR_MIN_PRESENT, withUnparsed, type QuorumResult } from './quorum.js';
42
43
  import { absentReasonFromCliFailure, classifyCliFailure } from './transport_resolver.js';
43
44
 
44
45
  type Dict = Record<string, unknown>;
@@ -117,6 +118,12 @@ export function _emitQuorumEvent(
117
118
  * absence is what the `false` on every line honestly records.
118
119
  */
119
120
  minPresent?: number;
121
+ /**
122
+ * Phase 3 — whether the seats agreed, when a stance tally ran.
123
+ * Omitted by every caller that ran none, which `appendQuorumEvent`
124
+ * records as `not_tallied` rather than as a bare `false`.
125
+ */
126
+ stanceAgreement?: StanceAgreement;
120
127
  },
121
128
  ): void {
122
129
  appendQuorumEvent({
@@ -128,6 +135,7 @@ export function _emitQuorumEvent(
128
135
  configuredTotal: ctx.configuredTotal ?? quorum.total,
129
136
  result: quorum,
130
137
  ...(ctx.minPresent !== undefined ? { minPresent: ctx.minPresent } : {}),
138
+ ...(ctx.stanceAgreement !== undefined ? { stanceAgreement: ctx.stanceAgreement } : {}),
131
139
  absent: absent.map(
132
140
  (a): QuorumAbsence => ({
133
141
  member: String(a['member'] ?? ''),
@@ -154,9 +162,11 @@ export function _postRunQuorum(
154
162
  members: ExternalAIClient[],
155
163
  responses: CouncilResponse[],
156
164
  ai_cfg: Dict,
165
+ parse_outcomes?: ReadonlyMap<string, string>,
157
166
  ): { quorum: QuorumResult; absent: Dict[] } {
158
167
  const absent: Dict[] = [];
159
168
  let present = 0;
169
+ let unparsed = 0;
160
170
  for (let i = 0; i < members.length; i++) {
161
171
  const m = members[i] as ExternalAIClient;
162
172
  const r = responses[i];
@@ -167,7 +177,33 @@ export function _postRunQuorum(
167
177
  // banner printed `2/2 present` — a single-voice verdict presented as
168
178
  // convergence, on a paid run. An empty answer contributes nothing to a
169
179
  // quorum by definition, whatever the transport thought of it.
180
+ // Step 2.3 — the same argument, one rung further in. The byte check
181
+ // below settles "did the transport deliver anything"; it cannot settle
182
+ // "was what it delivered usable content", and a prose refusal passes it
183
+ // unchanged. So a member whose findings answer reached `parse_failed`
184
+ // is pulled out of `present` into its own bucket rather than folded
185
+ // into `N/N present`. It is NOT merged with the error cases: those are
186
+ // transport failures with an `AbsentReason` taxonomy the absent-member
187
+ // table renders, and re-labelling one of them `unparsed` would lose the
188
+ // auth/timeout/quota distinction. Hence the error branch below wins for
189
+ // a member that both errored and parsed badly — the transport failure
190
+ // is the stronger fact.
191
+ //
192
+ // `parse_outcomes` is optional because the run path derives it AFTER
193
+ // the post-run attendance event is emitted: the event stays a
194
+ // transport-level reading by design, and the rendered artefact is where
195
+ // AC-2 asks for the distinction. A caller with no map gets the exact
196
+ // pre-2.3 behaviour, key-for-key.
170
197
  if (r !== undefined && !r.error && r.text.trim() !== '') {
198
+ if (parse_outcomes?.get(m.name) === 'parse_failed') {
199
+ unparsed += 1;
200
+ absent.push({
201
+ member: m.name,
202
+ reason: 'unparsed',
203
+ detail: 'answer present, no parser could read it',
204
+ });
205
+ continue;
206
+ }
171
207
  present += 1;
172
208
  continue;
173
209
  }
@@ -179,7 +215,46 @@ export function _postRunQuorum(
179
215
  detail: raw,
180
216
  });
181
217
  }
182
- return { quorum: evaluateQuorum(members.length, present, _quorum_setting_from(ai_cfg)), absent };
218
+ return { quorum: evaluateQuorum(members.length, present, _quorum_setting_from(ai_cfg), unparsed), absent };
219
+ }
220
+
221
+ /**
222
+ * Which of the three agreement states a stance tally represents.
223
+ *
224
+ * `undefined` when no tally ran — the emitter records that as `not_tallied`,
225
+ * which is a fact ("nobody asked"), not a `false` that reads as disagreement.
226
+ * Returned as an optional rather than a nullable so the caller can spread it
227
+ * under `exactOptionalPropertyTypes`, where an explicit `undefined` and an
228
+ * absent key are different things.
229
+ */
230
+ export function stanceAgreementOf(
231
+ tally: { consensus: unknown } | null,
232
+ ): StanceAgreement | undefined {
233
+ if (tally === null) {
234
+ return undefined;
235
+ }
236
+ return tally.consensus !== null ? 'consensus' : 'split';
237
+ }
238
+
239
+ /**
240
+ * Re-derive the rendered attendance line once the findings parser has spoken.
241
+ *
242
+ * Lives here rather than at the call site because it is the second half of the
243
+ * split `withUnparsed` documents: the post-run event stays a TRANSPORT-level
244
+ * reading so every rate over `events.log` keeps its denominator, and the
245
+ * rendered artefact is where AC-2 asks for the unparsed distinction. Counting
246
+ * `parse_failed` outcomes is the whole derivation; keeping it next to
247
+ * `_postRunQuorum` keeps both readings in one file.
248
+ */
249
+ export function annotateRenderedQuorum(
250
+ quorum: QuorumResult | null,
251
+ parse_outcomes: ReadonlyMap<string, string> | null | undefined,
252
+ ): QuorumResult | null {
253
+ if (quorum === null || parse_outcomes === null || parse_outcomes === undefined) {
254
+ return quorum;
255
+ }
256
+ const unparsed = Array.from(parse_outcomes.values()).filter((o) => o === 'parse_failed').length;
257
+ return withUnparsed(quorum, unparsed);
183
258
  }
184
259
 
185
260
  /**
@@ -205,7 +280,9 @@ export function _format_quorum_line(q: QuorumResult, phase?: QuorumEventPhase):
205
280
  // a solo answer concludes, and nothing in the line distinguishes "both
206
281
  // members agreed" from "one member answered". The counts were always there;
207
282
  // what was missing is the word that stops a reader inferring convergence.
208
- const degraded =
209
- q.present < q.total ? ` ⚠️ DEGRADED — ${String(q.total - q.present)} member(s) did not answer; this is not convergence.` : '';
210
- return `council:quorum · ${tag}${q.present}/${q.total} present, needed ${q.threshold} — ${verdict}.${degraded}`;
283
+ // Step 2.3 moved the wording into `formatAttendanceCaveats` so this line and
284
+ // its mirror in `orchestrator.ts` cannot drift apart, and added the
285
+ // present-unparsed clause there — see that function for why the two counts
286
+ // are disjoint.
287
+ return `council:quorum · ${tag}${q.present}/${q.total} present, needed ${q.threshold} — ${verdict}.${formatAttendanceCaveats(q)}`;
211
288
  }
@@ -218,6 +218,28 @@ export function tally_stances(
218
218
  * Render the **Vote Tally** verdict section: one line per option, the threshold,
219
219
  * and a cleared-or-escalated line. Deterministic — pure projection of the tally.
220
220
  */
221
+ /**
222
+ * Tally the stance lines of a finished round, or `null` when tallying is off.
223
+ *
224
+ * Wraps the member-shape mapping so a caller does not re-derive it: an errored
225
+ * response has no stance line to read, and the member key is
226
+ * `provider:model` because that is what `parse_stance_line` records. Exists so
227
+ * ONE tally is computed per pass and reused — two tallies over the same
228
+ * responses are two chances to disagree, and the attendance event and the
229
+ * handoff envelope both consume this one.
230
+ */
231
+ export function tallyFromResponses(
232
+ responses: ReadonlyArray<{ provider: string; model: string; text: string; error?: string | null }>,
233
+ enabled: boolean,
234
+ ): StanceTallyResult | null {
235
+ if (!enabled) {
236
+ return null;
237
+ }
238
+ return tally_stances(
239
+ responses.filter((r) => !r.error).map((r) => ({ member: `${r.provider}:${r.model}`, text: r.text })),
240
+ );
241
+ }
242
+
221
243
  export function render_vote_tally(result: StanceTallyResult): string {
222
244
  const lines: string[] = ['### Vote Tally'];
223
245
  if (result.options.length === 0) {
@@ -580,6 +580,58 @@ export function perTurnComposite(
580
580
  };
581
581
  }
582
582
 
583
+ /**
584
+ * A1.1 — append ONE composite reading to the durable store.
585
+ *
586
+ * The bench used to print the composite and discard it, which made
587
+ * `per_turn_composite.arming_precondition` ("at least 10 CI gate readings … from
588
+ * at least 2 distinct runner sessions") impossible to evaluate at all. This is
589
+ * the write half; `check_composite_arming.ts` is the read half.
590
+ *
591
+ * THE SESSION DISCRIMINATOR IS THE LOAD-BEARING FIELD, not the count. The
592
+ * precondition asks for two distinct runner SESSIONS because the instability it
593
+ * excludes was measured on ONE machine — a sibling metric read 44-157 % at n=12
594
+ * and 69-74 % at n=50 there — so twelve readings from one session is exactly the
595
+ * shape the floor rejects, and a bare counter cannot see the difference.
596
+ *
597
+ * A null composite is written as null rather than skipped. Dropping it silently
598
+ * would make the store's own length a lie about how many runs contributed, and
599
+ * the reader needs to distinguish "no run" from "a run whose slots were
600
+ * incomplete" — `perTurnComposite` returns null exactly because a composite over
601
+ * a subset reads LOW, and low is the direction that makes a ceiling look met.
602
+ */
603
+ export function composeReadingRecord(
604
+ composite: { ms: number; parts: Record<string, number> } | null,
605
+ tool_calls: number,
606
+ env: NodeJS.ProcessEnv = process.env,
607
+ ): Record<string, unknown> {
608
+ // In CI a session is the workflow run on a given runner; locally it is the
609
+ // host plus the process's own start, so two consecutive local runs are
610
+ // distinguishable while one run's records stay grouped.
611
+ const ciRun = env['GITHUB_RUN_ID'];
612
+ const session =
613
+ ciRun !== undefined && ciRun !== ''
614
+ ? `gh-${ciRun}-${env['RUNNER_OS'] ?? os.platform()}-${env['GITHUB_RUN_ATTEMPT'] ?? '1'}`
615
+ : `local-${os.hostname()}-${String(process.pid)}`;
616
+ return {
617
+ composite_ms: composite === null ? null : composite.ms,
618
+ parts: composite === null ? null : composite.parts,
619
+ tool_calls,
620
+ session,
621
+ platform: `${os.platform()}-${os.arch()}`,
622
+ node: process.version,
623
+ commit: env['GITHUB_SHA'] ?? null,
624
+ run_id: ciRun ?? null,
625
+ recorded_at: new Date().toISOString(),
626
+ };
627
+ }
628
+
629
+ /** Append one JSONL record. Creates the file and its directory if absent. */
630
+ export function appendReading(storePath: string, record: Record<string, unknown>): void {
631
+ fs.mkdirSync(path.dirname(storePath), { recursive: true });
632
+ fs.appendFileSync(storePath, `${JSON.stringify(record)}\n`, 'utf-8');
633
+ }
634
+
583
635
  interface HistoryEntry {
584
636
  recorded_at: string;
585
637
  invocation_path: InvocationPath;
@@ -895,6 +947,16 @@ export function main(argv: string[] = process.argv.slice(2)): number {
895
947
  : perTurnComposite(results, compositeCfg.tool_calls ?? 10);
896
948
  if (compositeCfg !== undefined) {
897
949
  const calls = compositeCfg.tool_calls ?? 10;
950
+ // A1.1: persist the reading BEFORE the ceiling comparison below, so a run
951
+ // that fails the gate still contributes its number. A store that only
952
+ // gets the passing runs is biased in the direction that makes a ceiling
953
+ // look met, which is the same bias the null-composite rule guards.
954
+ const recIdx = argv.indexOf('--record-composite');
955
+ if (recIdx >= 0) {
956
+ const dest = argv[recIdx + 1] ?? path.join(REPO_ROOT, 'agents', 'evidence', 'hook-composite-readings.jsonl');
957
+ appendReading(dest, composeReadingRecord(composite, calls));
958
+ process.stdout.write(`recorded composite reading → ${path.relative(REPO_ROOT, dest)}\n`);
959
+ }
898
960
  if (composite === null) {
899
961
  process.stdout.write(
900
962
  `ℹ️ per-turn composite not computed — a slot the definition needs is missing from this run\n`,
@@ -24,7 +24,11 @@ import * as path from 'node:path';
24
24
  import { fileURLToPath, pathToFileURL } from 'node:url';
25
25
 
26
26
  import { REPO, LEDGER_REL, load_ledger, pointer_unresolved } from './check_claims.js';
27
- import { collect as collectEnforcement, summarise as summariseEnforcement } from './check_enforcement_coverage.js';
27
+ import {
28
+ collect as collectEnforcement,
29
+ denominator_line as enforcementDenominatorLine,
30
+ summarise as summariseEnforcement,
31
+ } from './check_enforcement_coverage.js';
28
32
  import { collectSkillGaps } from './check_skill_gaps.js';
29
33
  import { loadRows as loadComparisonRows } from './check_comparison.js';
30
34
  import { computeStatus as domainSoundnessStatus } from './domain_soundness_status.js';
@@ -415,6 +419,13 @@ function render(): string {
415
419
  `${s.local_only} local-only · ${s.undeclared} undeclared (no \`enforced_by\` yet).`,
416
420
  );
417
421
  L.push('');
422
+ // The denominator, WITH the frame that produced it. Until 2026-08-23 the
423
+ // tree published five figures for this one property because every one was
424
+ // quoted without saying which population it was taken over. This line is
425
+ // the single sanctioned statement of it, and `check_enforcement_denominator`
426
+ // reds when a published doc restates a count instead of citing this block.
427
+ L.push(`\`${enforcementDenominatorLine(s.frames)}\``);
428
+ L.push('');
418
429
  L.push('| Rule | Effective level | Declared backstop(s) |');
419
430
  L.push('|---|---|---|');
420
431
  const declared = rows
@@ -434,11 +434,32 @@ function runLimitsMode(): number {
434
434
  /** The package's two projection-mode counts, one walk. Shared by both modes. */
435
435
  function projectionModeCounts(): ProjectionModeCounts {
436
436
  const stats = scoped_projection_stats(REPO, iter_skills());
437
+ // The tier split is a per-machine runtime artefact (gitignored), so absent is
438
+ // the normal state and must read as "unmeasured", never as zero.
439
+ let tierACount: number | null = null;
440
+ let tierBCount: number | null = null;
441
+ const tiersFile = path.join(REPO, 'agents', 'runtime', 'state', 'skill-tiers.json');
442
+ if (fs.existsSync(tiersFile)) {
443
+ try {
444
+ const parsed = JSON.parse(fs.readFileSync(tiersFile, 'utf-8')) as {
445
+ tier_a?: unknown;
446
+ tier_b?: unknown;
447
+ };
448
+ if (Array.isArray(parsed.tier_a) && Array.isArray(parsed.tier_b)) {
449
+ tierACount = parsed.tier_a.length;
450
+ tierBCount = parsed.tier_b.length;
451
+ }
452
+ } catch {
453
+ /* a malformed split is an absent split — never a partial count */
454
+ }
455
+ }
437
456
  return {
438
457
  scoped: stats.projected,
439
458
  legacyAll: stats.total,
440
459
  prunedUnderScoped: stats.pruned,
441
460
  activePacks: stats.active_packs,
461
+ tierACount,
462
+ tierBCount,
442
463
  };
443
464
  }
444
465
 
@@ -29,6 +29,7 @@ import process from 'node:process';
29
29
  import { fileURLToPath, pathToFileURL } from 'node:url';
30
30
  import YAML from 'yaml';
31
31
 
32
+ import { asOf } from './_lib/as_of.js';
32
33
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
33
34
 
34
35
  // src/scripts/check_always_budget.ts → parents[2] is the repo root
@@ -435,7 +436,7 @@ function recordTrend(totalExt: number, sizes: Array<[string, number, number]>):
435
436
 
436
437
  /** datetime.now(timezone.utc).isoformat(timespec="seconds") → ...+00:00. */
437
438
  function isoSeconds(): string {
438
- const d = new Date();
439
+ const d = asOf();
439
440
  const pad = (v: number): string => String(v).padStart(2, '0');
440
441
  return (
441
442
  `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}` +
@@ -24,6 +24,7 @@ import * as fs from 'node:fs';
24
24
  import * as path from 'node:path';
25
25
  import { fileURLToPath, pathToFileURL } from 'node:url';
26
26
 
27
+ import { asOfMs } from './_lib/as_of.js';
27
28
  import { assertWatchlistResolves, DeadScopeError } from './_lib/scan_scope.js';
28
29
 
29
30
  const QUIET = process.argv.slice(2).includes('--quiet');
@@ -76,7 +77,7 @@ function check(): number {
76
77
  }
77
78
 
78
79
  const mtimeMs = fs.statSync(target).mtimeMs;
79
- const age_days = (Date.now() - mtimeMs) / 86400000;
80
+ const age_days = (asOfMs() - mtimeMs) / 86400000;
80
81
  if (age_days > STALE_DAYS) {
81
82
  notes.push(
82
83
  `ℹ️ .augmentignore is ${Math.trunc(age_days)} days old (threshold: ${STALE_DAYS}) — ` +
@@ -19,6 +19,7 @@ import * as fs from 'node:fs';
19
19
  import * as path from 'node:path';
20
20
  import { fileURLToPath, pathToFileURL } from 'node:url';
21
21
 
22
+ import { asOf } from './_lib/as_of.js';
22
23
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
23
24
 
24
25
  const _HERE = fileURLToPath(import.meta.url);
@@ -185,7 +186,7 @@ function parse_args(argv: readonly string[]): ParsedArgs {
185
186
 
186
187
  /** Today's date as an ordinal, in local time (mirrors date.today()). */
187
188
  function _todayOrdinal(): number {
188
- const now = new Date();
189
+ const now = asOf();
189
190
  return _dateOrdinal(now.getFullYear(), now.getMonth() + 1, now.getDate());
190
191
  }
191
192