@event4u/agent-config 14.12.0 → 14.13.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 (466) 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 +234 -0
  5. package/CONTRIBUTING.md +38 -0
  6. package/CREDITS.md +135 -0
  7. package/NOTICE +13 -0
  8. package/README.md +8 -6
  9. package/dist/agent-src/commands/analyze/inbox.md +109 -2
  10. package/dist/agent-src/commands/feature/dev.md +7 -2
  11. package/dist/agent-src/commands/ghostwriter/write.md +5 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  14. package/dist/agent-src/commands/orchestrate.md +2 -2
  15. package/dist/agent-src/commands/post-as/me.md +5 -1
  16. package/dist/agent-src/commands/pr/merge.md +19 -6
  17. package/dist/agent-src/commands/roadmap/process-full.md +19 -5
  18. package/dist/agent-src/commands/tdd/red.md +12 -2
  19. package/dist/agent-src/commands/work.md +1 -1
  20. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
  21. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
  22. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
  23. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
  24. package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
  25. package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
  26. package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
  27. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  28. package/dist/agent-src/rules/broken-access-control.md +4 -0
  29. package/dist/agent-src/rules/code-provenance.md +4 -0
  30. package/dist/agent-src/rules/design-fidelity.md +1 -1
  31. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  32. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  33. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  34. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  35. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  36. package/dist/agent-src/rules/laravel-routing.md +1 -1
  37. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  38. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  39. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  40. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  41. package/dist/agent-src/rules/symfony-routing.md +1 -1
  42. package/dist/agent-src/rules/token-efficiency.md +14 -0
  43. package/dist/agent-src/rules/tool-safety.md +4 -0
  44. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  45. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  46. package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
  47. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  48. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  49. package/dist/agent-src/scripts/stubs_due.ts +400 -0
  50. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  51. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
  52. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  53. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  54. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  55. package/dist/agent-src/skills/database/SKILL.md +8 -0
  56. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  57. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  58. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  59. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  60. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  61. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  62. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  63. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  64. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  65. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  66. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  67. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  68. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  69. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  70. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  71. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  72. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  73. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  74. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  75. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  76. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  77. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  78. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  79. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  80. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  81. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  82. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  83. package/dist/agent-src/templates/roadmaps.md +97 -3
  84. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  85. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  86. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  87. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  88. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  93. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  94. package/dist/cli/commands/uiAudit.js +124 -5
  95. package/dist/cli/registry.js +2 -0
  96. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  97. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  98. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  99. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  100. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  101. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  102. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  103. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  104. package/dist/cli-delegate/cmd_conformance.js +42 -10
  105. package/dist/cli-delegate/cmd_doctor.js +3 -3
  106. package/dist/cli-delegate/cmd_export.js +3 -2
  107. package/dist/cli-delegate/cmd_fleet.js +2 -2
  108. package/dist/cli-delegate/cmd_handoff.js +1 -1
  109. package/dist/cli-delegate/cmd_preflight.js +2 -2
  110. package/dist/cli-delegate/cmd_prune.js +3 -2
  111. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  112. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  113. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  114. package/dist/cli-delegate/cmd_sync.js +3 -2
  115. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  116. package/dist/cli-delegate/cmd_validate.js +3 -2
  117. package/dist/discovery/deprecation-report.md +1 -1
  118. package/dist/discovery/discovery-manifest.json +57 -57
  119. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  120. package/dist/discovery/discovery-manifest.summary.md +1 -1
  121. package/dist/discovery/dormancy-report.md +1 -1
  122. package/dist/discovery/orphan-report.md +1 -1
  123. package/dist/discovery/packs.json +2 -2
  124. package/dist/discovery/trust-report.md +1 -1
  125. package/dist/discovery/workspaces.json +2 -2
  126. package/dist/hooks/dispatch.js +1836 -712
  127. package/dist/install/claudeRuleRewrite.js +254 -0
  128. package/dist/install/detect.js +29 -16
  129. package/dist/install/detect_php_shape.js +159 -0
  130. package/dist/install/install.mjs +634 -428
  131. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  132. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  133. package/dist/mcp/registry-manifest.json +3 -3
  134. package/dist/mcp/server.json +3 -3
  135. package/dist/mcp/server.mjs +4818 -2645
  136. package/dist/server/schemas/settings.js +3 -0
  137. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  138. package/dist/ui/index.html +1 -1
  139. package/docs/MIGRATION.md +1 -1
  140. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  141. package/docs/contracts/provider-lifecycle.md +1 -1
  142. package/docs/contracts/settings-classes.md +10 -4
  143. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  144. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  145. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  146. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  147. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  148. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  149. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  150. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  151. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  152. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  153. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  154. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  155. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  156. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  157. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  158. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  159. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  160. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  161. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  162. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  163. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  164. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  165. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  166. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  167. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  168. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  169. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  170. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  171. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  172. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  173. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  174. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  175. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  176. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  177. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  178. package/docs/guidelines/augment-portability-patterns.md +6 -4
  179. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  180. package/docs/guidelines/cross-role-handoff.md +2 -2
  181. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  182. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  183. package/docs/guidelines/php/database.md +90 -7
  184. package/docs/guidelines/prompt-templates.md +7 -7
  185. package/llms.txt +2 -2
  186. package/package.json +5 -2
  187. package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  188. package/src/agent-src/scripts/guarded_baseline.ts +328 -0
  189. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  190. package/src/agent-src/scripts/stub_queue.ts +82 -0
  191. package/src/agent-src/scripts/stubs_due.ts +400 -0
  192. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  193. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
  194. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  195. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  196. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  197. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  198. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  199. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  202. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  203. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  204. package/src/config/agent-settings.template.yml +32 -3
  205. package/src/config/assurance-capability-registry.json +21 -9
  206. package/src/config/canonical-terms.yml +119 -0
  207. package/src/config/capability-native-outcome-bars.json +81 -0
  208. package/src/config/ci-local-parity.yml +80 -0
  209. package/src/config/drafting-channels.yml +43 -0
  210. package/src/config/estate-count-budget.json +38 -36
  211. package/src/config/evaluator-budgets.json +14 -14
  212. package/src/config/gate-coverage.yml +579 -63
  213. package/src/config/gate-reachability-exemptions.json +21 -0
  214. package/src/config/gate-violation-baselines.json +37 -19
  215. package/src/config/harness-evolution-budget.json +25 -0
  216. package/src/config/lapsed-beta-baseline.json +96 -0
  217. package/src/config/memory-twin-verdicts.yml +129 -0
  218. package/src/config/metric-registry.yml +124 -0
  219. package/src/config/pack-size-budget.json +16 -15
  220. package/src/config/preamble-payload-budget.json +8 -8
  221. package/src/config/profiles/balanced.ini +27 -0
  222. package/src/config/profiles/full.ini +27 -0
  223. package/src/config/profiles/minimal.ini +27 -0
  224. package/src/config/publish-surface.json +9 -2
  225. package/src/config/routing-coverage-seed.json +16 -2
  226. package/src/config/rule-stub-ceilings.json +126 -112
  227. package/src/config/turnaround-budget.json +66 -0
  228. package/src/install/claudeRuleRewrite.ts +288 -0
  229. package/src/install/detect.ts +60 -17
  230. package/src/install/detect_php_shape.ts +191 -0
  231. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  232. package/src/scripts/_dispatch.bash +27 -0
  233. package/src/scripts/_lib/activation_ladder.ts +211 -0
  234. package/src/scripts/_lib/activation_states.ts +88 -0
  235. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  236. package/src/scripts/_lib/arith_claims.ts +181 -0
  237. package/src/scripts/_lib/arm_ranking.ts +62 -0
  238. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  239. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  240. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  241. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  242. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  243. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  244. package/src/scripts/_lib/candidate_record.ts +601 -0
  245. package/src/scripts/_lib/capture_rate.ts +319 -0
  246. package/src/scripts/_lib/collector_denominator.ts +771 -0
  247. package/src/scripts/_lib/collector_record.ts +340 -0
  248. package/src/scripts/_lib/collector_store.ts +664 -0
  249. package/src/scripts/_lib/collector_supervision.ts +827 -0
  250. package/src/scripts/_lib/concern_estate.ts +77 -0
  251. package/src/scripts/_lib/config_chain.ts +477 -0
  252. package/src/scripts/_lib/config_cost.ts +209 -0
  253. package/src/scripts/_lib/council_settings_block.ts +6 -0
  254. package/src/scripts/_lib/curator_ops.ts +172 -0
  255. package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
  256. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  257. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  258. package/src/scripts/_lib/empty_cycles.ts +88 -0
  259. package/src/scripts/_lib/eval_publication.ts +354 -0
  260. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  261. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  262. package/src/scripts/_lib/evidence_basis.ts +118 -0
  263. package/src/scripts/_lib/exec_evidence.ts +8 -0
  264. package/src/scripts/_lib/experience_card.ts +272 -0
  265. package/src/scripts/_lib/experience_report.ts +151 -0
  266. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  267. package/src/scripts/_lib/generated_by.ts +66 -0
  268. package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
  269. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  270. package/src/scripts/_lib/host_denominator.ts +687 -0
  271. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  272. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  273. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  274. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  275. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  276. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  277. package/src/scripts/_lib/loop_guards.ts +299 -0
  278. package/src/scripts/_lib/loss_class.ts +129 -0
  279. package/src/scripts/_lib/machine_wake.ts +51 -0
  280. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  281. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  282. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  283. package/src/scripts/_lib/orchestration_record.ts +253 -5
  284. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  285. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  286. package/src/scripts/_lib/paired_stats.ts +245 -0
  287. package/src/scripts/_lib/paired_verdict.ts +226 -0
  288. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  289. package/src/scripts/_lib/privacy_class.ts +47 -0
  290. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  291. package/src/scripts/_lib/repeated_failure.ts +105 -0
  292. package/src/scripts/_lib/repo_root.ts +111 -0
  293. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  294. package/src/scripts/_lib/role_split.ts +338 -0
  295. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  296. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  297. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  298. package/src/scripts/_lib/source_digest.ts +200 -0
  299. package/src/scripts/_lib/source_redact.ts +260 -0
  300. package/src/scripts/_lib/source_shape.ts +502 -0
  301. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  302. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  303. package/src/scripts/_lib/strip_comments.mjs +65 -0
  304. package/src/scripts/_lib/test_red_state.ts +154 -0
  305. package/src/scripts/_lib/trigger_shift.ts +144 -0
  306. package/src/scripts/_lib/untrusted_content.ts +82 -7
  307. package/src/scripts/adoption_report.ts +1 -1
  308. package/src/scripts/adr/evidence_census.ts +1 -1
  309. package/src/scripts/adr/regenerate_index.ts +26 -2
  310. package/src/scripts/adr_cite_check.ts +164 -1
  311. package/src/scripts/ai_council/blind_review.ts +11 -1
  312. package/src/scripts/ai_council/clients.ts +4 -0
  313. package/src/scripts/ai_council/config.ts +3 -0
  314. package/src/scripts/ai_council/consensus.ts +28 -8
  315. package/src/scripts/ai_council/consensus_round.ts +226 -0
  316. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  317. package/src/scripts/ai_council/inline_findings.ts +340 -0
  318. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  319. package/src/scripts/ai_council/orchestrator.ts +16 -203
  320. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  321. package/src/scripts/ai_council/pricing.ts +106 -0
  322. package/src/scripts/ai_council/prompts.ts +74 -7
  323. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  324. package/src/scripts/ai_council/py_format.ts +14 -3
  325. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  326. package/src/scripts/ai_council/response_record.ts +50 -0
  327. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  328. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  329. package/src/scripts/asset_delivery_ledger.ts +157 -0
  330. package/src/scripts/attest_artifact.ts +193 -0
  331. package/src/scripts/audit_auto_rules.ts +2 -1
  332. package/src/scripts/audit_command_surface.ts +1 -1
  333. package/src/scripts/audit_mcp_tools.ts +2 -2
  334. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  335. package/src/scripts/audit_user_type_axis.ts +2 -1
  336. package/src/scripts/bench_ab_clone.ts +215 -10
  337. package/src/scripts/bench_ab_integrity.ts +119 -5
  338. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  339. package/src/scripts/build_archive_index.ts +1 -1
  340. package/src/scripts/build_linear_digest.ts +1 -1
  341. package/src/scripts/build_proof.ts +11 -4
  342. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  343. package/src/scripts/build_source_digests.ts +157 -0
  344. package/src/scripts/cache_realization_report.ts +103 -0
  345. package/src/scripts/check_adr_frontmatter.ts +126 -0
  346. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  347. package/src/scripts/check_beta_review_markers.ts +235 -6
  348. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  349. package/src/scripts/check_claims.ts +576 -6
  350. package/src/scripts/check_composite_arming.ts +35 -0
  351. package/src/scripts/check_concern_admissions.ts +365 -0
  352. package/src/scripts/check_enforcement_coverage.ts +28 -0
  353. package/src/scripts/check_estate_count.ts +142 -1
  354. package/src/scripts/check_gate_reachability.ts +383 -0
  355. package/src/scripts/check_host_loadability.ts +104 -0
  356. package/src/scripts/check_loss_class_declared.ts +308 -0
  357. package/src/scripts/check_md_language.ts +15 -98
  358. package/src/scripts/check_memory_proposal.ts +18 -11
  359. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  360. package/src/scripts/check_no_external_sources.ts +281 -6
  361. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  362. package/src/scripts/check_pack_size.ts +59 -2
  363. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  364. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  365. package/src/scripts/check_publish_surface.ts +10 -1
  366. package/src/scripts/check_references.ts +24 -1
  367. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  368. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  369. package/src/scripts/check_score_contract.ts +26 -3
  370. package/src/scripts/check_static_parity.ts +285 -0
  371. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  372. package/src/scripts/check_suppression_hygiene.ts +15 -0
  373. package/src/scripts/ci_settle.ts +39 -2
  374. package/src/scripts/code_graph/build.ts +60 -3
  375. package/src/scripts/code_graph/extract.ts +44 -0
  376. package/src/scripts/code_graph/types.ts +24 -0
  377. package/src/scripts/collector_daemon.ts +714 -0
  378. package/src/scripts/config_cost_report.ts +302 -0
  379. package/src/scripts/consumer_matrix.ts +74 -1
  380. package/src/scripts/cost/budget.mjs +10 -3
  381. package/src/scripts/cost/track.mjs +10 -3
  382. package/src/scripts/council_cli.ts +37 -54
  383. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  384. package/src/scripts/evolution_lab.ts +980 -0
  385. package/src/scripts/external_sources_denylist.json +5 -18
  386. package/src/scripts/extract_audit_patterns.ts +21 -0
  387. package/src/scripts/fold_intake.ts +12 -1
  388. package/src/scripts/gen_discovery_baseline.ts +1 -1
  389. package/src/scripts/generate_capabilities_index.ts +12 -5
  390. package/src/scripts/generate_capability_matrix.ts +3 -3
  391. package/src/scripts/generate_command_flows.ts +2 -2
  392. package/src/scripts/generate_cookbook.ts +2 -2
  393. package/src/scripts/generate_index.ts +8 -1
  394. package/src/scripts/generate_knowledge_index.ts +2 -1
  395. package/src/scripts/generate_ownership_matrix.ts +2 -1
  396. package/src/scripts/generate_pack_manifests.ts +10 -2
  397. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  398. package/src/scripts/generate_settings_reference.ts +1 -1
  399. package/src/scripts/git_authorization_hook.ts +22 -1
  400. package/src/scripts/grade_target_readiness.ts +48 -5
  401. package/src/scripts/hook_effect_doctor.ts +261 -0
  402. package/src/scripts/hook_manifest.json +1 -1
  403. package/src/scripts/hook_manifest.yaml +98 -11
  404. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  405. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  406. package/src/scripts/hooks/concern_registry.ts +4 -0
  407. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  408. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  409. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  410. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  411. package/src/scripts/hooks/shims/install.sh +61 -0
  412. package/src/scripts/hooks/shims/php +101 -0
  413. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  414. package/src/scripts/hot_context_hook.ts +16 -0
  415. package/src/scripts/install-hooks.sh +20 -5
  416. package/src/scripts/install.ts +17 -35
  417. package/src/scripts/inventory_frontmatter.ts +2 -1
  418. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  419. package/src/scripts/lint_canonical_terms.ts +604 -0
  420. package/src/scripts/lint_composition_review.ts +619 -0
  421. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  422. package/src/scripts/lint_eval_specs.ts +593 -0
  423. package/src/scripts/lint_hook_manifest.ts +19 -0
  424. package/src/scripts/lint_host_portability.ts +373 -0
  425. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  426. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  427. package/src/scripts/lint_metric_consumers.ts +355 -0
  428. package/src/scripts/lint_skill_descriptions.ts +18 -1
  429. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  430. package/src/scripts/lint_skill_link_reach.ts +252 -0
  431. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  432. package/src/scripts/lint_ticket_buildable.ts +17 -1
  433. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  434. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  435. package/src/scripts/measure_docs_dead_links.ts +348 -0
  436. package/src/scripts/measure_host_capture.ts +461 -0
  437. package/src/scripts/migration_status.ts +3 -3
  438. package/src/scripts/model_rule_injection.ts +60 -0
  439. package/src/scripts/orchestration_record.ts +14 -0
  440. package/src/scripts/preamble_byte_census.ts +139 -10
  441. package/src/scripts/prepack-check.mjs +4 -1
  442. package/src/scripts/probe_turnaround.ts +384 -0
  443. package/src/scripts/probe_unblocked_ask.ts +279 -0
  444. package/src/scripts/render_benchmark_md.ts +1 -1
  445. package/src/scripts/rule_activation_census.ts +70 -9
  446. package/src/scripts/rule_backlinks.ts +1 -1
  447. package/src/scripts/run_lifecycle_suite.ts +208 -0
  448. package/src/scripts/run_skill_evals.ts +40 -0
  449. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  450. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  451. package/src/scripts/schemas/evals.schema.json +24 -1
  452. package/src/scripts/schemas/rule.schema.json +52 -1
  453. package/src/scripts/schemas/skill.schema.json +17 -2
  454. package/src/scripts/skill_overlap.ts +7 -1
  455. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  456. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  457. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  458. package/src/scripts/skill_usage_report.ts +2 -1
  459. package/src/scripts/stubs_due.ts +211 -0
  460. package/src/scripts/sweep_source_surfaces.ts +678 -0
  461. package/src/scripts/sync_pr_branch.ts +3 -3
  462. package/src/scripts/trigger_eval_grandfather.json +202 -222
  463. package/src/scripts/utilization_report.ts +22 -2
  464. package/src/server/schemas/settings.ts +5 -0
  465. package/src/templates/marketing-copy.yml +1 -1
  466. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Per-judge position-consistency — order-swap over sampled pairwise judgments.
