@event4u/agent-config 14.22.0 → 15.0.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 (557) 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 +333 -356
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/agent-handoff.md +8 -7
  7. package/dist/agent-src/commands/agents/init.md +1 -1
  8. package/dist/agent-src/commands/agents/user/accept.md +4 -4
  9. package/dist/agent-src/commands/agents/user/delete.md +2 -2
  10. package/dist/agent-src/commands/agents/user/init.md +3 -3
  11. package/dist/agent-src/commands/agents/user/review.md +3 -3
  12. package/dist/agent-src/commands/agents/user/show.md +3 -3
  13. package/dist/agent-src/commands/agents/user/update.md +2 -2
  14. package/dist/agent-src/commands/agents/user.md +6 -6
  15. package/dist/agent-src/commands/analytics/prune.md +1 -1
  16. package/dist/agent-src/commands/analytics/show.md +2 -2
  17. package/dist/agent-src/commands/analyze/decision.md +2 -2
  18. package/dist/agent-src/commands/analyze/inbox.md +5 -5
  19. package/dist/agent-src/commands/analyze/incident.md +3 -3
  20. package/dist/agent-src/commands/analyze/near-miss.md +3 -3
  21. package/dist/agent-src/commands/analyze/postmortem.md +4 -4
  22. package/dist/agent-src/commands/analyze/premortem.md +2 -2
  23. package/dist/agent-src/commands/analyze.md +2 -2
  24. package/dist/agent-src/commands/bug/fix.md +1 -1
  25. package/dist/agent-src/commands/bug/investigate.md +2 -2
  26. package/dist/agent-src/commands/cost/profile.md +3 -3
  27. package/dist/agent-src/commands/design.md +1 -1
  28. package/dist/agent-src/commands/feature/explore.md +1 -1
  29. package/dist/agent-src/commands/feature/plan.md +2 -2
  30. package/dist/agent-src/commands/feature/roadmap.md +2 -2
  31. package/dist/agent-src/commands/ghostwriter/fetch.md +4 -4
  32. package/dist/agent-src/commands/ghostwriter/list.md +1 -1
  33. package/dist/agent-src/commands/ghostwriter/show.md +1 -1
  34. package/dist/agent-src/commands/ghostwriter/write.md +9 -9
  35. package/dist/agent-src/commands/humanize.md +6 -6
  36. package/dist/agent-src/commands/jira-ticket.md +1 -1
  37. package/dist/agent-src/commands/judge/solo.md +1 -1
  38. package/dist/agent-src/commands/judge.md +1 -1
  39. package/dist/agent-src/commands/knowledge/cross-repo.md +1 -1
  40. package/dist/agent-src/commands/knowledge/forget.md +1 -1
  41. package/dist/agent-src/commands/knowledge/ingest.md +2 -2
  42. package/dist/agent-src/commands/knowledge/list.md +1 -1
  43. package/dist/agent-src/commands/memory/add.md +3 -3
  44. package/dist/agent-src/commands/memory/load.md +4 -4
  45. package/dist/agent-src/commands/memory/mine-session.md +1 -1
  46. package/dist/agent-src/commands/memory/promote.md +4 -4
  47. package/dist/agent-src/commands/memory/propose.md +2 -2
  48. package/dist/agent-src/commands/mode.md +5 -5
  49. package/dist/agent-src/commands/post-as/ghostwriter.md +3 -3
  50. package/dist/agent-src/commands/post-as/me.md +7 -7
  51. package/dist/agent-src/commands/pr/create.md +1 -1
  52. package/dist/agent-src/commands/pr/merge.md +48 -39
  53. package/dist/agent-src/commands/profile/activate.md +1 -1
  54. package/dist/agent-src/commands/profile/show.md +1 -1
  55. package/dist/agent-src/commands/research/deep.md +2 -2
  56. package/dist/agent-src/commands/research/report.md +2 -2
  57. package/dist/agent-src/commands/review/changes.md +1 -1
  58. package/dist/agent-src/commands/review/routing.md +1 -1
  59. package/dist/agent-src/commands/roadmap/create.md +1 -1
  60. package/dist/agent-src/commands/roadmap/materialize.md +2 -2
  61. package/dist/agent-src/commands/roadmap/next.md +9 -1
  62. package/dist/agent-src/commands/roadmap/process-full.md +2 -2
  63. package/dist/agent-src/commands/security-audit-config.md +3 -3
  64. package/dist/agent-src/commands/skill/preview.md +1 -1
  65. package/dist/agent-src/commands/skills/discover.md +1 -1
  66. package/dist/agent-src/commands/sync/agent-settings.md +2 -2
  67. package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
  68. package/dist/agent-src/commands/tests/create.md +1 -1
  69. package/dist/agent-src/commands/tests/e2e-heal.md +1 -1
  70. package/dist/agent-src/commands/tests/e2e-plan.md +1 -1
  71. package/dist/agent-src/contexts/authority/kernel-rule-edits.md +6 -6
  72. package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -2
  73. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +2 -2
  74. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +88 -1
  75. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +1 -1
  76. package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -1
  77. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  78. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  79. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +13 -1
  80. package/dist/agent-src/contexts/execution/cheap-question-mechanics.md +1 -1
  81. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +3 -3
  82. package/dist/agent-src/contexts/execution/mandated-lines.md +1 -1
  83. package/dist/agent-src/contexts/execution/non-interactive-contract.md +1 -1
  84. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -1
  85. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +5 -5
  86. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +1 -1
  87. package/dist/agent-src/contexts/execution/subagent-modes-detail.md +1 -1
  88. package/dist/agent-src/contexts/execution/subagent-routing.md +2 -2
  89. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +1 -1
  90. package/dist/agent-src/contexts/execution/user-memory-channels.md +3 -3
  91. package/dist/agent-src/contexts/execution/verification-mechanics.md +1 -1
  92. package/dist/agent-src/contexts/judges/persona-voice-rubric.md +2 -2
  93. package/dist/agent-src/guidelines/abstraction-thresholds.md +88 -0
  94. package/dist/agent-src/guidelines/agent-infra/5w2h-analysis.md +260 -0
  95. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +99 -0
  96. package/dist/agent-src/guidelines/agent-infra/agent-interaction-and-decision-quality.md +325 -0
  97. package/dist/agent-src/guidelines/agent-infra/api-cost-levers.md +177 -0
  98. package/dist/agent-src/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +222 -0
  99. package/dist/agent-src/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  100. package/dist/agent-src/guidelines/agent-infra/asking-and-brevity-examples.md +198 -0
  101. package/dist/agent-src/guidelines/agent-infra/break-glass-usage.md +113 -0
  102. package/dist/agent-src/guidelines/agent-infra/carve-out-predicates.md +17 -0
  103. package/dist/agent-src/guidelines/agent-infra/comparison-matrix.md +179 -0
  104. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +165 -0
  105. package/dist/agent-src/guidelines/agent-infra/corpus-grounding-authoring.md +91 -0
  106. package/dist/agent-src/guidelines/agent-infra/critical-thinking.md +156 -0
  107. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +109 -0
  108. package/dist/agent-src/guidelines/agent-infra/developer-judgment.md +82 -0
  109. package/dist/agent-src/guidelines/agent-infra/direct-answers-demos.md +142 -0
  110. package/dist/agent-src/guidelines/agent-infra/domain-adoption-gates.md +112 -0
  111. package/dist/agent-src/guidelines/agent-infra/domain-eval-anti-pattern.md +53 -0
  112. package/dist/agent-src/guidelines/agent-infra/domain-pack-architecture.md +56 -0
  113. package/dist/agent-src/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
  114. package/dist/agent-src/guidelines/agent-infra/emphasis-budget.md +45 -0
  115. package/dist/agent-src/guidelines/agent-infra/engineering-memory-data-format.md +210 -0
  116. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  117. package/dist/agent-src/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  118. package/dist/agent-src/guidelines/agent-infra/failure-signatures.md +70 -0
  119. package/dist/agent-src/guidelines/agent-infra/false-green.md +233 -0
  120. package/dist/agent-src/guidelines/agent-infra/first-principles.md +192 -0
  121. package/dist/agent-src/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
  122. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +169 -0
  123. package/dist/agent-src/guidelines/agent-infra/gate-authoring.md +177 -0
  124. package/dist/agent-src/guidelines/agent-infra/guarded-baseline.md +39 -0
  125. package/dist/agent-src/guidelines/agent-infra/installed-tools-manifest.md +142 -0
  126. package/dist/agent-src/guidelines/agent-infra/inversion-thinking.md +388 -0
  127. package/dist/agent-src/guidelines/agent-infra/ios-simulator-guide.md +378 -0
  128. package/dist/agent-src/guidelines/agent-infra/language-and-tone-examples.md +141 -0
  129. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +317 -0
  130. package/dist/agent-src/guidelines/agent-infra/linked-projects-onboarding-gate.md +80 -0
  131. package/dist/agent-src/guidelines/agent-infra/mcp-request-signing.md +197 -0
  132. package/dist/agent-src/guidelines/agent-infra/memory-access.md +149 -0
  133. package/dist/agent-src/guidelines/agent-infra/mental-models.md +314 -0
  134. package/dist/agent-src/guidelines/agent-infra/minimal-safe-diff-mechanics.md +241 -0
  135. package/dist/agent-src/guidelines/agent-infra/missing-tool-handling.md +66 -0
  136. package/dist/agent-src/guidelines/agent-infra/model-recommendation.md +101 -0
  137. package/dist/agent-src/guidelines/agent-infra/naming.md +69 -0
  138. package/dist/agent-src/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  139. package/dist/agent-src/guidelines/agent-infra/output-patterns.md +117 -0
  140. package/dist/agent-src/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  141. package/dist/agent-src/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  142. package/dist/agent-src/guidelines/agent-infra/review-routing-data-format.md +143 -0
  143. package/dist/agent-src/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  144. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +274 -0
  145. package/dist/agent-src/guidelines/agent-infra/role-contracts.md +209 -0
  146. package/dist/agent-src/guidelines/agent-infra/role-mode-router.md +89 -0
  147. package/dist/agent-src/guidelines/agent-infra/rule-body-migration-inventory.md +241 -0
  148. package/dist/agent-src/guidelines/agent-infra/rule-type-governance.md +73 -0
  149. package/dist/agent-src/guidelines/agent-infra/runtime-layer.md +89 -0
  150. package/dist/agent-src/guidelines/agent-infra/scqa-framework.md +526 -0
  151. package/dist/agent-src/guidelines/agent-infra/security-lint-containment.md +121 -0
  152. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +134 -0
  153. package/dist/agent-src/guidelines/agent-infra/simplicity-and-goal-demos.md +211 -0
  154. package/dist/agent-src/guidelines/agent-infra/six-hats.md +353 -0
  155. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +229 -0
  156. package/dist/agent-src/guidelines/agent-infra/skill-quality-checklist.md +157 -0
  157. package/dist/agent-src/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  158. package/dist/agent-src/guidelines/agent-infra/symptom-driven-harvest-loop.md +104 -0
  159. package/dist/agent-src/guidelines/agent-infra/systems-thinking.md +220 -0
  160. package/dist/agent-src/guidelines/agent-infra/tool-description-as-policy.md +35 -0
  161. package/dist/agent-src/guidelines/agent-infra/tool-integration.md +73 -0
  162. package/dist/agent-src/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
  163. package/dist/agent-src/guidelines/agent-infra/untrusted-input-spotlighting.md +166 -0
  164. package/dist/agent-src/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  165. package/dist/agent-src/guidelines/augment-portability-patterns.md +70 -0
  166. package/dist/agent-src/guidelines/code-clarity.md +350 -0
  167. package/dist/agent-src/guidelines/component-oriented-and-oop-development.md +189 -0
  168. package/dist/agent-src/guidelines/cross-role-handoff.md +127 -0
  169. package/dist/agent-src/guidelines/design-antipatterns-triggers.json +18 -0
  170. package/dist/agent-src/guidelines/design-antipatterns.md +327 -0
  171. package/dist/agent-src/guidelines/design-asset-discipline.md +38 -0
  172. package/dist/agent-src/guidelines/design-canon.md +63 -0
  173. package/dist/agent-src/guidelines/design-fidelity-mechanics.md +293 -0
  174. package/dist/agent-src/guidelines/design-fidelity-routing.md +78 -0
  175. package/dist/agent-src/guidelines/design-handover-extraction.md +117 -0
  176. package/dist/agent-src/guidelines/design-modes.md +143 -0
  177. package/dist/agent-src/guidelines/design-reconciliation.md +172 -0
  178. package/dist/agent-src/guidelines/docs/readme-size-and-splitting.md +209 -0
  179. package/dist/agent-src/guidelines/e2e/playwright.md +363 -0
  180. package/dist/agent-src/guidelines/gtm-handoff.md +114 -0
  181. package/dist/agent-src/guidelines/monorepo-antipatterns.md +141 -0
  182. package/dist/agent-src/guidelines/php/api-design.md +115 -0
  183. package/dist/agent-src/guidelines/php/artisan-commands.md +81 -0
  184. package/dist/agent-src/guidelines/php/blade-ui.md +78 -0
  185. package/dist/agent-src/guidelines/php/controllers.md +90 -0
  186. package/dist/agent-src/guidelines/php/database.md +194 -0
  187. package/dist/agent-src/guidelines/php/eloquent.md +208 -0
  188. package/dist/agent-src/guidelines/php/flux.md +80 -0
  189. package/dist/agent-src/guidelines/php/general.md +207 -0
  190. package/dist/agent-src/guidelines/php/git.md +164 -0
  191. package/dist/agent-src/guidelines/php/jobs.md +111 -0
  192. package/dist/agent-src/guidelines/php/livewire.md +71 -0
  193. package/dist/agent-src/guidelines/php/logging.md +79 -0
  194. package/dist/agent-src/guidelines/php/naming.md +89 -0
  195. package/dist/agent-src/guidelines/php/patterns/dependency-injection.md +57 -0
  196. package/dist/agent-src/guidelines/php/patterns/dtos.md +199 -0
  197. package/dist/agent-src/guidelines/php/patterns/events.md +67 -0
  198. package/dist/agent-src/guidelines/php/patterns/factory.md +53 -0
  199. package/dist/agent-src/guidelines/php/patterns/pipelines.md +66 -0
  200. package/dist/agent-src/guidelines/php/patterns/policies.md +66 -0
  201. package/dist/agent-src/guidelines/php/patterns/repositories.md +122 -0
  202. package/dist/agent-src/guidelines/php/patterns/service-layer.md +64 -0
  203. package/dist/agent-src/guidelines/php/patterns/strategy.md +247 -0
  204. package/dist/agent-src/guidelines/php/patterns.md +28 -0
  205. package/dist/agent-src/guidelines/php/performance.md +92 -0
  206. package/dist/agent-src/guidelines/php/php-coding-patterns.md +80 -0
  207. package/dist/agent-src/guidelines/php/resources.md +100 -0
  208. package/dist/agent-src/guidelines/php/security.md +110 -0
  209. package/dist/agent-src/guidelines/php/sql.md +97 -0
  210. package/dist/agent-src/guidelines/php/validations.md +119 -0
  211. package/dist/agent-src/guidelines/php/websocket.md +100 -0
  212. package/dist/agent-src/guidelines/prompt-templates.md +189 -0
  213. package/dist/agent-src/guidelines/redundancy-taxonomy.md +208 -0
  214. package/dist/agent-src/guidelines/wing4-handoff.md +127 -0
  215. package/dist/agent-src/personas/README.md +1 -1
  216. package/dist/agent-src/personas/_template-specialist/persona.md +1 -1
  217. package/dist/agent-src/personas/product-owner.md +1 -1
  218. package/dist/agent-src/rules/active-remediation.md +1 -1
  219. package/dist/agent-src/rules/architecture.md +2 -2
  220. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  221. package/dist/agent-src/rules/ask-when-uncertain.md +2 -2
  222. package/dist/agent-src/rules/brand-source-of-truth.md +9 -7
  223. package/dist/agent-src/rules/code-comment-discipline.md +2 -2
  224. package/dist/agent-src/rules/code-provenance.md +1 -1
  225. package/dist/agent-src/rules/content-quoting-floor.md +1 -1
  226. package/dist/agent-src/rules/context-hygiene.md +5 -5
  227. package/dist/agent-src/rules/cross-source-consistency.md +1 -1
  228. package/dist/agent-src/rules/design-fidelity.md +36 -46
  229. package/dist/agent-src/rules/direct-answers.md +2 -2
  230. package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
  231. package/dist/agent-src/rules/evaluator-independence.md +1 -1
  232. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  233. package/dist/agent-src/rules/icon-consistency.md +5 -1
  234. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  235. package/dist/agent-src/rules/language-and-tone.md +3 -3
  236. package/dist/agent-src/rules/minimal-safe-diff.md +1 -1
  237. package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
  238. package/dist/agent-src/rules/recurring-criticism.md +1 -1
  239. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  240. package/dist/agent-src/rules/role-mode-adherence.md +2 -2
  241. package/dist/agent-src/rules/security-sensitive-stop.md +1 -1
  242. package/dist/agent-src/rules/size-enforcement.md +1 -1
  243. package/dist/agent-src/rules/source-confidentiality.md +2 -2
  244. package/dist/agent-src/rules/think-before-action.md +1 -1
  245. package/dist/agent-src/rules/token-efficiency.md +7 -5
  246. package/dist/agent-src/rules/ui-audit-gate.md +3 -2
  247. package/dist/agent-src/rules/untrusted-input-defense.md +3 -3
  248. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
  249. package/dist/agent-src/skills/activation-design/SKILL.md +2 -2
  250. package/dist/agent-src/skills/adr-create/SKILL.md +5 -5
  251. package/dist/agent-src/skills/ai-council/SKILL.md +1 -1
  252. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +1 -1
  253. package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
  254. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  255. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +24 -3
  256. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  257. package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -1
  258. package/dist/agent-src/skills/churn-prevention/SKILL.md +2 -2
  259. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -1
  260. package/dist/agent-src/skills/code-refactoring/SKILL.md +3 -3
  261. package/dist/agent-src/skills/code-review/SKILL.md +3 -3
  262. package/dist/agent-src/skills/command-writing/SKILL.md +3 -3
  263. package/dist/agent-src/skills/comp-banding/SKILL.md +1 -1
  264. package/dist/agent-src/skills/competitive-moat-analysis/SKILL.md +1 -1
  265. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  266. package/dist/agent-src/skills/complexity-first-planning/SKILL.md +1 -1
  267. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  268. package/dist/agent-src/skills/content-funnel-design/SKILL.md +2 -2
  269. package/dist/agent-src/skills/contracts-cognition/SKILL.md +1 -1
  270. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +2 -2
  271. package/dist/agent-src/skills/corpus-grounding/SKILL.md +2 -2
  272. package/dist/agent-src/skills/customer-research/SKILL.md +2 -2
  273. package/dist/agent-src/skills/dashboard-design/SKILL.md +1 -1
  274. package/dist/agent-src/skills/data-handling-judgment/SKILL.md +1 -1
  275. package/dist/agent-src/skills/deal-qualification-meddic/SKILL.md +2 -2
  276. package/dist/agent-src/skills/decision-record/SKILL.md +3 -3
  277. package/dist/agent-src/skills/decision-review/SKILL.md +8 -8
  278. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +22 -22
  279. package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
  280. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +2 -2
  281. package/dist/agent-src/skills/design-review/SKILL.md +4 -4
  282. package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +20 -1
  283. package/dist/agent-src/skills/design-tokens/SKILL.md +17 -2
  284. package/dist/agent-src/skills/design-variations/SKILL.md +2 -2
  285. package/dist/agent-src/skills/developer-like-execution/SKILL.md +2 -2
  286. package/dist/agent-src/skills/discovery-interview/SKILL.md +2 -2
  287. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +3 -3
  288. package/dist/agent-src/skills/editorial-calendar/SKILL.md +2 -2
  289. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +44 -1
  290. package/dist/agent-src/skills/existing-ui-audit/references/anti-slop-cross-reference.md +2 -2
  291. package/dist/agent-src/skills/expansion-playbook/SKILL.md +2 -2
  292. package/dist/agent-src/skills/experiment-loop/SKILL.md +1 -1
  293. package/dist/agent-src/skills/experiment-loop/references/protocol.md +1 -1
  294. package/dist/agent-src/skills/fe-design/SKILL.md +3 -3
  295. package/dist/agent-src/skills/fe-design/references/design-patterns.md +1 -1
  296. package/dist/agent-src/skills/fe-design/references/design-read-and-memory.md +3 -3
  297. package/dist/agent-src/skills/fe-design/references/source-led-port.md +1 -1
  298. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  299. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  300. package/dist/agent-src/skills/forecast-accuracy/SKILL.md +2 -2
  301. package/dist/agent-src/skills/forecasting/SKILL.md +2 -2
  302. package/dist/agent-src/skills/fundraising-narrative/SKILL.md +2 -2
  303. package/dist/agent-src/skills/funnel-analysis/SKILL.md +2 -2
  304. package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
  305. package/dist/agent-src/skills/gtm-launch/SKILL.md +2 -2
  306. package/dist/agent-src/skills/hiring-loop-design/SKILL.md +1 -1
  307. package/dist/agent-src/skills/html-deck/SKILL.md +5 -5
  308. package/dist/agent-src/skills/humanizer/SKILL.md +1 -1
  309. package/dist/agent-src/skills/humanizer/data/patterns.md +1 -1
  310. package/dist/agent-src/skills/iconography/SKILL.md +3 -3
  311. package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
  312. package/dist/agent-src/skills/laravel-api-endpoint/SKILL.md +2 -2
  313. package/dist/agent-src/skills/launch-readiness/SKILL.md +3 -3
  314. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +6 -6
  315. package/dist/agent-src/skills/livewire/SKILL.md +1 -1
  316. package/dist/agent-src/skills/market-entry-analysis/SKILL.md +1 -1
  317. package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
  318. package/dist/agent-src/skills/memory-consolidation/SKILL.md +3 -3
  319. package/dist/agent-src/skills/messaging-architecture/SKILL.md +2 -2
  320. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  321. package/dist/agent-src/skills/onboarding-design/SKILL.md +2 -2
  322. package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
  323. package/dist/agent-src/skills/one-on-one-cadence/SKILL.md +1 -1
  324. package/dist/agent-src/skills/org-design/SKILL.md +1 -1
  325. package/dist/agent-src/skills/overbuild-review-lens/SKILL.md +3 -3
  326. package/dist/agent-src/skills/override-management/SKILL.md +1 -1
  327. package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
  328. package/dist/agent-src/skills/persona-writing/SKILL.md +1 -1
  329. package/dist/agent-src/skills/php-coder/SKILL.md +1 -1
  330. package/dist/agent-src/skills/pipeline-strategy/SKILL.md +2 -2
  331. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -3
  332. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  333. package/dist/agent-src/skills/positioning-strategy/SKILL.md +2 -2
  334. package/dist/agent-src/skills/privacy-review/SKILL.md +1 -1
  335. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +3 -3
  336. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  337. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -2
  338. package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
  339. package/dist/agent-src/skills/refine-ticket/SKILL.md +2 -2
  340. package/dist/agent-src/skills/release-comms/SKILL.md +2 -2
  341. package/dist/agent-src/skills/retention-loops/SKILL.md +2 -2
  342. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  343. package/dist/agent-src/skills/roadmap-management/SKILL.md +1 -1
  344. package/dist/agent-src/skills/roadmap-management/references/archival.md +1 -1
  345. package/dist/agent-src/skills/roadmap-writing/SKILL.md +5 -5
  346. package/dist/agent-src/skills/rule-writing/SKILL.md +6 -6
  347. package/dist/agent-src/skills/runway-cognition/SKILL.md +2 -2
  348. package/dist/agent-src/skills/scenario-modeling/SKILL.md +2 -2
  349. package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
  350. package/dist/agent-src/skills/skill-writing/references/procedure.md +1 -1
  351. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +3 -3
  352. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +1 -1
  353. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +3 -3
  354. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  355. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +1 -1
  356. package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
  357. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +60 -4
  358. package/dist/agent-src/skills/throughput-vs-morale-tradeoff/SKILL.md +1 -1
  359. package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
  360. package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
  361. package/dist/agent-src/skills/ui-component-architect/SKILL.md +28 -8
  362. package/dist/agent-src/skills/unit-economics-modeling/SKILL.md +2 -2
  363. package/dist/agent-src/skills/upstream-contribute/SKILL.md +1 -1
  364. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  365. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  366. package/dist/agent-src/skills/vision-articulation/SKILL.md +1 -1
  367. package/dist/agent-src/skills/voc-extract/SKILL.md +2 -2
  368. package/dist/agent-src/skills/voice-and-tone-design/SKILL.md +2 -2
  369. package/dist/agent-src/skills/wireframe/SKILL.md +1 -1
  370. package/dist/agent-src/skills/workspace-link/SKILL.md +1 -1
  371. package/dist/agent-src/templates/agent-settings.md +6 -6
  372. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  373. package/dist/agent-src/templates/contexts/knowledge-pages.md +2 -3
  374. package/dist/agent-src/templates/copilot-instructions.md +1 -1
  375. package/dist/agent-src/templates/roadmaps.md +1 -1
  376. package/dist/agent-src/templates/scripts/README.md +2 -2
  377. package/dist/agent-src/user-types/_template/user-type.md +1 -1
  378. package/dist/cli/registry.js +1 -1
  379. package/dist/cli-delegate/archive_completed_roadmaps.js +52 -4
  380. package/dist/cli-delegate/check_update_banner.js +12 -1
  381. package/dist/cli-delegate/{chunk-TGIPZBCW.js → chunk-2KKXJW25.js} +22 -8
  382. package/dist/cli-delegate/{chunk-NLP54U3J.js → chunk-2XY7ILBT.js} +13 -1
  383. package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-3FKR64R5.js} +34 -6
  384. package/dist/cli-delegate/{chunk-J3RFNKG4.js → chunk-55ACLDUE.js} +2 -2
  385. package/dist/cli-delegate/{chunk-PKOBQADP.js → chunk-57PN4GYJ.js} +1 -1
  386. package/dist/cli-delegate/{chunk-BIXEDQPZ.js → chunk-AK6HODNQ.js} +4 -4
  387. package/dist/cli-delegate/{chunk-2FTMENJL.js → chunk-GYC3VRYN.js} +1 -1
  388. package/dist/cli-delegate/{chunk-LWTYTX6F.js → chunk-HZ52BRGG.js} +24 -18
  389. package/dist/cli-delegate/{chunk-6RJA2F5A.js → chunk-IVBPRCQO.js} +1 -1
  390. package/dist/cli-delegate/{chunk-I6RHFQEG.js → chunk-YUM5KURG.js} +17 -1
  391. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  392. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  393. package/dist/cli-delegate/cmd_conformance.js +3 -3
  394. package/dist/cli-delegate/cmd_doctor.js +3 -3
  395. package/dist/cli-delegate/cmd_explain.js +2 -2
  396. package/dist/cli-delegate/cmd_export.js +4 -4
  397. package/dist/cli-delegate/cmd_handoff.js +24 -16
  398. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  399. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  400. package/dist/cli-delegate/cmd_migrate.js +2 -2
  401. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  402. package/dist/cli-delegate/cmd_prune.js +4 -4
  403. package/dist/cli-delegate/cmd_route_audit.js +3 -3
  404. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  405. package/dist/cli-delegate/cmd_session_recycle.js +4 -14
  406. package/dist/cli-delegate/cmd_settings_get.js +15 -9
  407. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  408. package/dist/cli-delegate/cmd_settings_set.js +41 -11
  409. package/dist/cli-delegate/cmd_sync.js +4 -4
  410. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  411. package/dist/cli-delegate/cmd_update.js +1 -1
  412. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  413. package/dist/cli-delegate/cmd_validate.js +4 -4
  414. package/dist/cli-delegate/cmd_versions.js +1 -1
  415. package/dist/discovery/deprecation-report.md +1 -1
  416. package/dist/discovery/discovery-manifest.json +27 -80
  417. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  418. package/dist/discovery/discovery-manifest.summary.md +3 -3
  419. package/dist/discovery/dormancy-report.md +1 -1
  420. package/dist/discovery/orphan-report.md +1 -1
  421. package/dist/discovery/packs.json +5 -7
  422. package/dist/discovery/trust-report.md +2 -2
  423. package/dist/discovery/workspaces.json +4 -6
  424. package/dist/hooks/dispatch.js +9249 -8981
  425. package/dist/install/install.mjs +47 -8
  426. package/dist/mcp/registry-manifest.json +3 -3
  427. package/dist/mcp/server.json +2 -2
  428. package/dist/mcp/server.mjs +5496 -2400
  429. package/dist/router.json +1 -1
  430. package/dist/scripts/_lib/agent_settings.js +73 -0
  431. package/dist/scripts/_lib/agent_src.js +20 -0
  432. package/dist/scripts/_lib/guidelines_lane.js +158 -0
  433. package/dist/scripts/_lib/lean_projection_mode.js +108 -0
  434. package/dist/scripts/_lib/router_match.js +243 -0
  435. package/dist/scripts/_lib/rule_injection.js +216 -0
  436. package/dist/scripts/condense.js +22 -25
  437. package/dist/scripts/project_thin_rules.js +139 -19
  438. package/dist/server/io/yamlIO.js +125 -17
  439. package/dist/server/schemas/settings.js +32 -5
  440. package/dist/shared/settingsSurface.js +6 -1
  441. package/docs/MIGRATION.md +56 -0
  442. package/docs/contracts/settings-classes.md +48 -7
  443. package/docs/guidelines/abstraction-thresholds.md +35 -0
  444. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +3 -3
  445. package/docs/guidelines/agent-infra/false-green.md +2 -2
  446. package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  447. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  448. package/docs/guidelines/agent-infra/skill-quality-checklist.md +1 -1
  449. package/docs/guidelines/design-fidelity-mechanics.md +4 -0
  450. package/docs/guidelines/design-fidelity-routing.md +78 -0
  451. package/docs/guidelines/design-reconciliation.md +172 -0
  452. package/docs/guidelines/gtm-handoff.md +2 -2
  453. package/docs/guidelines/wing4-handoff.md +2 -2
  454. package/llms.txt +1 -1
  455. package/package.json +7 -3
  456. package/src/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
  457. package/src/config/agent-settings.template.yml +94 -1
  458. package/src/config/ci-local-parity.yml +34 -0
  459. package/src/config/continuity-surface.json +8 -29
  460. package/src/config/evaluator-budgets.json +4 -4
  461. package/src/config/gate-coverage.yml +31 -8
  462. package/src/config/gate-reachability-exemptions.json +1 -0
  463. package/src/config/gate-violation-baselines.json +3 -3
  464. package/src/config/hook-token-budget.json +8 -7
  465. package/src/config/host-injection-effect.json +2 -2
  466. package/src/config/pack-size-budget.json +55 -4
  467. package/src/config/packed-binary-manifest.json +1 -1
  468. package/src/config/platform-anchor.json +47 -0
  469. package/src/config/preamble-payload-budget.json +2 -3
  470. package/src/config/publish-surface.json +4 -2
  471. package/src/config/ratification-policy.json +7 -0
  472. package/src/config/routing-coverage-seed.json +9 -2
  473. package/src/config/rule-stub-ceilings.json +16 -9
  474. package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
  475. package/src/scripts/_cli/cmd_settings_get.ts +22 -7
  476. package/src/scripts/_cli/handoff_sessions.ts +14 -44
  477. package/src/scripts/_lib/agent_settings.ts +85 -0
  478. package/src/scripts/_lib/agent_src.ts +21 -0
  479. package/src/scripts/_lib/artifact_maturity.ts +242 -0
  480. package/src/scripts/_lib/conformance_report.ts +403 -0
  481. package/src/scripts/_lib/continuity_slot.ts +295 -0
  482. package/src/scripts/_lib/continuity_writer.ts +312 -0
  483. package/src/scripts/_lib/design_system_import.ts +20 -0
  484. package/src/scripts/_lib/design_tolerance.ts +281 -0
  485. package/src/scripts/_lib/guidelines_lane.ts +164 -0
  486. package/src/scripts/_lib/hook_settings.ts +85 -0
  487. package/src/scripts/_lib/lean_projection_mode.ts +127 -0
  488. package/src/scripts/_lib/obligation_frequency.ts +2 -3
  489. package/src/scripts/_lib/packed_binary_predicate.ts +37 -0
  490. package/src/scripts/_lib/platform_anchor.ts +1053 -0
  491. package/src/scripts/_lib/ratification_artifact.ts +278 -0
  492. package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
  493. package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
  494. package/src/scripts/_lib/security_lint.ts +23 -2
  495. package/src/scripts/_lib/self_repair.ts +21 -0
  496. package/src/scripts/_lib/session_eol.ts +44 -0
  497. package/src/scripts/_lib/session_index_trust.ts +387 -0
  498. package/src/scripts/_lib/standing_bound_ratchet.ts +220 -0
  499. package/src/scripts/_lib/tolerance_shadow.ts +177 -0
  500. package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
  501. package/src/scripts/ai_council/redact_low_impact_entry.ts +8 -0
  502. package/src/scripts/audit_mcp_tools.ts +69 -25
  503. package/src/scripts/autonomy_friction_traffic.ts +379 -0
  504. package/src/scripts/build_mcp_catalog.ts +24 -1
  505. package/src/scripts/check_host_tree_parity.ts +291 -0
  506. package/src/scripts/check_kernel_edit_ratified.ts +462 -0
  507. package/src/scripts/check_loss_class_declared.ts +793 -46
  508. package/src/scripts/check_platform_anchor.ts +390 -0
  509. package/src/scripts/check_preamble_payload_budget.ts +424 -7
  510. package/src/scripts/check_projected_rule_routes.ts +395 -0
  511. package/src/scripts/check_rule_projection_integrity.ts +102 -2
  512. package/src/scripts/ci_settle.ts +205 -5
  513. package/src/scripts/code_graph/build.ts +79 -0
  514. package/src/scripts/code_graph/cli.ts +264 -7
  515. package/src/scripts/code_graph/detect.ts +38 -0
  516. package/src/scripts/code_graph/query.ts +25 -2
  517. package/src/scripts/code_graph/sqlite_store.ts +16 -1
  518. package/src/scripts/code_graph/types.ts +52 -3
  519. package/src/scripts/code_graph/validate.ts +3 -1
  520. package/src/scripts/code_graph/verbs.ts +590 -0
  521. package/src/scripts/condense.ts +22 -26
  522. package/src/scripts/generate_host_cost_table.ts +354 -0
  523. package/src/scripts/handoff_context_hook.ts +39 -1
  524. package/src/scripts/hook_manifest.json +1 -1
  525. package/src/scripts/hook_manifest.yaml +59 -28
  526. package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
  527. package/src/scripts/hooks/category_a.ts +1 -1
  528. package/src/scripts/hooks/chain_nudge_hook.ts +311 -25
  529. package/src/scripts/hooks/code_graph_context_hook.ts +7 -18
  530. package/src/scripts/hooks/push_settle_hook.ts +3 -2
  531. package/src/scripts/hooks/rule_inject_hook.ts +107 -20
  532. package/src/scripts/hooks/session_eol_hook.ts +177 -145
  533. package/src/scripts/hooks/source_first_gate_hook.ts +12 -0
  534. package/src/scripts/hooks/ui_route_nudge_hook.ts +52 -15
  535. package/src/scripts/hot_context_hook.ts +103 -408
  536. package/src/scripts/lint_evidence_artifacts.ts +1 -0
  537. package/src/scripts/lint_knowledge_scale.ts +0 -26
  538. package/src/scripts/lint_roadmap_blockers.ts +164 -1
  539. package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
  540. package/src/scripts/mcp_server/graph_tools.ts +294 -0
  541. package/src/scripts/mcp_server/path_util.ts +31 -0
  542. package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
  543. package/src/scripts/mcp_server/tools.ts +3 -13
  544. package/src/scripts/memory_lookup.ts +9 -9
  545. package/src/scripts/model_rule_injection.ts +61 -4
  546. package/src/scripts/project_thin_rules.ts +149 -16
  547. package/src/scripts/report_standing_payload_by_host.ts +650 -0
  548. package/src/scripts/schemas/agent-settings.schema.json +7 -1
  549. package/src/scripts/session_memory_index.ts +86 -8
  550. package/src/scripts/sync_agent_settings.ts +270 -10
  551. package/src/server/io/yamlIO.ts +127 -17
  552. package/src/server/schemas/settings.ts +45 -6
  553. package/src/shared/settingsSurface.ts +13 -2
  554. package/src/templates/compact-instructions.md +8 -3
  555. package/src/vendor/grammars/README.md +27 -2
  556. package/dist/agent-src/commands/chat-history/import.md +0 -170
  557. package/dist/agent-src/commands/chat-history.md +0 -63
