@event4u/agent-config 14.20.0 → 14.22.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 (242) 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 +441 -0
  5. package/CREDITS.md +37 -0
  6. package/README.md +1 -1
  7. package/agents/templates/.ai-council.yml.example +10 -0
  8. package/dist/agent-src/commands/analyze/inbox.md +381 -6
  9. package/dist/agent-src/commands/analyze/{reference-repo.md → repo.md} +251 -34
  10. package/dist/agent-src/commands/analyze/roadmap-repos.md +129 -0
  11. package/dist/agent-src/commands/analyze.md +12 -7
  12. package/dist/agent-src/commands/feature/plan.md +55 -16
  13. package/dist/agent-src/commands/feature/refactor.md +8 -3
  14. package/dist/agent-src/commands/humanize.md +48 -4
  15. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
  16. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
  17. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +22 -1
  18. package/dist/agent-src/contexts/execution/host-capability-manifest.md +4 -1
  19. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +35 -2
  20. package/dist/agent-src/contexts/execution/terminal-states.md +4 -1
  21. package/dist/agent-src/rules/evaluator-independence.md +4 -4
  22. package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
  23. package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
  24. package/dist/agent-src/rules/token-efficiency.md +26 -3
  25. package/dist/agent-src/scripts/_cli_entry.ts +51 -0
  26. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +14 -23
  27. package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
  28. package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
  29. package/dist/agent-src/scripts/stubs_due.ts +4 -18
  30. package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
  31. package/dist/agent-src/skills/code-intelligence/SKILL.md +25 -0
  32. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  33. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +27 -11
  34. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
  35. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  36. package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
  37. package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
  38. package/dist/agent-src/skills/technical-specification/SKILL.md +4 -0
  39. package/dist/agent-src/templates/agent-settings.md +0 -1
  40. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  41. package/dist/agent-src/templates/features.md +5 -0
  42. package/dist/agent-src/templates/roadmaps.md +15 -0
  43. package/dist/cli-delegate/_cli_entry.js +8 -0
  44. package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
  45. package/dist/cli-delegate/archival_sweep.js +8 -0
  46. package/dist/cli-delegate/archive_completed_roadmaps.js +494 -0
  47. package/dist/cli-delegate/check_update_banner.js +923 -0
  48. package/dist/cli-delegate/{chunk-KPBWFOPZ.js → chunk-2FTMENJL.js} +194 -37
  49. package/dist/cli-delegate/{chunk-PI2GU3DP.js → chunk-2TAQ2K4V.js} +4 -1
  50. package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
  51. package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
  52. package/dist/cli-delegate/{chunk-C6IPZRDA.js → chunk-BIXEDQPZ.js} +7 -1
  53. package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
  54. package/dist/cli-delegate/{chunk-NUMQHLS5.js → chunk-J3RFNKG4.js} +21 -2
  55. package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
  56. package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
  57. package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
  58. package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-TGIPZBCW.js} +1 -1
  59. package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
  60. package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
  61. package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
  62. package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
  63. package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
  64. package/dist/cli-delegate/cmd_conformance.js +19 -5
  65. package/dist/cli-delegate/cmd_doctor.js +3 -3
  66. package/dist/cli-delegate/cmd_export.js +2 -2
  67. package/dist/cli-delegate/cmd_handoff.js +27 -3
  68. package/dist/cli-delegate/cmd_prune.js +2 -2
  69. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  70. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  71. package/dist/cli-delegate/cmd_sync.js +2 -2
  72. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  73. package/dist/cli-delegate/cmd_validate.js +2 -2
  74. package/dist/cli-delegate/dashboard_mode.js +16 -0
  75. package/dist/cli-delegate/gate_budget.js +24 -0
  76. package/dist/cli-delegate/gate_execute.js +25 -0
  77. package/dist/cli-delegate/guarded_baseline.js +18 -0
  78. package/dist/cli-delegate/resume_probe.js +22 -0
  79. package/dist/cli-delegate/roadmap_gates.js +638 -0
  80. package/dist/cli-delegate/roadmap_set_step.js +173 -0
  81. package/dist/cli-delegate/stub_queue.js +47 -0
  82. package/dist/cli-delegate/stubs_due.js +38 -0
  83. package/dist/cli-delegate/ticket_bundles.js +59 -0
  84. package/dist/cli-delegate/update_roadmap_progress.js +60 -0
  85. package/dist/discovery/deprecation-report.md +1 -1
  86. package/dist/discovery/discovery-manifest.json +60 -29
  87. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  88. package/dist/discovery/discovery-manifest.summary.md +3 -3
  89. package/dist/discovery/dormancy-report.md +1 -1
  90. package/dist/discovery/orphan-report.md +1 -1
  91. package/dist/discovery/packs.json +7 -6
  92. package/dist/discovery/trust-report.md +2 -2
  93. package/dist/discovery/workspaces.json +6 -5
  94. package/dist/hooks/dispatch.js +1522 -1008
  95. package/dist/install/claudeLayerCarriage.js +237 -0
  96. package/dist/install/claudePathsPlan.js +79 -0
  97. package/dist/install/hostLayerFingerprint.js +1 -1
  98. package/dist/install/install.mjs +10 -1
  99. package/dist/install/partitionEligibility.js +231 -117
  100. package/dist/install/ruleLayerPartition.js +10 -7
  101. package/dist/mcp/registry-manifest.json +3 -3
  102. package/dist/mcp/server.json +2 -2
  103. package/dist/mcp/server.mjs +39376 -38902
  104. package/dist/scripts/ai_council/content_ceiling.js +63 -0
  105. package/dist/scripts/ai_council/seat_policy.js +106 -0
  106. package/dist/scripts/ai_council/transport_resolver.js +21 -0
  107. package/dist/scripts/condense.js +32 -25
  108. package/docs/MIGRATION.md +49 -1
  109. package/docs/contracts/settings-classes.md +1 -1
  110. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
  111. package/llms.txt +14 -14
  112. package/package.json +7 -4
  113. package/src/agent-src/scripts/_cli_entry.ts +51 -0
  114. package/src/agent-src/scripts/archive_completed_roadmaps.ts +14 -23
  115. package/src/agent-src/scripts/roadmap_gates.ts +4 -20
  116. package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
  117. package/src/agent-src/scripts/stubs_due.ts +4 -18
  118. package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
  119. package/src/config/continuity-surface.json +509 -0
  120. package/src/config/estate-count-budget.json +1 -1
  121. package/src/config/gate-coverage.yml +29 -8
  122. package/src/config/gate-violation-baselines.json +8 -8
  123. package/src/config/gitignore-block.txt +19 -0
  124. package/src/config/host-injection-effect.json +73 -0
  125. package/src/config/packed-binary-manifest.json +33 -0
  126. package/src/config/preamble-payload-budget.json +112 -105
  127. package/src/config/publish-surface.json +4 -2
  128. package/src/config/release-gate-locality.yml +4 -3
  129. package/src/install/claudeLayerCarriage.ts +273 -0
  130. package/src/install/claudePathsPlan.ts +76 -0
  131. package/src/install/hostLayerFingerprint.ts +1 -1
  132. package/src/install/partitionEligibility.ts +261 -127
  133. package/src/install/ruleLayerPartition.ts +19 -23
  134. package/src/scripts/_dispatch.bash +77 -27
  135. package/src/scripts/_lib/auto_dispatch.ts +2 -2
  136. package/src/scripts/_lib/blocked_by_marker.ts +189 -0
  137. package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
  138. package/src/scripts/_lib/continuity_surface.ts +296 -0
  139. package/src/scripts/_lib/corpus_manifest.ts +26 -9
  140. package/src/scripts/_lib/hook_settings.ts +1 -1
  141. package/src/scripts/_lib/host_capability.ts +38 -1
  142. package/src/scripts/_lib/injection_effect.ts +151 -0
  143. package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
  144. package/src/scripts/_lib/packed_binary_predicate.ts +225 -0
  145. package/src/scripts/_lib/pin_resolver.ts +13 -0
  146. package/src/scripts/_lib/regression_neighbourhood.ts +1 -1
  147. package/src/scripts/_lib/release_highlights.ts +19 -211
  148. package/src/scripts/_lib/release_material.ts +27 -77
  149. package/src/scripts/_lib/retired_status.ts +74 -0
  150. package/src/scripts/_lib/skill_catalogue.ts +156 -21
  151. package/src/scripts/_lib/structured_ask.ts +117 -0
  152. package/src/scripts/_lib/subagent_capsule.ts +117 -8
  153. package/src/scripts/_lib/tty_prompt.ts +76 -0
  154. package/src/scripts/ai_council/api_transport.ts +168 -0
  155. package/src/scripts/ai_council/clients.ts +58 -63
  156. package/src/scripts/ai_council/config.ts +13 -0
  157. package/src/scripts/ai_council/content_ceiling.ts +79 -0
  158. package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
  159. package/src/scripts/ai_council/jury_aggregate.ts +178 -0
  160. package/src/scripts/ai_council/prompts.ts +9 -0
  161. package/src/scripts/ai_council/seat_policy.ts +137 -0
  162. package/src/scripts/ai_council/status_surface.ts +79 -0
  163. package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
  164. package/src/scripts/ai_council/transport_resolver.ts +59 -1
  165. package/src/scripts/ai_tells_rules.ts +446 -5
  166. package/src/scripts/ask_block_census.ts +499 -0
  167. package/src/scripts/bench_humanizer_eval.ts +264 -40
  168. package/src/scripts/bench_prose_tells_fp.ts +198 -0
  169. package/src/scripts/capture_skill_catalogue.ts +24 -11
  170. package/src/scripts/check_branch_work_committed.ts +234 -0
  171. package/src/scripts/check_candidate_lines.ts +499 -0
  172. package/src/scripts/check_continuity_surface.ts +475 -0
  173. package/src/scripts/check_dependency_floors.ts +13 -6
  174. package/src/scripts/check_estate_count.ts +40 -79
  175. package/src/scripts/check_pack_size.ts +263 -24
  176. package/src/scripts/check_release_highlights.ts +0 -157
  177. package/src/scripts/check_roadmap_trackable.ts +19 -16
  178. package/src/scripts/check_rule_layer_partition.ts +54 -34
  179. package/src/scripts/check_single_delivery.ts +97 -31
  180. package/src/scripts/check_update_banner.ts +13 -0
  181. package/src/scripts/code_graph/build.ts +138 -15
  182. package/src/scripts/code_graph/cli.ts +76 -8
  183. package/src/scripts/code_graph/extract.ts +11 -0
  184. package/src/scripts/code_graph/grammar_probe.ts +43 -0
  185. package/src/scripts/code_graph/loader.ts +88 -14
  186. package/src/scripts/code_graph/query.ts +121 -11
  187. package/src/scripts/code_graph/resolution_tiers.ts +238 -0
  188. package/src/scripts/code_graph/sqlite_store.ts +247 -6
  189. package/src/scripts/code_graph/types.ts +66 -1
  190. package/src/scripts/code_graph/validate.ts +23 -0
  191. package/src/scripts/condense.ts +34 -22
  192. package/src/scripts/corpus_manifest.ts +5 -5
  193. package/src/scripts/council_cli.ts +29 -39
  194. package/src/scripts/count_intent_disagreement.ts +426 -0
  195. package/src/scripts/detect_ai_tells.ts +142 -20
  196. package/src/scripts/handoff_context_hook.ts +79 -0
  197. package/src/scripts/harvest_reference_tokens.ts +698 -0
  198. package/src/scripts/hook_effect_doctor.ts +82 -1
  199. package/src/scripts/hook_manifest.json +1 -1
  200. package/src/scripts/hook_manifest.yaml +94 -12
  201. package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
  202. package/src/scripts/hooks/code_graph_context_hook.ts +212 -0
  203. package/src/scripts/hooks/concern_registry.ts +6 -2
  204. package/src/scripts/hooks/delegation_nudge_hook.ts +45 -1
  205. package/src/scripts/hooks/host_semantics.ts +1 -1
  206. package/src/scripts/hooks/one_question_per_ask_hook.ts +191 -0
  207. package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
  208. package/src/scripts/hooks/rule_inject_hook.ts +1 -1
  209. package/src/scripts/hooks/skill_route_hook.ts +11 -4
  210. package/src/scripts/inbox_source_census.ts +322 -0
  211. package/src/scripts/install-hooks.sh +134 -0
  212. package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
  213. package/src/scripts/lint_plan_risk_register.ts +13 -17
  214. package/src/scripts/lint_roadmap_blockers.ts +51 -1
  215. package/src/scripts/mcp_server/suggest_skill.ts +72 -0
  216. package/src/scripts/mcp_server/tools.ts +2 -56
  217. package/src/scripts/media/lib/adapter-contract.md +7 -2
  218. package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
  219. package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
  220. package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
  221. package/src/scripts/migrate_command_suggestions.ts +1 -1
  222. package/src/scripts/probe_unblocked_ask.ts +135 -2
  223. package/src/scripts/rdp_candidates_delta.ts +276 -0
  224. package/src/scripts/rdp_quality_eval.ts +217 -19
  225. package/src/scripts/release.ts +26 -71
  226. package/src/scripts/release_drill.ts +6 -10
  227. package/src/scripts/release_env.ts +1 -0
  228. package/src/scripts/release_mix_taxonomy.json +3 -2
  229. package/src/scripts/release_publication.ts +34 -29
  230. package/src/scripts/report_host_injection_effect.ts +189 -0
  231. package/src/scripts/report_layer_overlap.ts +41 -0
  232. package/src/scripts/report_skill_menu_census.ts +341 -0
  233. package/src/scripts/self_review_gate.ts +409 -15
  234. package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
  235. package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
  236. package/src/vendor/grammars/README.md +61 -0
  237. package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
  238. package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
  239. package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
  240. package/src/scripts/_lib/carrier_status.ts +0 -118
  241. package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
  242. package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