3
+ *
4
+ * `road-to-inbox-harvest-2026-08-e-council-topology-evidence` Phase 3, step 3.5:
5
+ * "repeat sampled pairwise judgments with candidate order reversed; emit a
6
+ * per-judge position-consistency metric", verified by "the metric exists per
7
+ * judge and is reported with the verdict".
8
+ *
9
+ * ── What already existed, and why this is not a second copy of it ────────────
10
+ * `check_quality_regression.evaluatePair` (`:84-108`) already judges every pair
11
+ * in both orders and resolves a flip to `inconsistent` rather than to a winner,
12
+ * and `_lib/judge_hygiene.ts:5-9` records that as stronger than the step that
13
+ * asked for it. Two things it does not do, and both are the point here:
14
+ *
15
+ * 1. It is SINGLE-JUDGE. `aggregate` returns one run-wide `inconsistency_rate`
16
+ * (`:216`), so two judges of differing reliability average into one number
17
+ * that describes neither. The step asks for the metric PER JUDGE, which is
18
+ * what makes it actionable: you can drop the flipper.
19
+ * 2. It reports presence, not DIRECTION. A judge that flips at random and a
20
+ * judge that always prefers whatever it was shown first produce the same
21
+ * inconsistency rate and need opposite remedies — the first is noise, the
22
+ * second is a systematic bias that survives averaging and quietly decides
23
+ * verdicts. `first_position_rate` separates them.
24
+ *
25
+ * That module is the thin-vs-eager token gate and is not council code; this one
26
+ * is council-side and stays a pure library — no transport, no fixture path, no
27
+ * `main`. The judge is an injected function, so the whole surface is testable
28
+ * against a scripted judge and costs nothing to exercise.
29
+ *
30
+ * ── Honest scope ────────────────────────────────────────────────────────────
31
+ * The shipped council has NO pairwise judging stage (`grep -rn pairwise
32
+ * src/scripts/ai_council` returns nothing): members deliberate, peer-review and
33
+ * are scored on findings, never compared two at a time. So this module is the
34
+ * metric and its renderer, exercised by the provider-leakage bench that Phase 3
35
+ * builds; it does not claim a live council verdict currently carries the line,
36
+ * because there is currently no live council judgment for it to describe.
37
+ */
38
+
39
+ import { _sha256_hex } from './blind_review.js';
40
+
41
+ /** A judge's preference between the two PRESENTED candidates — order-relative. */
42
+ export type PairwiseVerdict = 'first' | 'second' | 'tie';
43
+
44
+ /**
45
+ * The pluggable judge. `first`/`second` are the candidate bodies in PRESENTED
46
+ * order, so a judge implementation cannot tell which arm it is looking at
47
+ * unless the bodies themselves leak it.
48
+ */
49
+ export type PairwiseJudge = (ctx: { readonly id: string }, first: string, second: string) => PairwiseVerdict;
50
+
51
+ /** How a pair resolved once both orders were seen. */
52
+ export type PairResolution = 'a' | 'b' | 'tie' | 'inconsistent';
53
+
54
+ export interface SwapObservation {
55
+ readonly id: string;
56
+ /** Verdict with A presented first. */
57
+ readonly forward: PairwiseVerdict;
58
+ /** Verdict with B presented first. */
59
+ readonly reverse: PairwiseVerdict;
60
+ readonly resolution: PairResolution;
61
+ }
62
+
63
+ /**
64
+ * Judge one (a, b) pair in BOTH orders.
65
+ *
66
+ * A verdict that does not survive the swap resolves to `inconsistent`, never to
67
+ * a winner — a flagged tie would still be a tie in somebody's denominator,
68
+ * while `inconsistent` is its own bucket with its own reported rate.
69
+ */
70
+ export function judgeBothOrders(id: string, a: string, b: string, judge: PairwiseJudge): SwapObservation {
71
+ const ctx = { id };
72
+ const forward = judge(ctx, a, b);
73
+ const reverse = judge(ctx, b, a);
74
+ // Normalise each verdict to the CANDIDATE it names, not the position.
75
+ const wf: PairResolution = forward === 'first' ? 'a' : forward === 'second' ? 'b' : 'tie';
76
+ const wr: PairResolution = reverse === 'first' ? 'b' : reverse === 'second' ? 'a' : 'tie';
77
+ const resolution: PairResolution = wf === wr ? wf : 'inconsistent';
78
+ return { id, forward, reverse, resolution };
79
+ }
80
+
81
+ export interface JudgeConsistency {
82
+ readonly judge: string;
83
+ /** Pairs actually repeated in both orders. */
84
+ readonly sampled: number;
85
+ /** Both orders named the same candidate, or both said tie. */
86
+ readonly consistent: number;
87
+ /** The two orders disagreed. */
88
+ readonly inconsistent: number;
89
+ /**
90
+ * `consistent / sampled`. `null` at zero pairs — a rate over an empty
91
+ * denominator is not 1.0, and reporting it as 1.0 would make an unrun swap
92
+ * indistinguishable from a perfectly stable judge.
93
+ */
94
+ readonly position_consistency: number | null;
95
+ /**
96
+ * Share of DECISIVE verdicts (`first`/`second`, both orders pooled) that
97
+ * named whichever candidate was shown FIRST. ~0.5 is unbiased; near 1.0 is
98
+ * primacy, near 0.0 recency. `null` when nothing decisive was said.
99
+ *
100
+ * This is the direction an inconsistency rate cannot show, and the reason a
101
+ * judge that flips at random is a different problem from one that always
102
+ * prefers the top of the list.
103
+ */
104
+ readonly first_position_rate: number | null;
105
+ /** Decisive verdicts counted for `first_position_rate`. */
106
+ readonly decisive_verdicts: number;
107
+ }
108
+
109
+ /** Per-judge metric over that judge's own swapped observations. */
110
+ export function positionConsistency(judge: string, obs: readonly SwapObservation[]): JudgeConsistency {
111
+ let consistent = 0;
112
+ let inconsistent = 0;
113
+ let firstWins = 0;
114
+ let decisive = 0;
115
+ for (const o of obs) {
116
+ if (o.resolution === 'inconsistent') {
117
+ inconsistent += 1;
118
+ } else {
119
+ consistent += 1;
120
+ }
121
+ for (const v of [o.forward, o.reverse]) {
122
+ if (v === 'first') {
123
+ decisive += 1;
124
+ firstWins += 1;
125
+ } else if (v === 'second') {
126
+ decisive += 1;
127
+ }
128
+ }
129
+ }
130
+ const sampled = obs.length;
131
+ return {
132
+ judge,
133
+ sampled,
134
+ consistent,
135
+ inconsistent,
136
+ position_consistency: sampled > 0 ? consistent / sampled : null,
137
+ first_position_rate: decisive > 0 ? firstWins / decisive : null,
138
+ decisive_verdicts: decisive,
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Deterministic sample of `ids` at `rate`, seeded by `seed`.
144
+ *
145
+ * The step says "SAMPLED pairwise judgments", because the swap doubles judge
146
+ * calls and doubling every one of them to measure the judge is a cost the
147
+ * measurement does not need. Deterministic so a published consistency figure is
148
+ * reproducible from the report's own seed — a sample nobody can re-draw is a
149
+ * number nobody can check.
150
+ *
151
+ * `rate <= 0` samples nothing; `rate >= 1` samples everything.
152
+ */
153
+ export function sampleForSwap(ids: readonly string[], rate: number, seed: string): string[] {
154
+ if (!(rate > 0)) {
155
+ return [];
156
+ }
157
+ if (rate >= 1) {
158
+ return [...ids];
159
+ }
160
+ return ids.filter((id) => _unitHash(`${seed} ${id}`) < rate);
161
+ }
162
+
163
+ /**
164
+ * Stable [0,1) hash of a string.
165
+ *
166
+ * Reuses `blind_review._sha256_hex` rather than carrying a local one. That
167
+ * export exists for exactly this reason — `blind_review.ts:38-44` records that
168
+ * two hashes of one input are two answers to one question and the second is the
169
+ * one nobody updates. A hand-rolled FNV-1a was tried here first and its low bits
170
+ * were skewed enough that a rate of 0.25 sampled half the corpus; the test that
171
+ * caught it is kept.
172
+ */
173
+ function _unitHash(s: string): number {
174
+ return parseInt(_sha256_hex(s).slice(0, 8), 16) / 4294967296;
175
+ }
176
+
177
+ /**
178
+ * One report line per judge, for emission BESIDE a verdict.
179
+ *
180
+ * `n/a` rather than a number when nothing was sampled: the step's verify is
181
+ * that the metric is reported, and a report that silently prints nothing for an
182
+ * unrun swap satisfies it only by looking like it ran.
183
+ */
184
+ export function renderPositionConsistency(rows: readonly JudgeConsistency[]): string {
185
+ if (rows.length === 0) {
186
+ return 'position consistency: no judge sampled — order-swap NOT RUN.';
187
+ }
188
+ const pct = (v: number | null): string => (v === null ? 'n/a' : `${(v * 100).toFixed(0)}%`);
189
+ return rows
190
+ .map(
191
+ (r) =>
192
+ `position consistency · ${r.judge}: ${pct(r.position_consistency)} ` +
193
+ `(${String(r.consistent)}/${String(r.sampled)} pairs survived the swap; ` +
194
+ `first-position rate ${pct(r.first_position_rate)} over ${String(r.decisive_verdicts)} decisive verdicts)`,
195
+ )
196
+ .join('\n');
197
+ }
@@ -21,10 +21,14 @@
21
21
  // Failure normalisation (one member's exception → `error`-set
22
22
  // CouncilResponse, never raise) is unchanged.
23
23
 
24
- import { ConsensusResult, CouncilQuestion, PeerReviewResult } from './orchestrator_results.js';
25
- import type { RunConsensusScoringOptions, RunPeerReviewOptions } from './orchestrator_results.js';
24
+ import type { ConsensusResult } from './orchestrator_results.js';
25
+ import { CouncilQuestion, PeerReviewResult } from './orchestrator_results.js';
26
+ import type { RunPeerReviewOptions } from './orchestrator_results.js';
26
27
  export { ConsensusResult, CouncilQuestion, PeerReviewResult } from './orchestrator_results.js';
27
28
  export type { RunConsensusScoringOptions, RunPeerReviewOptions } from './orchestrator_results.js';
29
+ // Moved to its own module for the source-size budget; re-exported so every
30
+ // existing importer of `run_consensus_scoring` is untouched.
31
+ export { run_consensus_scoring } from './consensus_round.js';
28
32
  import {
29
33
  record_spend as _record_daily_spend,
30
34
  today_spend_usd as _today_spend_usd,
@@ -39,16 +43,9 @@ import {
39
43
  import type {
40
44
  ConsensusMetadata,
41
45
  Finding} from './consensus.js';
42
- import {
43
- ConsensusBucket,
44
- FindingScore,
45
- aggregate_scores,
46
- anonymize_findings,
47
- anonymize_responses,
48
- bucket_by_threshold,
49
- parse_findings_outcome,
50
- parse_scores_response,
51
- } from './consensus.js';
46
+ import type { ConsensusBucket } from './consensus.js';
47
+ import { anonymize_responses } from './consensus.js';
48
+ import { composeFinalRoundSuffix } from './inline_findings.js';
52
49
  import type {
53
50
  CostEstimate,
54
51
  PriceTable} from './pricing.js';
@@ -64,9 +61,7 @@ import {
64
61
  ANTI_CONFORMITY_DIRECTIVE,
65
62
  describe_verdict_mismatch,
66
63
  STANCE_LINE_CONTRACT,
67
- build_extraction_user_prompt,
68
64
  build_peer_review_user_prompt,
69
- build_scoring_user_prompt,
70
65
  peer_review_synthesis_addendum,
71
66
  synthesis_template,
72
67
  system_prompt_for,
@@ -366,6 +361,8 @@ export interface ConsultOptions {
366
361
  * context). Default `null` → byte-identical to today.
367
362
  */
368
363
  no_project_context_members?: ReadonlySet<string> | null;
364
+ /** Phase 1B — `composeFinalRoundSuffix`. Default `false` → prompt unchanged. */
365
+ inline_findings?: boolean;
369
366
  /** Mid-flight cli→api fallback; absent → no retry. See `mid_flight_fallback`. */
370
367
  cli_fallback?: CliFallbackOptions | null;
371
368
  }
@@ -435,15 +432,13 @@ export function consult(
435
432
  let current_suffix = '';
436
433
 
437
434
  const stance_tally = opts.stance_tally ?? false;
435
+ const inline_findings = opts.inline_findings ?? false;
438
436
  for (let round_idx = 0; round_idx < rounds; round_idx++) {
439
- // Phase 1: the FINAL round carries the mandatory STANCE closing-line
440
- // contract when the tally is enabled. Off (default) → the original
441
- // question object flows through untouched, byte-identical to today.
437
+ // The FINAL round carries the opt-in closing contracts (STANCE line,
438
+ // inline findings). Both off → the question flows through untouched,
439
+ // byte-identical to today. Order lives in the composer.
442
440
  const is_final = round_idx === rounds - 1;
443
- const suffix_for_round =
444
- is_final && stance_tally
445
- ? `${current_suffix}\n\n---\n\n${STANCE_LINE_CONTRACT}`
446
- : current_suffix;
441
+ const suffix_for_round = composeFinalRoundSuffix(current_suffix, { is_final, inline_findings, stance_tally });
447
442
  const prompt_for_round = `${question.user_prompt}${suffix_for_round}`;
448
443
  const round_question =
449
444
  round_idx === 0 && prompt_for_round === question.user_prompt
@@ -1581,188 +1576,6 @@ export function run_peer_review(
1581
1576
 
1582
1577
 
1583
1578
 
1584
- /**
1585
- * Two-pass consensus round (Phase 4 / F3).
1586
- *
1587
- * Pass 1 — extraction: each member re-emits its own deliberation as
1588
- * a JSON array of `{id, text}` findings. Pass 2 — scoring: each
1589
- * member sees the *other* members' findings under anonymous labels
1590
- * and rates them 1-10 + agree/disagree + reason.
1591
- *
1592
- * The cost budget is shared across both passes; the daily ledger
1593
- * receives both. Errors in one member's extraction or scoring tag
1594
- * that member but never abort the round.
1595
- */
1596
- export function run_consensus_scoring(
1597
- members: ExternalAIClient[],
1598
- deliberation_responses: CouncilResponse[],
1599
- opts: RunConsensusScoringOptions = {},
1600
- ): ConsensusResult {
1601
- const budget = opts.budget ?? null;
1602
- const table = opts.table ?? null;
1603
- const on_overrun = opts.on_overrun ?? null;
1604
- const project = opts.project ?? null;
1605
- const original_ask = opts.original_ask ?? '';
1606
- const max_tokens = opts.max_tokens ?? DEFAULT_MAX_TOKENS;
1607
- const strong_threshold = opts.strong_threshold ?? 0.7;
1608
- const minority_threshold = opts.minority_threshold ?? 0.4;
1609
-
1610
- if (members.length === 0 || deliberation_responses.length === 0) {
1611
- return new ConsensusResult({
1612
- bucket: new ConsensusBucket(),
1613
- findings: [],
1614
- scores: [],
1615
- metadata: new Map(),
1616
- extraction_responses: [],
1617
- scoring_responses: [],
1618
- });
1619
- }
1620
-
1621
- // ── Pass 1: extraction ──────────────────────────────────────────
1622
- const member_by_name = new Map<string, ExternalAIClient>();
1623
- for (const m of members) {
1624
- member_by_name.set(m.name, m);
1625
- }
1626
- const extraction_responses: CouncilResponse[] = [];
1627
- const all_findings: Finding[] = [];
1628
- // Per-member extraction outcome — step 2.2. Recorded rather than derived from the
1629
- // findings count, because "zero findings" and "could not be read" are different facts
1630
- // and the count cannot tell them apart. `parsed-after-reask` is kept distinct from
1631
- // `parsed`: a member that needed a second ask is a signal about the prompt or the
1632
- // member, and collapsing it into `parsed` would hide the only evidence that the
1633
- // re-ask is doing anything.
1634
- const parse_outcomes = new Map<string, string>();
1635
- for (const resp of deliberation_responses) {
1636
- const member = member_by_name.get(resp.provider);
1637
- if (member === undefined || resp.error || !_pyStrip(resp.text)) {
1638
- continue;
1639
- }
1640
- const question = new CouncilQuestion({
1641
- mode: 'prompt',
1642
- user_prompt: build_extraction_user_prompt(resp.text),
1643
- max_tokens,
1644
- });
1645
- const extracted = consult([member], question, budget, {
1646
- table,
1647
- on_overrun,
1648
- project,
1649
- original_ask,
1650
- });
1651
- extraction_responses.push(...extracted);
1652
- if (extracted.length === 0 || extracted[0]!.error) {
1653
- continue;
1654
- }
1655
- const source = `${member.name}:${member.model}`;
1656
- let ex = parse_findings_outcome(extracted[0]!.text, { source });
1657
-
1658
- // Step 2.2 — ONE bounded re-ask on `parse_failed`, and one only.
1659
- //
1660
- // A member that said something no parser could read used to be indistinguishable
1661
- // from a member that found nothing: `parse_findings_response` returned `[]` for
1662
- // both, and this loop pushed the empty array with no branch. So an unparseable
1663
- // answer counted as a clean zero-findings review.
1664
- //
1665
- // ONE re-ask, not a loop. A re-ask is a paid call, and an unbounded retry turns
1666
- // one unparseable answer into open-ended spend — the failure mode the N=3
1667
- // validation budget exists for, reached here by a different road. `empty` is NOT
1668
- // re-asked: a member that said nothing has nothing to restate, and re-asking it
1669
- // buys a second silence.
1670
- if (ex.outcome === 'parse_failed') {
1671
- const retry_q = new CouncilQuestion({
1672
- mode: 'prompt',
1673
- user_prompt:
1674
- build_extraction_user_prompt(resp.text) +
1675
- '\n\nYour previous answer could not be parsed. Reply with ONLY a JSON ' +
1676
- 'array of {"id": string, "text": string} objects, no prose before or ' +
1677
- 'after it. An empty array [] is a valid answer meaning you found nothing.',
1678
- max_tokens,
1679
- });
1680
- const retried = consult([member], retry_q, budget, {
1681
- table,
1682
- on_overrun,
1683
- project,
1684
- original_ask,
1685
- });
1686
- extraction_responses.push(...retried);
1687
- if (retried.length > 0 && !retried[0]!.error) {
1688
- ex = parse_findings_outcome(retried[0]!.text, { source });
1689
- }
1690
- parse_outcomes.set(source, ex.outcome === 'parsed' ? 'parsed-after-reask' : 'parse_failed');
1691
- } else {
1692
- parse_outcomes.set(source, ex.outcome);
1693
- }
1694
- all_findings.push(...ex.findings);
1695
- }
1696
-
1697
- if (all_findings.length === 0) {
1698
- return new ConsensusResult({
1699
- bucket: new ConsensusBucket(),
1700
- findings: [],
1701
- scores: [],
1702
- metadata: new Map(),
1703
- parse_outcomes,
1704
- extraction_responses,
1705
- scoring_responses: [],
1706
- });
1707
- }
1708
-
1709
- // ── Pass 2: scoring (each member rates the OTHERS' findings) ────
1710
- const scoring_responses: CouncilResponse[] = [];
1711
- const all_scores: FindingScore[] = [];
1712
- for (const member of members) {
1713
- const scorer = `${member.name}:${member.model}`;
1714
- const others = all_findings.filter((f) => f.source !== scorer);
1715
- if (others.length === 0) {
1716
- continue;
1717
- }
1718
- const anon = anonymize_findings(others);
1719
- const label_to_id = new Map<string, string>();
1720
- const anon_text = new Map<string, string>();
1721
- for (const [label, f] of anon) {
1722
- label_to_id.set(label, f.id);
1723
- anon_text.set(label, f.text);
1724
- }
1725
- const question = new CouncilQuestion({
1726
- mode: 'prompt',
1727
- user_prompt: build_scoring_user_prompt(anon_text),
1728
- max_tokens,
1729
- });
1730
- const scored = consult([member], question, budget, {
1731
- table,
1732
- on_overrun,
1733
- project,
1734
- original_ask,
1735
- });
1736
- scoring_responses.push(...scored);
1737
- if (scored.length === 0 || scored[0]!.error) {
1738
- continue;
1739
- }
1740
- for (const s of parse_scores_response(scored[0]!.text, { scorer })) {
1741
- const real_id = label_to_id.get(s.finding_id);
1742
- if (real_id === undefined) {
1743
- continue;
1744
- }
1745
- all_scores.push(
1746
- new FindingScore(real_id, s.scorer, s.score, s.agree, s.reason),
1747
- );
1748
- }
1749
- }
1750
-
1751
- const metadata = aggregate_scores(all_findings, all_scores);
1752
- const bucket = bucket_by_threshold(all_findings, metadata, {
1753
- strong: strong_threshold,
1754
- minority: minority_threshold,
1755
- });
1756
- return new ConsensusResult({
1757
- bucket,
1758
- findings: all_findings,
1759
- scores: all_scores,
1760
- metadata,
1761
- parse_outcomes,
1762
- extraction_responses,
1763
- scoring_responses,
1764
- });
1765
- }
1766
1579
 
1767
1580
  /**
1768
1581
  * Format the per-member meta line — tokens, cost (or subscription), latency.
@@ -25,7 +25,14 @@ import type { ProjectContext } from './project_context.js';
25
25
  // The alternative was leaving the two options interfaces behind, which would have meant
26
26
  // finding 19 lines elsewhere for no design reason.
27
27
  import type { OnOverrunCallback } from './orchestrator.js';
28
- import type { ConsensusBucket, ConsensusMetadata, Finding, FindingScore } from './consensus.js';
28
+ import type {
29
+ ConsensusBucket,
30
+ ConsensusMetadata,
31
+ Finding,
32
+ FindingScore,
33
+ FindingsExtraction,
34
+ } from './consensus.js';
35
+ import type { RecordedExtractionOutcome } from './inline_findings.js';
29
36
 
30
37
  /**
31
38
  * Bundle returned by `run_peer_review()` (Phase 5 / F1).
@@ -121,7 +128,7 @@ export class ConsensusResult {
121
128
  *
122
129
  * Additive and optional, so no existing constructor call changes.
123
130
  */
124
- parse_outcomes: Map<string, string>;
131
+ parse_outcomes: Map<string, RecordedExtractionOutcome>;
125
132
  extraction_responses: CouncilResponse[];
126
133
  scoring_responses: CouncilResponse[];
127
134
 
@@ -130,7 +137,7 @@ export class ConsensusResult {
130
137
  findings: Finding[];
131
138
  scores: FindingScore[];
132
139
  metadata: Map<string, ConsensusMetadata>;
133
- parse_outcomes?: Map<string, string>;
140
+ parse_outcomes?: Map<string, RecordedExtractionOutcome>;
134
141
  extraction_responses: CouncilResponse[];
135
142
  scoring_responses: CouncilResponse[];
136
143
  }) {
@@ -163,4 +170,17 @@ export interface RunConsensusScoringOptions {
163
170
  max_tokens?: number;
164
171
  strong_threshold?: number;
165
172
  minority_threshold?: number;
173
+ /**
174
+ * Phase 1B: findings already harvested from each member's own deliberation
175
+ * reply by `harvest_inline_findings`, keyed `provider:model`. A member with
176
+ * an entry skips the separate extraction call entirely; a member without one
177
+ * takes the shipped extraction path unchanged. Absent → extraction-always,
178
+ * call-for-call identical to today.
179
+ *
180
+ * A pre-computed map rather than a boolean because the harvest must run
181
+ * BEFORE peer review and synthesis read the responses, which is upstream of
182
+ * this function — see `harvest_inline_findings` for why that ordering is
183
+ * load-bearing.
184
+ */
185
+ inline_extractions?: ReadonlyMap<string, FindingsExtraction> | null;
166
186
  }
@@ -148,6 +148,112 @@ export function estimate_cost(
148
148
  };
149
149
  }
150
150
 
151
+ // ── billable-aware aggregation ─────────────────────────────────────
152
+ //
153
+ // A vendor-official CLI seat (anthropic / openai / gemini) runs under the
154
+ // user's subscription auth and is `billable = false`; the contract states it
155
+ // in as many words (`docs/contracts/ai-council-config.md:173`). Pricing such
156
+ // an answer at API rates and reporting the figure as spend is the defect these
157
+ // two helpers exist to close, found 2026-08-27: `council_cli.ts` ran
158
+ // `estimate_cost` over every non-errored response with no `billable` check, so
159
+ // one run printed `TOTAL: $0.0000` from the pre-run path (which filters) and
160
+ // `actual $0.1055` from the post-run path, two lines apart.
161
+ //
162
+ // Why the coercion below is not paranoia: `_serialise_responses` stringifies
163
+ // every metadata value with `String(v)`, so a persisted artefact carries
164
+ // `"billable": "false"` — and `Boolean("false")` is `true` in JavaScript. A
165
+ // consumer reading the field back with a bare `Boolean()` sees a subscription
166
+ // seat as billable, which is the same wrong answer arrived at from the other
167
+ // direction.
168
+
169
+ /** The subset of a `CouncilResponse` the cost aggregation reads. */
170
+ export interface BillableCostInput {
171
+ provider: string;
172
+ model: string;
173
+ input_tokens: number;
174
+ output_tokens: number;
175
+ error?: string | null;
176
+ metadata?: Record<string, unknown> | null;
177
+ }
178
+
179
+ /**
180
+ * Does this response represent money actually spent?
181
+ *
182
+ * ABSENT means billable. A missing flag is not evidence of a free call, and
183
+ * defaulting the other way would let a client that forgot to stamp its
184
+ * transport silently zero its own spend.
185
+ */
186
+ export function isBillableResponse(r: BillableCostInput): boolean {
187
+ const raw = (r.metadata ?? {})['billable'];
188
+ if (raw === undefined || raw === null) {
189
+ return true;
190
+ }
191
+ if (typeof raw === 'boolean') {
192
+ return raw;
193
+ }
194
+ if (typeof raw === 'string') {
195
+ // The persisted form. Only the two literals a `String(v)` round-trip
196
+ // can produce are interpreted; anything else falls through to the
197
+ // conservative default rather than being guessed at.
198
+ const t = raw.trim().toLowerCase();
199
+ if (t === 'false') {
200
+ return false;
201
+ }
202
+ return true;
203
+ }
204
+ // Every other type is BILLABLE, not truthiness-of-value. The first draft of
205
+ // this function ended `return Boolean(raw)` while its own comment promised a
206
+ // conservative default, and a council review (2/2) caught the contradiction:
207
+ // `Boolean(0)` and `Boolean([])` are `false`, so a numeric or empty-array
208
+ // value would have zeroed a billable seat's spend. The serialiser should
209
+ // never emit those, which is exactly why guessing at them is wrong.
210
+ return true;
211
+ }
212
+
213
+ /**
214
+ * Did every answered response come from a non-billable transport?
215
+ *
216
+ * Exported because the CLI's output line needs it and must NOT infer it from a
217
+ * zero total. A council review (2/2) rated that inference the highest-severity
218
+ * finding in the first draft, and the reasoning is concrete: `estimate_cost`
219
+ * returns `0.0` when `lookup` finds no price row, so an unpriced BILLABLE model
220
+ * produces a zero total. So do a billable seat that errored and one that
221
+ * reported zero tokens. All three would have printed "all seats
222
+ * subscription-authed" over real spend.
223
+ *
224
+ * Vacuously false on an empty or all-errored set: with nothing answered there is
225
+ * no transport to make a claim about, and silence is the honest output.
226
+ */
227
+ export function allSeatsNonBillable(responses: BillableCostInput[]): boolean {
228
+ const answered = responses.filter((r) => !r.error);
229
+ if (answered.length === 0) {
230
+ return false;
231
+ }
232
+ return answered.every((r) => !isBillableResponse(r));
233
+ }
234
+
235
+ /**
236
+ * Total USD actually spent across a set of responses.
237
+ *
238
+ * Errored responses contribute nothing (no tokens were billed for an answer
239
+ * that never arrived), and non-billable transports contribute nothing (the
240
+ * subscription already paid). What remains is spend.
241
+ */
242
+ export function sumBillableCost(responses: BillableCostInput[], table: PriceTable): number {
243
+ let total = 0.0;
244
+ for (const r of responses) {
245
+ if (r.error) {
246
+ continue;
247
+ }
248
+ if (!isBillableResponse(r)) {
249
+ continue;
250
+ }
251
+ const ce = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table);
252
+ total += ce.input_usd + ce.output_usd;
253
+ }
254
+ return total;
255
+ }
256
+
151
257
  // ── prompt-cache repricing ─────────────────────────────────────────
152
258
  //
153
259
  // Prompt-cache multipliers derived from the base input rate (Anthropic, GA —