@@ -18,10 +18,20 @@
18
18
  * every agent's head: `not settled` and `settled` are different from `could not
19
19
  * read`, and only the first two may end a wait.
20
20
  *
21
- * Exit codes: 0 = settled, every check succeeded (or was skipped) ·
21
+ * A verdict also has to be ABOUT SOMETHING, which is the second half of the
22
+ * same rule and was missing until 2026-09-08: the rollup answers about the head
23
+ * the PR *record* carries, and that head stops tracking the branch when the PR
24
+ * is merged or when the record lags a push. Both then look like a healthy
25
+ * green. {@link classifyTarget} refuses those, before the wait and again at
26
+ * verdict time. Measured cost of not having it: a `SETTLED GREEN — 40 check(s)`
27
+ * for a head with literally zero check runs.
28
+ *
29
+ * Exit codes: 0 = settled green, and the head it is about is named ·
22
30
  * 1 = settled, at least one check failed ·
23
- * 2 = did not settle within the budget, or the API could not be
24
- * read — NEVER a verdict, and the reason is printed.
31
+ * 2 = did not settle within the budget, the API could not be read,
32
+ * or the target is not a PR a verdict can be about (merged,
33
+ * closed, or head-diverged) — NEVER a verdict, and the reason
34
+ * is printed.
25
35
  *
26
36
  * Usage: ./scripts-run src/scripts/ci_settle <pr> [--timeout-min N] [--interval-sec N]
27
37
  *
@@ -57,6 +67,121 @@ export type PollState =
57
67
  | { kind: 'pending'; total: number; done: number }
58
68
  | { kind: 'settled'; failing: string[]; total: number };
59
69
 
70
+ /**
71
+ * What `git ls-remote` said about the PR branch's tip.
72
+ *
73
+ * `absent` and `unreadable` are different answers and must not collapse: a
74
+ * cross-repo fork PR legitimately has no ref under this `origin`, while a
75
+ * transport failure means nobody knows. Collapsing them either disables the
76
+ * divergence check for forks silently, or blocks every fork PR forever.
77
+ */
78
+ export type RemoteTip =
79
+ | { kind: 'found'; sha: string }
80
+ | { kind: 'absent' }
81
+ | { kind: 'unreadable'; reason: string };
82
+
83
+ /**
84
+ * Whether the PR this wait is about still decides anything.
85
+ *
86
+ * `refuse` is NOT a verdict — it exits 2 like every other non-verdict, because
87
+ * the wait produced no readable statement about the head that matters.
88
+ */
89
+ export type TargetState =
90
+ | { kind: 'open'; head: string; ref: string; divergenceChecked: boolean }
91
+ | { kind: 'unreadable'; reason: string }
92
+ | { kind: 'refuse'; reason: string };
93
+
94
+ /**
95
+ * Decide whether a green from {@link classifyPoll} may be reported at all.
96
+ *
97
+ * WHY THIS EXISTS, measured 2026-09-08 on PR #1949 and paid for twice in one
98
+ * session. `gh pr view --json statusCheckRollup` answers about the head the PR
99
+ * *record* carries, and that head stops tracking the branch in two situations
100
+ * this script previously could not tell apart from a healthy wait:
101
+ *
102
+ * 1. **The PR is already merged or closed.** A push to its branch fires no
103
+ * `pull_request` event, so no checks are created for the new commits and the
104
+ * rollup keeps returning the merge-time head's checks. The script reported
105
+ * `SETTLED GREEN — 40 check(s)` for a head that had stopped mattering, and
106
+ * the only thing that exposed it was a hand-written
107
+ * `/commits/<sha>/check-runs` query answering `0`. Reported at face value
108
+ * that green authorises a merge of content nobody checked.
109
+ * 2. **The PR record lags the branch ref.** Same shape, different cause
110
+ * (recorded on PR #710): `git ls-remote` shows the new SHA while the record
111
+ * keeps the old one, and merging then lands the PR WITHOUT the newer
112
+ * commits — silently, which is what makes it worse than a red.
113
+ *
114
+ * Both are answered by the same two facts, which is why one function decides
115
+ * them: the PR's `state`, and whether its head equals the branch tip. Pure, so
116
+ * the failure is testable without a network — feed it a merged PR and it must
117
+ * answer `refuse`, never `open`.
118
+ */
119
+ export function classifyTarget(
120
+ stdout: string,
121
+ stderr: string,
122
+ status: number | null,
123
+ tip: RemoteTip,
124
+ ): TargetState {
125
+ const combined = `${stdout}\n${stderr}`.toLowerCase();
126
+ for (const marker of _UNREADABLE_MARKERS) {
127
+ if (combined.includes(marker.toLowerCase())) {
128
+ return { kind: 'unreadable', reason: marker };
129
+ }
130
+ }
131
+ if (status !== 0) {
132
+ return { kind: 'unreadable', reason: `gh exited ${String(status)}` };
133
+ }
134
+ let state: string;
135
+ let head: string;
136
+ let ref: string;
137
+ try {
138
+ const parsed = JSON.parse(stdout) as {
139
+ state?: unknown;
140
+ headRefOid?: unknown;
141
+ headRefName?: unknown;
142
+ };
143
+ if (
144
+ typeof parsed.state !== 'string' ||
145
+ typeof parsed.headRefOid !== 'string' ||
146
+ typeof parsed.headRefName !== 'string'
147
+ ) {
148
+ return { kind: 'unreadable', reason: 'no state / headRefOid / headRefName in response' };
149
+ }
150
+ state = parsed.state.toUpperCase();
151
+ head = parsed.headRefOid;
152
+ ref = parsed.headRefName;
153
+ } catch {
154
+ return { kind: 'unreadable', reason: 'unparseable JSON' };
155
+ }
156
+ if (state !== 'OPEN') {
157
+ return {
158
+ kind: 'refuse',
159
+ reason:
160
+ `the PR is ${state}, not OPEN. Its rollup describes head ${head.slice(0, 9)} as of ` +
161
+ 'that transition; pushes after it create no checks, so a green here would be about ' +
162
+ 'a head that no longer decides anything',
163
+ };
164
+ }
165
+ if (tip.kind === 'unreadable') {
166
+ return { kind: 'unreadable', reason: `branch tip: ${tip.reason}` };
167
+ }
168
+ if (tip.kind === 'absent') {
169
+ // A fork PR's ref is not under this origin. Say the check did not apply
170
+ // rather than pretending it passed.
171
+ return { kind: 'open', head, ref, divergenceChecked: false };
172
+ }
173
+ if (tip.sha !== head) {
174
+ return {
175
+ kind: 'refuse',
176
+ reason:
177
+ `the PR record is at head ${head.slice(0, 9)} but origin/${ref} is at ` +
178
+ `${tip.sha.slice(0, 9)}. Merging in this state lands the PR WITHOUT the newer ` +
179
+ 'commits (recorded on PR #710), and any verdict here is about the wrong head',
180
+ };
181
+ }
182
+ return { kind: 'open', head, ref, divergenceChecked: true };
183
+ }
184
+
60
185
  /** Markers that mean the API did not answer — not that nothing is pending. */
61
186
  const _UNREADABLE_MARKERS = [
62
187
  'error connecting to',
@@ -126,6 +251,41 @@ function poll(pr: string): PollState {
126
251
  return classifyPoll(r.stdout ?? '', r.stderr ?? '', r.status);
127
252
  }
128
253
 
254
+ /**
255
+ * Read the branch tip from the remote, not from a local ref.
256
+ *
257
+ * A local `origin/<ref>` is only as fresh as the last fetch, and the divergence
258
+ * this guards against is created by somebody else's push — so a stale local ref
259
+ * would report agreement exactly when it matters most.
260
+ */
261
+ function readTip(ref: string): RemoteTip {
262
+ const r = spawnSync('git', ['ls-remote', 'origin', `refs/heads/${ref}`], {
263
+ encoding: 'utf-8',
264
+ timeout: 60_000,
265
+ });
266
+ if (r.status !== 0) {
267
+ const why = (r.stderr ?? '').trim().split('\n')[0] ?? `git exited ${String(r.status)}`;
268
+ return { kind: 'unreadable', reason: why };
269
+ }
270
+ const line = (r.stdout ?? '').trim();
271
+ if (line === '') return { kind: 'absent' };
272
+ const sha = line.split(/\s+/)[0] ?? '';
273
+ return sha === '' ? { kind: 'unreadable', reason: 'empty sha in ls-remote output' } : { kind: 'found', sha };
274
+ }
275
+
276
+ function readTarget(pr: string): TargetState {
277
+ const r = spawnSync('gh', ['pr', 'view', pr, '--json', 'state,headRefOid,headRefName'], {
278
+ encoding: 'utf-8',
279
+ timeout: 60_000,
280
+ });
281
+ // The ref name comes from the same read, so the tip lookup needs it first;
282
+ // classifyTarget is called twice rather than plumbing a callback through a
283
+ // pure function.
284
+ const shape = classifyTarget(r.stdout ?? '', r.stderr ?? '', r.status, { kind: 'absent' });
285
+ if (shape.kind !== 'open') return shape;
286
+ return classifyTarget(r.stdout ?? '', r.stderr ?? '', r.status, readTip(shape.ref));
287
+ }
288
+
129
289
  function sleepSync(seconds: number): void {
130
290
  // Deliberately synchronous: this is a CLI whose whole job is to block.
131
291
  spawnSync(process.execPath, ['-e', `setTimeout(()=>{}, ${String(seconds * 1000)})`], {
@@ -164,18 +324,58 @@ export function main(argv: readonly string[]): number {
164
324
  }
165
325
  const intervalSec = num('--interval-sec', 60);
166
326
 
327
+ // Up front, because waiting nine minutes to learn the PR was merged before
328
+ // the wait began is the expensive way to find out.
329
+ const before = readTarget(pr);
330
+ if (before.kind === 'refuse') {
331
+ process.stdout.write(`ci_settle: REFUSING TO WAIT — ${before.reason}. No verdict is claimed.\n`);
332
+ return 2;
333
+ }
334
+ if (before.kind === 'unreadable') {
335
+ process.stdout.write(
336
+ `ci_settle: could not read the PR's target state (${before.reason}) — NOT a verdict, waiting anyway; ` +
337
+ 'the pre-verdict re-check below still applies.\n',
338
+ );
339
+ } else if (!before.divergenceChecked) {
340
+ process.stdout.write(
341
+ `ci_settle: origin carries no refs/heads/${before.ref} (a fork PR) — the head-divergence check does not apply here.\n`,
342
+ );
343
+ }
344
+
167
345
  const deadline = Date.now() + timeoutMin * 60_000;