@@ -17,6 +17,55 @@ export type EdgeConfidence = 'EXTRACTED' | 'INFERRED' | 'AMBIGUOUS';
17
17
  /** Relations the extractor emits. */
18
18
  export type Relation = 'calls' | 'imports' | 'uses' | 'inherits' | 'member';
19
19
 
20
+ /**
21
+ * HOW an edge's target was arrived at — the mechanism, not the confidence.
22
+ *
23
+ * The two axes are independent and conflating them is what this field fixes.
24
+ * `confidence` says how much to trust the target; `resolved_via` says what
25
+ * produced it, which is the axis a consumer filters on. Phase 3's verbs accept
26
+ * an edge when `resolved_via` is not in `{name-lookup, dynamic}` — a rule that
27
+ * cannot be expressed in the confidence scale at all, because a `name-lookup`
28
+ * hit and a same-file hit can both be INFERRED.
29
+ *
30
+ * Four of the eight occur today, and saying which is the point of an enum that
31
+ * is wider than its current population:
32
+ *
33
+ * · `same-file` — a local declaration in the using file. The language's own
34
+ * shadowing rule makes this the strongest binding there is.
35
+ * · `import-specifier` — an import/`use` binding: the file states where the
36
+ * name comes from.
37
+ * · `name-lookup` — the repo-wide same-name table, or an attempted lookup that
38
+ * found nothing and left a `symbol:` pseudo-target. A guess either way, and
39
+ * the value that says so.
40
+ * · `dynamic` — a receiver the extractor cannot type (`$obj->m()`, an
41
+ * unresolved `C::m()`), or a hierarchy rooted outside the repository.
42
+ *
43
+ * The remaining four are declared and currently unemitted: `path-alias` and
44
+ * `psr4` arrive with the resolution tiers in step 2.3, and `route-table` /
45
+ * `test-import` with the relations Phase 3 adds. They are in the union now so
46
+ * that adding them later is a build change rather than a schema change.
47
+ */
48
+ export type ResolvedVia =
49
+ | 'same-file'
50
+ | 'import-specifier'
51
+ | 'path-alias'
52
+ | 'psr4'
53
+ | 'route-table'
54
+ | 'test-import'
55
+ | 'name-lookup'
56
+ | 'dynamic';
57
+
58
+ /**
59
+ * WHICH engine produced the edge.
60
+ *
61
+ * One value, and the field exists anyway: an edge with no provider is
62
+ * indistinguishable from an edge whose provider nobody recorded, and the whole
63
+ * point of a mixed graph — should one ever exist — is being able to tell them
64
+ * apart. Kill register K2 forbids an external provider entering `src/`, so this
65
+ * stays a single-member union until a decision changes that.
66
+ */
67
+ export type EdgeProvider = 'native';
68
+
20
69
  export interface CodeNode {
21
70
  /** Path-qualified from day one: `<relpath>#<symbol>` (collision-free). */
22
71
  id: string;
@@ -45,6 +94,14 @@ export interface CodeEdge {
45
94
  target: string;
46
95
  relation: Relation;
47
96
  confidence: EdgeConfidence;
97
+ /**
98
+ * REQUIRED. Not optional, so "no edge lacks either field" is a property the
99
+ * type system enforces at every construction site rather than a rule a
100
+ * linter has to re-check afterwards.
101
+ */
102
+ resolved_via: ResolvedVia;
103
+ /** REQUIRED, for the same reason. */
104
+ provider: EdgeProvider;
48
105
  /**
49
106
  * Present only on AMBIGUOUS / multi-candidate edges: the resolved-target
50
107
  * candidates by id. An AMBIGUOUS edge is "correct" when the true target is
@@ -105,6 +162,14 @@ export interface CodeGraph {
105
162
  }
106
163
 
107
164
  /**
165
+ * Bumped 2 → 3 by `road-to-a-graph-that-is-shipped` 2.2: every `CodeEdge` now
166
+ * carries `resolved_via` and `provider`. A cached sidecar written at v2 has
167
+ * neither, so `--update` would reuse untagged edges beside tagged ones and
168
+ * produce a graph whose `resolved_via` histogram silently under-counts —
169
+ * exactly the mixed-graph failure the previous bump describes. `readSidecar`
170
+ * refuses a version mismatch, which is what makes that impossible rather than
171
+ * merely unlikely.
172
+ *
108
173
  * Bumped 1 → 2 by `road-to-the-graph-that-lies-confidently`: `CodeNode.kind`
109
174
  * gained three members, `CodeGraph` gained `suppressed_edge_counts`, and the
110
175
  * per-file extract sidecar gained the import specifier. A cached sidecar
@@ -113,7 +178,7 @@ export interface CodeGraph {
113
178
  * file — a silently mixed graph. `readSidecar` refuses a version mismatch, so
114
179
  * the bump is what makes that impossible rather than merely unlikely.
115
180
  */
116
- export const SCHEMA_VERSION = 2;
181
+ export const SCHEMA_VERSION = 3;
117
182
 
118
183
  /** Deterministic per-file byte cap — files above this become a SKIPPED node. */
119
184
  export const MAX_FILE_BYTES = 1_000_000;
@@ -6,6 +6,19 @@ import type { CodeGraph } from './types.js';
6
6
 
7
7
  const RELATIONS = new Set(['calls', 'imports', 'uses', 'inherits', 'member']);
8
8
  const CONFIDENCES = new Set(['EXTRACTED', 'INFERRED', 'AMBIGUOUS']);
9
+ /** Mirrors `ResolvedVia` in types.ts — the full union, including the four
10
+ * values no build emits yet (2.3 and Phase 3 add them). */
11
+ const RESOLVED_VIA = new Set([
12
+ 'same-file',
13
+ 'import-specifier',
14
+ 'path-alias',
15
+ 'psr4',
16
+ 'route-table',
17
+ 'test-import',
18
+ 'name-lookup',
19
+ 'dynamic',
20
+ ]);
21
+ const PROVIDERS = new Set(['native']);
9
22
  const KINDS = new Set([
10
23
  'file',
11
24
  'class',
@@ -57,6 +70,16 @@ export function validateGraph(g: unknown): ValidateResult {
57
70
  if (!RELATIONS.has(ee['relation'] as string)) push(`edge[${i}].relation invalid: ${String(ee['relation'])}`);
58
71
  if (!CONFIDENCES.has(ee['confidence'] as string))
59
72
  push(`edge[${i}].confidence invalid: ${String(ee['confidence'])}`);
73
+ // Both are REQUIRED (2.2). Checked as presence-and-membership rather
74
+ // than membership alone, because an absent field and a misspelled one
75
+ // are different defects: absent means the build did not tag the edge,
76
+ // misspelled means the taxonomy drifted.
77
+ if (ee['resolved_via'] === undefined) push(`edge[${i}].resolved_via is required`);
78
+ else if (!RESOLVED_VIA.has(ee['resolved_via'] as string))
79
+ push(`edge[${i}].resolved_via invalid: ${String(ee['resolved_via'])}`);
80
+ if (ee['provider'] === undefined) push(`edge[${i}].provider is required`);
81
+ else if (!PROVIDERS.has(ee['provider'] as string))
82
+ push(`edge[${i}].provider invalid: ${String(ee['provider'])}`);
60
83
  // a source must be a known node; targets may be unresolved `symbol:` refs
61
84
  if (typeof ee['source'] === 'string' && !ids.has(ee['source'] as string))
62
85
  push(`edge[${i}].source is not a known node: ${String(ee['source'])}`);
@@ -265,9 +265,9 @@ export {
265
265
  } from '../install/claudePathsPlan.js';
266
266
  import { rule_in_scope } from '../install/ruleInScope.js';
267
267
  import { pruneEmptyDirs } from './_lib/prune_empty_dirs.js';
268
- import { commandsWithheld, partitionActive, personaPartition, setPartitionAnnounce } from '../install/partitionEligibility.js'; // ADR-236
268
+ import { claudeLayerHolds, commandWithheld, keepInProjectLayer, personaPartition } from '../install/partitionEligibility.js'; // ADR-236
269
269
  import { dedupableRules, partitionRulesForDir } from '../install/ruleLayerPartition.js'; // ADR-236, per-host evidence
270
- import { _claude_paths_plan, derive_trigger_globs } from '../install/claudePathsPlan.js';
270
+ import { _claude_paths_plan, applies_when, derive_trigger_globs } from '../install/claudePathsPlan.js';
271
271
 
272
272
  const _HERE = path.dirname(fileURLToPath(import.meta.url)); // <repo>/src/scripts
273
273
  const _DEFAULT_PROJECT_ROOT = path.resolve(_HERE, '..', '..');
@@ -320,7 +320,6 @@ function _deriveState(root: string): ModuleState {
320
320
  }
321
321
 
322
322
  export const MODULE_STATE: ModuleState = _deriveState(_DEFAULT_PROJECT_ROOT);
323
- setPartitionAnnounce(success); // ADR-236: the mode line must be visible at the default level
324
323
 
325
324
  /**
326
325
  * Test seam — reassign one or more module-state fields, mirroring the pytest
@@ -1299,7 +1298,7 @@ export function _emit_cursor_mdc(source: string, target: string): void {
1299
1298
  const globs = always_apply ? [] : derive_trigger_globs(meta);
1300
1299
  const lines = [
1301
1300
  '---',
1302
- `description: ${_yaml_scalar(description)}`,
1301
+ `description: ${_yaml_scalar(always_apply ? description : applies_when(description, meta))}`,
1303
1302
  `globs: ${globs.join(',')}`,
1304
1303
  `alwaysApply: ${always_apply ? 'true' : 'false'}`,
1305
1304
  '---',
@@ -1321,7 +1320,7 @@ export function _emit_windsurf_rule(source: string, target: string): void {
1321
1320
  const lines = [
1322
1321
  '---',
1323
1322
  `trigger: ${trigger}`,
1324
- `description: ${_yaml_scalar(description)}`,
1323
+ `description: ${_yaml_scalar(always_apply ? description : applies_when(description, meta))}`,
1325
1324
  `globs: ${globs.join(',')}`,
1326
1325
  '---',
1327
1326
  '',
@@ -1628,23 +1627,22 @@ function _render_native_model_md(src_md: string, tier: string): string {
1628
1627
  }
1629
1628
 
1630
1629
  export function generate_claude_skills(active_skill_names: ReadonlySet<string> | null = null): number {
1631
- if (partitionActive(MODULE_STATE.PROJECT_ROOT)) active_skill_names = new Set<string>();
1632
1630
  if (!_exists(MODULE_STATE.SKILLS_SOURCE)) {
1633
1631
  process.stderr.write(' ⚠️ dist/agent-src/skills/ not found — skipping skills\n');
1634
1632
  return 0;
1635
1633
  }
1636
1634
 
1637
- let skills = _iterdirSorted(MODULE_STATE.SKILLS_SOURCE)
1635
+ const all_skills = _iterdirSorted(MODULE_STATE.SKILLS_SOURCE)
1638
1636
  .filter((p) => _isDir(p))
1639
1637
  .map((p) => path.basename(p))
1640
1638
  .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
1639
+ // ADR-236: withhold every skill `~/.claude/skills` holds — see `keepInProjectLayer`.
1640
+ let skills = keepInProjectLayer('skills', all_skills);
1641
1641
  if (active_skill_names !== null) {
1642
1642
  skills = skills.filter((s) => active_skill_names.has(s));
1643
1643
  }
1644
1644
  const skill_set = new Set(skills);
1645
- const command_slugs = partitionActive(MODULE_STATE.PROJECT_ROOT)
1646
- ? new Set<string>()
1647
- : new Set([...iterCommands()].map(([, slug]) => slug));
1645
+ const command_slugs = _emitted_wrapper_slugs(new Set(all_skills));
1648
1646
 
1649
1647
  _mkdirp(MODULE_STATE.CLAUDE_SKILLS_DIR);
1650
1648
  const auto = _read_model_auto_switch() === 'auto';
@@ -1737,6 +1735,22 @@ function _nested_command_subpath(source_file: string): string | null {
1737
1735
  return sub.includes('/') ? sub : null;
1738
1736
  }
1739
1737
 
1738
+ /** The emitter's four skips, in one place — see `emittedWrapperSlugs`. */
1739
+ const _wrapper_is_emitted = (f: string, s: string, skills: ReadonlySet<string>): boolean =>
1740
+ !skills.has(s) &&
1741
+ _nested_command_subpath(f) === null &&
1742
+ !is_claude_builtin_name(s) &&
1743
+ !claudeLayerHolds('skills', s);
1744
+
1745
+ /** Wrapper slugs the command emitter really writes — see `emittedWrapperSlugs`. */
1746
+ function _emitted_wrapper_slugs(skill_names: ReadonlySet<string>): Set<string> {
1747
+ return new Set(
1748
+ [...iterCommands()]
1749
+ .filter(([f, s]) => _wrapper_is_emitted(f, s, skill_names))
1750
+ .map(([, slug]) => slug),
1751
+ );
1752
+ }
1753
+
1740
1754
  /**
1741
1755
  * Project-scope `.claude/commands/<cluster>/<sub>.md` — the colon form.
1742
1756
  *
@@ -1749,7 +1763,7 @@ function _nested_command_subpath(source_file: string): string | null {
1749
1763
  *
1750
1764
  * Emitting the nested form here lets `generate_claude_commands` stop wrapping
1751
1765
  * the clustered commands: one listing, same reachability, and reachability no
1752
- * longer depends on a global deploy. Dedup AND precedence: `commandsWithheld`.
1766
+ * longer depends on a global deploy. Dedup AND precedence: `commandWithheld`.
1753
1767
  *
1754
1768
  * ADR-003 (colon canonical for clusters) and ADR-044 (flat commands stay
1755
1769
  * hyphenated) both hold: flat commands are untouched and keep their wrapper.
@@ -1757,8 +1771,6 @@ function _nested_command_subpath(source_file: string): string | null {
1757
1771
  export function generate_claude_project_commands(
1758
1772
  active_command_slugs: ReadonlySet<string> | null = null,
1759
1773
  ): number {
1760
- if (commandsWithheld(MODULE_STATE.PROJECT_ROOT)) active_command_slugs = new Set<string>();
1761
- // Returns before the stale sweep — invariant, see `commandsWithheld`.
1762
1774
  if (!_isDir(path.join(MODULE_STATE.PROJECT_ROOT, 'src', 'domains'))) {
1763
1775
  return 0;
1764
1776
  }
@@ -1768,7 +1780,7 @@ export function generate_claude_project_commands(
1768
1780
  continue;
1769
1781
  }
1770
1782
  const sub = _nested_command_subpath(source_file);
1771
- if (sub !== null) {
1783
+ if (sub !== null && !commandWithheld(`${sub}.md`)) {
1772
1784
  nested.push([source_file, sub]);
1773
1785
  }
1774
1786
  }
@@ -1805,7 +1817,6 @@ export function generate_claude_project_commands(
1805
1817
  }
1806
1818
 
1807
1819
  export function generate_claude_commands(active_command_slugs: ReadonlySet<string> | null = null): number {
1808
- if (partitionActive(MODULE_STATE.PROJECT_ROOT)) active_command_slugs = new Set<string>();
1809
1820
  if (!_isDir(path.join(MODULE_STATE.PROJECT_ROOT, 'src', 'domains'))) {
1810
1821
  process.stderr.write(' ⚠️ src/domains/ not found — skipping commands\n');
1811
1822
  return 0;
@@ -1826,6 +1837,7 @@ export function generate_claude_commands(active_command_slugs: ReadonlySet<strin
1826
1837
  let count = 0;
1827
1838
  let skipped = 0;
1828
1839
  let reserved = 0;
1840
+ let withheld = 0;
1829
1841
  let rendered = 0;
1830
1842
  const auto = _read_model_auto_switch() === 'auto';
1831
1843
  for (const [source_file, slug] of iterCommands()) {
@@ -1854,6 +1866,9 @@ export function generate_claude_commands(active_command_slugs: ReadonlySet<strin
1854
1866
  reserved += 1;
1855
1867
  continue;
1856
1868
  }
1869
+ // ADR-236 per-name: the INSTALLER re-projects visible flat commands as
1870
+ // `~/.claude/skills/<slug>/SKILL.md` (install.ts:_apply_claude_flat_command_wrappers).
1871
+ if (claudeLayerHolds('skills', slug)) { withheld += 1; continue; }
1857
1872
  current_slugs.add(slug);
1858
1873
 
1859
1874
  const skill_dir = path.join(MODULE_STATE.CLAUDE_SKILLS_DIR, slug);
@@ -1906,6 +1921,9 @@ export function generate_claude_commands(active_command_slugs: ReadonlySet<strin
1906
1921
  if (reserved) {
1907
1922
  msg += ` (${reserved} withheld — Claude Code built-in name)`;
1908
1923
  }
1924
+ if (withheld > 0) {
1925
+ msg += ` (${withheld} withheld — ~/.claude/skills carries the wrapper)`;
1926
+ }
1909
1927
  if (removed_dirs) {
1910
1928
  msg += ` (${removed_dirs} stale dirs removed)`;
1911
1929
  }
@@ -2244,19 +2262,13 @@ export function generate_persona_symlinks(): number {
2244
2262
  _print(' ⚠️ dist/agent-src/personas/ not found — skipping personas');
2245
2263
  return 0;
2246
2264
  }
2247
- const personas = _rglobSorted(MODULE_STATE.PERSONAS_SOURCE, '*.md')
2248
- .filter((p) => _isFile(p) && path.basename(p, '.md') !== 'README')
2249
- .map((p) => path.basename(p))
2250
- // glob('*.md') is non-recursive in Python; mirror that — only top level.
2251
- .filter((name) => _isFile(path.join(MODULE_STATE.PERSONAS_SOURCE, name)));
2252
2265
  // Python uses PERSONAS_SOURCE.glob("*.md") (non-recursive). Re-derive
2253
2266
  // from a direct listing to match exactly.
2254
2267
  const direct = _iterdirSorted(MODULE_STATE.PERSONAS_SOURCE)
2255
2268
  .filter((p) => p.endsWith('.md') && _isFile(p) && path.basename(p, '.md') !== 'README')
2256
2269
  .map((p) => path.basename(p))
2257
2270
  .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
2258
- void personas;
2259
- const partition = personaPartition(MODULE_STATE.PROJECT_ROOT, direct);
2271
+ const partition = personaPartition(direct);
2260
2272
  const tool_dirs = _filter_tool_dirs(PERSONA_TOOL_DIRS);
2261
2273
  let total = 0;
2262
2274
  for (const [tool_dir, rel_prefix] of Object.entries(tool_dirs)) {
@@ -23,7 +23,7 @@ import * as path from 'node:path';
23
23
  import process from 'node:process';
24
24
  import { fileURLToPath } from 'node:url';
25
25
 
26
- import { partitionActive } from '../install/partitionEligibility.js';
26
+ import { resolveHostLayerVerdict } from '../install/partitionEligibility.js';
27
27
  import {
28
28
  type CorpusManifest,
29
29
  captureManifest,
@@ -126,9 +126,9 @@ export function parseArgs(argv: readonly string[]): Parsed | string {
126
126
  /**
127
127
  * One real capture over the real tree.
128
128
  *
129
- * This is the one caller for which the process globals `partitionActive` reads
130
- * — the host layer under the running user's home, and the install lockfile —
131
- * ARE this run's own host, so it is the one caller that passes the predicate.
129
+ * This is the one caller for which the process globals `resolveHostLayerVerdict`
130
+ * reads — the host layer under the running user's home, and the install lockfile
131
+ * — ARE this run's own host, so it is the one caller that passes the predicate.
132
132
  * Everywhere else the field stays `null` rather than recording some other
133
133
  * machine's state under this tree's name.
134
134
  */
@@ -138,7 +138,7 @@ function capture(limit: number): CorpusManifest {
138
138
  userHome: process.env['HOME'] ?? os.homedir(),
139
139
  limit,
140
140
  enumerationRule: ENUMERATION_RULE_ID,
141
- partitionActive,
141
+ hostLayerVerified: (root) => resolveHostLayerVerdict(root).verified,
142
142
  });
143
143
  }
144
144
 
@@ -78,8 +78,11 @@ import {
78
78
  } from './ai_council/config.js';
79
79
  import { AuthCache, select_solo_member } from './ai_council/solo_dispatch.js';
80
80
  import { InvalidModeError, resolve_global_mode } from './ai_council/modes.js';
81
- import { resolveMemberTransport } from './ai_council/transport_resolver.js';
82
- import { classifyCliFailure, type AbsentReason } from './ai_council/transport_resolver.js';
81
+ import { classifyCliFailure, resolveMemberTransport, type AbsentReason } from './ai_council/transport_resolver.js';
82
+ import {
83
+ disabledSeats as _disabledSeats,
84
+ resolvedTransportFor as _resolvedTransportFor,
85
+ } from './ai_council/status_surface.js';
83
86
  import { evaluateQuorum, type QuorumResult } from './ai_council/quorum.js';
84
87
  import {
85
88
  _emitQuorumEvent,
@@ -90,6 +93,7 @@ import {
90
93
  _quorum_min_present_from,
91
94
  _quorum_setting_from,
92
95
  } from './ai_council/quorum_wiring.js';
96
+ import { measureDeliberation, runCallsFrom } from './ai_council/deliberation_metrics.js';
93
97
  import { formatQualificationLine, type MemberQualification } from './ai_council/qualification.js';
94
98
  import {
95
99
  absenceReasonFor,
@@ -2163,31 +2167,6 @@ function _emit_shadow_slo_banner(): void {
2163
2167
  * leaves nothing to infer. Exit is always 0 — this reports a state, it does not
2164
2168
  * gate — and the verdict line is machine-greppable in both directions.
2165
2169
  */
2166
- /**
2167
- * Resolve the concrete transport a member would use on THIS machine right now.
2168
- *
2169
- * `cmd_status` exists to answer "is the council reachable, and will it bill me".
2170
- * Since the transport-mode setting was removed, the second half is not a value
2171
- * anyone can look up in the config — it is a per-machine resolution. Printing a
2172
- * configured mode would be the same class of stale answer the removed setting
2173
- * produced. `mode` is pinned to `auto` because the loader no longer emits
2174
- * anything else.
2175
- */
2176
- function _resolvedTransportFor(
2177
- name: string,
2178
- member: { readonly binary: string | null; readonly api_key_ref: string | null },
2179
- report?: EnvironmentReport,
2180
- ): ReturnType<typeof resolveMemberTransport> {
2181
- return resolveMemberTransport({
2182
- provider: name,
2183
- report: report ?? detectEnvironment(),
2184
- invocationMode: null,
2185
- memberSettings: null,
2186
- globalMode: 'auto',
2187
- binaryOverride: member.binary,
2188
- });
2189
- }
2190
-
2191
2170
  /** Gather what `fallbackPostureFor` needs; the decision itself is pure. */
2192
2171
  function _posture(
2193
2172
  name: string,
@@ -2263,6 +2242,9 @@ export function cmd_status(args: Args, opts: { env?: Record<string, string | und
2263
2242
  transport: t.available ? t.transport : null,
2264
2243
  billing: t.available ? t.billing : null,
2265
2244
  reason: t.reason,
2245
+ absent_reason: t.absentReason,
2246
+ policy_exclusion: m.policy_exclusion,
2247
+ content_ceiling: m.content_ceiling,
2266
2248
  },
2267
2249
  ];
2268
2250
  }),
@@ -2273,6 +2255,7 @@ export function cmd_status(args: Args, opts: { env?: Record<string, string | und
2273
2255
  enabledMembers.map(([n, m]) => [n, _posture(n, m)]),
2274
2256
  ),
2275
2257
  },
2258
+ disabled_seats: _disabledSeats(cfg),
2276
2259
  ignored_transport_keys: cfg?.ignored_transport_keys ?? [],
2277
2260
  qualification: qualificationJson(qualifications),
2278
2261
  qualified_members: countableSeats(qualifications),
@@ -2310,6 +2293,15 @@ export function cmd_status(args: Args, opts: { env?: Record<string, string | und
2310
2293
  const billing = t.available ? ` · ${t.billing}` : '';
2311
2294
  const detail = t.available ? t.transport : `unavailable — ${t.reason ?? 'no usable transport'}`;
2312
2295
  _stdout(` transport ${name}: ${detail}${billing}\n`);
2296
+ // 2.1: the machine-readable half of the refusal.
2297
+ if (!t.available && t.absentReason !== null && t.absentReason.startsWith('policy_')) {
2298
+ _stdout(` policy ${name}: ${t.absentReason}\n`);
2299
+ }
2300
+ _stdout(` content ceiling ${name}: ${member.content_ceiling}\n`);
2301
+ }
2302
+ // 1.2: a disabled seat was invisible here — `enabled` members only.
2303
+ for (const [name, reason] of Object.entries(_disabledSeats(cfg))) {
2304
+ _stdout(` disabled seat ${name}: ${reason}\n`);
2313
2305
  }
2314
2306
  for (const line of renderPostureLines(
2315
2307
  enabledMembers.map(([n, m]) => [n, _posture(n, m)] as const),
@@ -2739,18 +2731,15 @@ function cmd_run(
2739
2731
  }
2740
2732
  const estimated_total = estimates.reduce((acc, e) => acc + _total_usd(e), 0.0);
2741
2733
  let actual_total = 0.0;
2742
- const all_responses: CouncilResponse[] = [...responses];
2743
- if (peer_review !== null) {
2744
- all_responses.push(...peer_review.responses);
2745
- }
2746
- if (consensus !== null) {
2747
- all_responses.push(...consensus.extraction_responses);
2748
- all_responses.push(...consensus.scoring_responses);
2749
- }
2750
- if (chairman !== null && chairman.response !== null) {
2751
- all_responses.push(chairman.response);
2752
- }
2753
- all_responses.push(...stance_repairs);
2734
+ const run_calls = runCallsFrom({
2735
+ deliberation: responses,
2736
+ peerReview: peer_review?.responses ?? null,
2737
+ consensusExtraction: consensus?.extraction_responses ?? null,
2738
+ consensusScoring: consensus?.scoring_responses ?? null,
2739
+ chairman: chairman?.response ?? null,
2740
+ stanceRepairs: stance_repairs,
2741
+ });
2742
+ const all_responses: CouncilResponse[] = run_calls.responses;
2754
2743
  // Billable-aware: a subscription-CLI seat spent nothing, so pricing it at
2755
2744
  // API rates and calling the figure "actual" is a false statement about
2756
2745
  // money. See pricing.ts § billable-aware aggregation.
@@ -2800,6 +2789,7 @@ function cmd_run(
2800
2789
  // one for a machine consumer), even when every field is `null`: the
2801
2790
  // work-order envelope for whatever executes on this verdict next.
2802
2791
  payload['handoff'] = handoff;
2792
+ payload['deliberation'] = measureDeliberation(run_calls.calls);
2803
2793
  const out_path = _validate_council_output_path(args.output as string, {
2804
2794
  kind: 'responses',
2805
2795
  subcommand: 'run',