168
346
  let unreadableStreak = 0;
169
347
 
170
348
  for (;;) {
171
349
  const state = poll(pr);
172
350
  if (state.kind === 'settled') {
351
+ // The rollup is about the record's head. Re-read that head at
352
+ // VERDICT time, not only at start: a push or a merge during the
353
+ // wait makes the rollup describe something the caller is not about
354
+ // to act on, and this is the last moment a wrong verdict is still
355
+ // preventable.
356
+ const at = readTarget(pr);
357
+ if (at.kind === 'refuse') {
358
+ process.stdout.write(
359
+ `ci_settle: WITHHOLDING A VERDICT — ${at.reason}. The checks that settled are not about ` +
360
+ 'the head that matters now.\n',
361
+ );
362
+ return 2;
363
+ }
364
+ if (at.kind === 'unreadable') {
365
+ process.stdout.write(
366
+ `ci_settle: WITHHOLDING A VERDICT — could not confirm the target head (${at.reason}). ` +
367
+ 'A verdict needs to name the head it is about.\n',
368
+ );
369
+ return 2;
370
+ }
173
371
  if (state.failing.length === 0) {
174
- process.stdout.write(`ci_settle: SETTLED GREEN — ${String(state.total)} check(s)\n`);
372
+ process.stdout.write(
373
+ `ci_settle: SETTLED GREEN — ${String(state.total)} check(s) on ${at.head.slice(0, 9)}\n`,
374
+ );
175
375
  return 0;
176
376
  }
177
377
  process.stdout.write(
178
- `ci_settle: SETTLED RED — ${String(state.failing.length)} of ${String(state.total)} failing:\n` +
378
+ `ci_settle: SETTLED RED — ${String(state.failing.length)} of ${String(state.total)} failing on ${at.head.slice(0, 9)}:\n` +
179
379
  state.failing.map((f) => ` ${f}\n`).join(''),
180
380
  );
181
381
  return 1;
@@ -34,6 +34,7 @@ import {
34
34
  type EdgeConfidence,
35
35
  EXPECTED_GRAMMAR_ABI,
36
36
  EXT_LANG,
37
+ isStatedResolution,
37
38
  type Lang,
38
39
  type ResolvedVia,
39
40
  SCHEMA_VERSION,
@@ -612,6 +613,52 @@ export function buildGraph(
612
613
  });
613
614
  }
614
615
 
616
+ // DERIVED `tests` edges (3.2).
617
+ //
618
+ // A test file that imports an in-repo symbol from a NON-test file is
619
+ // asserted to test it. Derived here rather than extracted because the
620
+ // predicate is a property of the two PATHS, which no grammar can see, and
621
+ // because `buildGraph` already holds every `imports` edge plus the node
622
+ // table needed to reject cross-test and out-of-repo targets.
623
+ //
624
+ // Three exclusions, each of which would otherwise manufacture a false
625
+ // `tests` edge:
626
+ // · target outside the repository (`external:*` / `symbol:*`) — there is
627
+ // no subject to test;
628
+ // · target in another TEST file — a shared test helper is not a subject;
629
+ // · target is the subject FILE node rather than a symbol in it, which is
630
+ // kept: a test that imports a module tests that module, and the file
631
+ // node is the only handle a caller has for a module with no exported
632
+ // symbol the extractor named;
633
+ // · THE SOURCE IMPORT IS ITSELF A GUESS. Added after an independent review
634
+ // demonstrated the laundering: a PHP `use Two\Mailer` with no
635
+ // `composer.json` binds by BASE NAME, so the `imports` edge is
636
+ // `name-lookup` and can point at `One\Mailer` — and a `tests` edge
637
+ // derived from it, stamped `test-import`, made that wrong target
638
+ // TRUSTWORTHY to every consumer of the accepted-edge filter. Measured
639
+ // consequences on a two-namespace fixture: `tests-for One\Mailer`
640
+ // named a test that does not test it, `tests-for Two\Mailer` reported
641
+ // none, `untested` inverted the pair, and `dead` called the tested class
642
+ // dead. A derived edge may never be more trustworthy than the edge it
643
+ // was derived from.
644
+ const nodeSourceFile = new Map(nodes.map((n) => [n.id, n.source_file]));
645
+ for (const e of [...edges]) {
646
+ if (e.relation !== 'imports') continue;
647
+ if (!isStatedResolution(e.resolved_via)) continue;
648
+ const from = nodeSourceFile.get(e.source);
649
+ if (from === undefined || !isTestFile(from)) continue;
650
+ const to = nodeSourceFile.get(e.target);
651
+ if (to === undefined || isTestFile(to)) continue;
652
+ emit({
653
+ source: e.source,
654
+ target: e.target,
655
+ relation: 'tests',
656
+ confidence: 'INFERRED',
657
+ resolved_via: 'test-import',
658
+ provider: 'native',
659
+ });
660
+ }
661
+
615
662
  // deterministic ordering
616
663
  nodes.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
617
664
  edges.sort((a, b) => {
@@ -677,6 +724,38 @@ function ambiguousTarget(candidates: readonly string[], targetName: string): str
677
724
  return `symbol:${targetName}`;
678
725
  }
679
726
 
727
+ /**
728
+ * Is `relPath` a test file?
729
+ *
730
+ * A deterministic PATH predicate — no content read, no heuristic on the file's
731
+ * body. It is the input to the derived `tests` relation (3.2), so it has to be
732
+ * conservative in one direction only: a subject wrongly classified as a test
733
+ * silently loses its `tests` edges, while a test wrongly classified as a
734
+ * subject would make a test file look like a tested surface. Both are wrong;
735
+ * the second is worse, because `untested` would then report a real subject as
736
+ * covered.
737
+ *
738
+ * The four conventions are the ones this launch set actually uses, and each is
739
+ * anchored rather than substring-matched so a directory called
740
+ * `src/latest/thing.ts` is not a test:
741
+ *
742
+ * · a `tests/` or `test/` path segment (this repository's own layout);
743
+ * · a `__tests__/` segment (the JS convention);
744
+ * · a `.test.` / `.spec.` filename infix (Vitest / Jest / Pest-JS);
745
+ * · a `Test.php` / `test.php` filename suffix, or a `_test.php` infix
746
+ * (PHPUnit's `*Test.php` and Go-style `_test` both appear in PHP trees).
747
+ */
748
+ export function isTestFile(relPath: string): boolean {
749
+ const p = relPath.split(path.sep).join('/');
750
+ const segments = p.split('/');
751
+ if (segments.some((seg) => seg === 'tests' || seg === 'test' || seg === '__tests__')) return true;
752
+ const base = segments[segments.length - 1] ?? '';
753
+ if (/\.(test|spec)\./i.test(base)) return true;
754
+ if (/(^|[._-])test\.php$/i.test(base)) return true;
755
+ if (/Test\.php$/.test(base)) return true;
756
+ return false;
757
+ }
758
+
680
759
  export function serializeGraph(g: CodeGraph): string {
681
760
  const key_order: (keyof CodeGraph)[] = [
682
761
  'schema_version',
@@ -28,6 +28,20 @@
28
28
  * `agents/runtime/state/code-graph-v1.json`) is local-only and disposable —
29
29
  * gitignored, rebuildable from source at any time; never a source of truth.
30
30
  *
31
+ * impact --diff <rev> [--depth N] callers/dependents/test files
32
+ * reachable from the changed
33
+ * symbols over ACCEPTED edges
34
+ * tests-for <symbol> test files importing the symbol
35
+ * untested --diff <rev> changed symbols no test imports
36
+ * dead [--entry-points F] zero accepted in-edges, minus
37
+ * [--accept-missing-exports] declared entry points; REFUSES
38
+ * when a source is unavailable
39
+ *
40
+ * The four gate verbs (3.1–3.3) each print the `resolved_via` histogram of the
41
+ * edges they accepted AND of the edges they refused to walk, plus the graph's
42
+ * three-state staleness — so a caller can tell "no callers" from "no callers I
43
+ * would trust", and "dead" from "dead as of a graph 40 commits behind".
44
+ *
31
45
  * Query subcommands (query/path/explain/affected) are added by the Phase-3
32
46
  * query tier. Deterministic, LLM-free, no network. Exit codes:
33
47
  * 0 ok · 1 not-found / validation-failed / refresh-budget-exceeded ·
@@ -49,8 +63,8 @@ import process from 'node:process';
49
63
  import { fileURLToPath } from 'node:url';
50
64
 
51
65
  import { hardenedSpawnEnv } from '../_lib/spawn_env.js';
52
- import { buildFromRepo, sidecarPath } from './build.js';
53
- import { computeVerdict, detectSources, pickSource } from './detect.js';
66
+ import { buildFromRepo, isTestFile, sidecarPath } from './build.js';
67
+ import { computeVerdict, detectSources, type GraphState, graphState, pickSource } from './detect.js';
54
68
  import { suggestVerb } from './intent.js';
55
69
  import {
56
70
  affected,
@@ -65,6 +79,18 @@ import {
65
79
  import { openGraphIndex, sqliteTwinPath } from './sqlite_store.js';
66
80
  import type { CodeGraph } from './types.js';
67
81
  import { validateGraph } from './validate.js';
82
+ import {
83
+ dead,
84
+ type DeadResult,
85
+ entryPointsFromFile,
86
+ impact,
87
+ type ImpactResult,
88
+ repoEntryPoints,
89
+ testsFor,
90
+ type TestsForResult,
91
+ untested,
92
+ type UntestedResult,
93
+ } from './verbs.js';
68
94
 
69
95
  const _HERE = fileURLToPath(import.meta.url);
70
96
  export const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..', '..');
@@ -258,10 +284,24 @@ function budgetOf(argv: string[]): number {
258
284
  return Number.isFinite(b) && b > 0 ? b : 1500;
259
285
  }
260
286
 
261
- function changedNodeSeeds(g: LoadedGraph, root: string, ref: string): string[] {
262
- let files: string[];
287
+ /**
288
+ * Files changed between `ref` and `HEAD`, repo-relative.
289
+ *
290
+ * Extracted from `changedNodeSeeds` so the Phase-3 verbs seed from the same
291
+ * diff reading as `affected --since`. `null` distinguishes "git refused" (a bad
292
+ * rev, not a repository) from "nothing changed" — a verb that reports an empty
293
+ * impact set for a rev git could not resolve is asserting something it never
294
+ * measured.
295
+ */
296
+ export function changedFiles(root: string, ref: string): string[] | null {
297
+ // `execFileSync` takes an argv array, so there is no shell and `$(...)` in a
298
+ // rev is inert. What the `${ref}..HEAD` concatenation does NOT stop is
299
+ // OPTION injection: `--output=/tmp/x` becomes `--output=/tmp/x..HEAD`, a
300
+ // well-formed option whose value is a filename, and the file is written with
301
+ // exit 0 (probed 2026-09-09). A rev never begins with `-`.
302
+ if (ref.startsWith('-')) return null;
263
303
  try {
264
- files = execFileSync('git', ['-C', root, 'diff', '--name-only', `${ref}..HEAD`], {
304
+ return execFileSync('git', ['-C', root, 'diff', '--name-only', `${ref}..HEAD`], {
265
305
  env: hardenedSpawnEnv(),
266
306
  encoding: 'utf-8',
267
307
  stdio: ['ignore', 'pipe', 'ignore'],
@@ -270,8 +310,13 @@ function changedNodeSeeds(g: LoadedGraph, root: string, ref: string): string[] {
270
310
  .map((s) => s.trim())
271
311
  .filter(Boolean);
272
312
  } catch {
273
- return [];
313
+ return null;
274
314
  }
315
+ }
316
+
317
+ function changedNodeSeeds(g: LoadedGraph, root: string, ref: string): string[] {
318
+ const files = changedFiles(root, ref);
319
+ if (files === null) return [];
275
320
  // Served by the `nodes_source_file` index on the SQLite path, so a wide
276
321
  // diff does not force the whole node table into memory to answer it.
277
322
  return g.idsInFiles(files);
@@ -322,6 +367,213 @@ function isFlagValue(argv: string[], token: string): boolean {
322
367
  return i > 0 && (argv[i - 1] as string).startsWith('--');
323
368
  }
324
369
 
370
+ // Phase-3 gate verbs (3.1-3.3).
371
+
372
+ /** The staleness token every gate verb prints, per step 3.1–3.3's shared
373
+ * verify: "each prints `resolved_via` counts and the staleness state". */
374
+ /**
375
+ * The staleness of the graph the verb is ACTUALLY reading.
376
+ *
377
+ * `answeredBy` is `resolveGraph`'s own picked path when it has one. Without it
378
+ * the two disagreed on the case `resolveRoot`'s docstring exists for: with
379
+ * `--root <other repo>` the verb answers from `DEFAULT_CACHE` (anchored to the
380
+ * package tree) while `graphState` looked under the OTHER root, so the printed
381
+ * staleness described a cache the answer never came from. An independent review
382
+ * found the `--graph` half fixed and this half open.
383
+ */
384
+ function stateOf(argv: string[], answeredBy?: string): GraphState {
385
+ const explicit = flag(argv, '--graph');
386
+ return graphState(resolveRoot(argv), explicit ?? answeredBy);
387
+ }
388
+
389
+ /** The two histogram lines + the staleness line, in one place so the four
390
+ * verbs cannot drift apart in how they report their own filtering. */
391
+ function renderEnvelope(r: { source: string; state: GraphState; accepted_via: string; rejected_via: string }): void {
392
+ process.stdout.write(`source: ${r.source}\nstaleness: ${r.state}\n`);
393
+ process.stdout.write(`accepted resolved_via: ${r.accepted_via}\n`);
394
+ process.stdout.write(`rejected resolved_via: ${r.rejected_via}\n`);
395
+ }
396
+
397
+ function renderReads(reads: readonly { path: string; lines: [number, number] | null }[]): void {
398
+ if (!reads.length) return;
399
+ process.stdout.write('minimal read set:\n');
400
+ for (const r of reads) process.stdout.write(` ${r.path}${r.lines ? `:${r.lines[0]}-${r.lines[1]}` : ''}\n`);
401
+ }
402
+
403
+ /**
404
+ * `impact --diff <rev>` (3.1) — callers, dependents and test files reachable
405
+ * from the changed symbols over ACCEPTED edges, plus the producing edges and a
406
+ * minimal read set.
407
+ */
408
+ function cmdImpact(argv: string[]): number {
409
+ const ref = flag(argv, '--diff');
410
+ if (ref === null) {
411
+ process.stderr.write('usage: code_graph/cli.ts impact --diff <rev> [--graph P] [--depth N]\n');
412
+ return 2;
413
+ }
414
+ const root = resolveRoot(argv);
415
+ const files = changedFiles(root, ref);
416
+ if (files === null) {
417
+ process.stderr.write(`code-graph: cannot resolve rev '${ref}' in ${root}\n`);
418
+ return 1;
419
+ }
420
+ const r = resolveGraph(argv);
421
+ if ('err' in r) {
422
+ process.stderr.write(`code-graph: ${r.err}\n`);
423
+ return 1;
424
+ }
425
+ try {
426
+ const depth = Number(flag(argv, '--depth'));
427
+ const res: ImpactResult = impact(
428
+ r.g,
429
+ files,
430
+ stateOf(argv, r.g.answeredBy),
431
+ Number.isFinite(depth) && depth > 0 ? depth : 2,
432
+ isTestFile,
433
+ );
434
+ renderEnvelope(res);
435
+ process.stdout.write(`changed files: ${files.length} · seeds: ${res.seeds.length}\n`);
436
+ if (res.unresolved_files.length)
437
+ process.stdout.write(`unresolved changed files (no node in the graph): ${res.unresolved_files.join(', ')}\n`);
438
+ process.stdout.write(`dependents (${res.dependents.length}):\n`);
439
+ for (const d of res.dependents) process.stdout.write(` ${d}\n`);
440
+ process.stdout.write(`test files (${res.test_files.length}):\n`);
441
+ for (const t of res.test_files) process.stdout.write(` ${t}\n`);
442
+ process.stdout.write(`producing edges (${res.producing_edges.length}):\n`);
443
+ for (const e of res.producing_edges) process.stdout.write(` ${e}\n`);
444
+ renderReads(res.recommended_reads);
445
+ return 0;
446
+ } finally {
447
+ r.g.close();
448
+ }
449
+ }
450
+
451
+ /** `tests-for <symbol>` (3.2) — the test files that import the symbol. */
452
+ function cmdTestsFor(argv: string[]): number {
453
+ const positional = argv.filter((a) => !a.startsWith('--') && !isFlagValue(argv, a));
454
+ const symbol = positional[0];
455
+ if (!symbol) {
456
+ process.stderr.write('usage: code_graph/cli.ts tests-for <symbol> [--graph P]\n');
457
+ return 2;
458
+ }
459
+ const r = resolveGraph(argv);
460
+ if ('err' in r) {
461
+ process.stderr.write(`code-graph: ${r.err}\n`);
462
+ return 1;
463
+ }
464
+ try {
465
+ const res: TestsForResult = testsFor(r.g, symbol, stateOf(argv, r.g.answeredBy));
466
+ renderEnvelope(res);
467
+ process.stdout.write(`seeds: ${res.seeds.join(', ') || '(none)'}\n`);
468
+ process.stdout.write(`tests (${res.tests.length}):\n`);
469
+ for (const t of res.tests) process.stdout.write(` ${t}\n`);
470
+ renderReads(res.recommended_reads);
471
+ return 0;
472
+ } finally {
473
+ r.g.close();
474
+ }
475
+ }
476
+
477
+ /** `untested --diff <rev>` (3.2) — changed symbols no test file imports. */
478
+ function cmdUntested(argv: string[]): number {
479
+ const ref = flag(argv, '--diff');
480
+ if (ref === null) {
481
+ process.stderr.write('usage: code_graph/cli.ts untested --diff <rev> [--graph P]\n');
482
+ return 2;
483
+ }
484
+ const root = resolveRoot(argv);
485
+ const files = changedFiles(root, ref);
486
+ if (files === null) {
487
+ process.stderr.write(`code-graph: cannot resolve rev '${ref}' in ${root}\n`);
488
+ return 1;
489
+ }
490
+ const r = resolveGraph(argv);
491
+ if ('err' in r) {
492
+ process.stderr.write(`code-graph: ${r.err}\n`);
493
+ return 1;
494
+ }
495
+ try {
496
+ const res: UntestedResult = untested(r.g, files, stateOf(argv, r.g.answeredBy));
497
+ renderEnvelope(res);
498
+ process.stdout.write(`changed files: ${files.length} · changed symbols: ${res.tested.length + res.untested.length}\n`);
499
+ if (res.unresolved_files.length)
500
+ process.stdout.write(`unresolved changed files (no node in the graph): ${res.unresolved_files.join(', ')}\n`);
501
+ process.stdout.write(`tested (${res.tested.length}) · untested (${res.untested.length}):\n`);
502
+ for (const u of res.untested) process.stdout.write(` ${u}\n`);
503
+ renderReads(res.recommended_reads);
504
+ return 0;
505
+ } finally {
506
+ r.g.close();
507
+ }
508
+ }
509
+
510
+ /**
511
+ * `dead` (3.3) — symbols with zero accepted in-edges that no declared entry
512
+ * point names. REFUSES by default when an entry-point source is unavailable;
513
+ * see `verbs.ts::dead` for why that refusal is not relaxable by an options bag.
514
+ */
515
+ function cmdDead(argv: string[]): number {
516
+ const r = resolveGraph(argv);
517
+ if ('err' in r) {
518
+ process.stderr.write(`code-graph: ${r.err}\n`);
519
+ return 1;
520
+ }
521
+ try {
522
+ const root = resolveRoot(argv);
523
+ const sources = repoEntryPoints(root);
524
+ const listFile = flag(argv, '--entry-points');
525
+ if (listFile !== null) {
526
+ if (!fs.existsSync(listFile)) {
527
+ process.stderr.write(`code-graph: entry-point list not found: ${listFile}\n`);
528
+ return 1;
529
+ }
530
+ // An operator-supplied list SUPPLIES the missing source, so the
531
+ // `exports` row stops being a gap rather than being ignored: the
532
+ // caller has stated the entry points the graph could not.
533
+ const supplied = entryPointsFromFile(listFile);
534
+ const patched = sources.map((srcRow) =>
535
+ srcRow.name === 'exports'
536
+ ? { ...srcRow, status: 'read' as const, detail: `supplied by ${listFile}`, entries: [] }
537
+ : srcRow,
538
+ );
539
+ patched.push(supplied);
540
+ const res: DeadResult = dead(r.g, patched, stateOf(argv, r.g.answeredBy));
541
+ return renderDead(res);
542
+ }
543
+ const res: DeadResult = dead(r.g, sources, stateOf(argv, r.g.answeredBy), {
544
+ acceptMissingExports: argv.includes('--accept-missing-exports'),
545
+ });
546
+ return renderDead(res);
547
+ } finally {
548
+ r.g.close();
549
+ }
550
+ }
551
+
552
+ function renderDead(res: DeadResult): number {
553
+ // The envelope FIRST, on both branches. It used to print only after the
554
+ // refusal check, so the default invocation in this repository — where
555
+ // `exports` is always unavailable — printed neither histogram nor the
556
+ // staleness line, and 3.1-3.3's shared verify ("each prints `resolved_via`
557
+ // counts and the staleness state") held only on the branch that answers.
558
+ // A reader of a refusal wants the staleness most of all: it says whether
559
+ // re-running after a rebuild could change anything.
560
+ renderEnvelope(res);
561
+ process.stdout.write('entry-point sources consulted:\n');
562
+ for (const srcRow of res.sources)
563
+ process.stdout.write(
564
+ ` ${srcRow.name.padEnd(13)} ${srcRow.status}${srcRow.detail ? ` — ${srcRow.detail}` : ''} · ${srcRow.entries.length} entr${srcRow.entries.length === 1 ? 'y' : 'ies'}\n`,
565
+ );
566
+ if (res.refusal !== null) {
567
+ process.stderr.write(`❌ dead refused: ${res.refusal}\n`);
568
+ return 1;
569
+ }
570
+ process.stdout.write(`excluded as declared entry points: ${res.excluded.length}\n`);
571
+ process.stdout.write(`dead (${res.dead.length}):\n`);
572
+ for (const d of res.dead) process.stdout.write(` ${d}\n`);
573
+ renderReads(res.recommended_reads);
574
+ return 0;
575
+ }
576
+
325
577
  function cmdDetect(argv: string[]): number {
326
578
  const root = resolveRoot(argv);
327
579
  if (flag(argv, '--format') === 'json') {
@@ -462,9 +714,14 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise<numb
462
714
  if (sub === 'refresh') return cmdRefresh(argv.slice(1));
463
715
  if (sub === 'query' || sub === 'explain' || sub === 'affected' || sub === 'path')
464
716
  return cmdQuery(sub, argv.slice(1));
717
+ if (sub === 'impact') return cmdImpact(argv.slice(1));
718
+ if (sub === 'tests-for') return cmdTestsFor(argv.slice(1));
719
+ if (sub === 'untested') return cmdUntested(argv.slice(1));
720
+ if (sub === 'dead') return cmdDead(argv.slice(1));
465
721
  if (sub === 'suggest-verb') return cmdSuggestVerb(argv.slice(1));
466
722
  process.stderr.write(
467
- 'usage: code_graph/cli.ts <build|validate|detect|refresh|query|explain|affected|path|suggest-verb> [options]\n',
723
+ 'usage: code_graph/cli.ts <build|validate|detect|refresh|query|explain|affected|path|' +
724
+ 'impact|tests-for|untested|dead|suggest-verb> [options]\n',
468
725
  );
469
726
  return 2;
470
727
  } catch (e) {