@event4u/agent-config 8.10.0 → 8.12.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 (226) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/AGENTS.md +1 -0
  3. package/CHANGELOG.md +67 -149
  4. package/README.md +6 -6
  5. package/dist/agent-src/commands/challenge-me/vision.md +121 -32
  6. package/dist/agent-src/commands/challenge-me/with-docs.md +21 -8
  7. package/dist/agent-src/commands/commit/in-chunks.md +1 -1
  8. package/dist/agent-src/commands/commit.md +2 -1
  9. package/dist/agent-src/commands/cost/report.md +2 -1
  10. package/dist/agent-src/commands/feature/dev.md +4 -4
  11. package/dist/agent-src/commands/humanize.md +101 -0
  12. package/dist/agent-src/commands/jira-ticket.md +2 -2
  13. package/dist/agent-src/commands/memory/load.md +15 -0
  14. package/dist/agent-src/commands/optimize/project.md +12 -0
  15. package/dist/agent-src/commands/roadmap/create.md +12 -11
  16. package/dist/agent-src/commands/tests/create.md +1 -1
  17. package/dist/agent-src/commands/worktree/cleanup.md +22 -17
  18. package/dist/agent-src/commands/worktree/create.md +3 -1
  19. package/dist/agent-src/commands/worktree/status.md +12 -0
  20. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +66 -0
  21. package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +1 -0
  22. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +47 -3
  23. package/dist/agent-src/contexts/execution/roadmap-ci-steps-mechanics.md +117 -0
  24. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +111 -85
  25. package/dist/agent-src/contexts/execution/roadmap-writing-source-derived.md +65 -0
  26. package/dist/agent-src/contexts/execution/subagent-modes-detail.md +84 -0
  27. package/dist/agent-src/rules/architecture.md +6 -51
  28. package/dist/agent-src/rules/autonomous-execution.md +7 -37
  29. package/dist/agent-src/rules/broken-access-control.md +7 -45
  30. package/dist/agent-src/rules/code-comment-discipline.md +64 -0
  31. package/dist/agent-src/rules/context-hygiene.md +14 -0
  32. package/dist/agent-src/rules/decision-revisit-gate.md +9 -77
  33. package/dist/agent-src/rules/delegation-policy.md +10 -8
  34. package/dist/agent-src/rules/design-fidelity.md +4 -0
  35. package/dist/agent-src/rules/git-history-discipline.md +4 -79
  36. package/dist/agent-src/rules/improve-before-implement.md +7 -66
  37. package/dist/agent-src/rules/legal-safety-floor.md +11 -55
  38. package/dist/agent-src/rules/no-roadmap-references.md +13 -77
  39. package/dist/agent-src/rules/persona-governance.md +5 -47
  40. package/dist/agent-src/rules/provider-lifecycle-discipline.md +6 -32
  41. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +21 -104
  42. package/dist/agent-src/rules/roadmap-progress-sync.md +5 -56
  43. package/dist/agent-src/rules/think-before-action.md +10 -0
  44. package/dist/agent-src/rules/untrusted-input-defense.md +3 -75
  45. package/dist/agent-src/rules/verify-before-complete.md +12 -0
  46. package/dist/agent-src/skills/agent-docs-writing/SKILL.md +96 -12
  47. package/dist/agent-src/skills/ai-council/SKILL.md +19 -9
  48. package/dist/agent-src/skills/api-design/SKILL.md +7 -5
  49. package/dist/agent-src/skills/api-testing/SKILL.md +1 -1
  50. package/dist/agent-src/skills/authz-review/SKILL.md +59 -2
  51. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  52. package/dist/agent-src/skills/bug-analyzer/SKILL.md +19 -16
  53. package/dist/agent-src/skills/code-refactoring/SKILL.md +9 -9
  54. package/dist/agent-src/skills/content-funnel-design/SKILL.md +2 -0
  55. package/dist/agent-src/skills/data-flow-mapper/SKILL.md +1 -1
  56. package/dist/agent-src/skills/decision-review/SKILL.md +86 -0
  57. package/dist/agent-src/skills/defense-in-depth/SKILL.md +2 -2
  58. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +7 -7
  59. package/dist/agent-src/skills/design-intelligence/SKILL.md +8 -8
  60. package/dist/agent-src/skills/design-review/SKILL.md +23 -2
  61. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +2 -0
  62. package/dist/agent-src/skills/editorial-calendar/SKILL.md +2 -0
  63. package/dist/agent-src/skills/fe-design/SKILL.md +7 -9
  64. package/dist/agent-src/skills/git-workflow/SKILL.md +86 -0
  65. package/dist/agent-src/skills/humanizer/SKILL.md +147 -0
  66. package/dist/agent-src/skills/humanizer/data/patterns.md +190 -0
  67. package/dist/agent-src/skills/humanizer/evals/triggers.json +17 -0
  68. package/dist/agent-src/skills/laravel/SKILL.md +14 -1
  69. package/dist/agent-src/skills/launch-readiness/SKILL.md +20 -19
  70. package/dist/agent-src/skills/legal-practice-profile/SKILL.md +126 -0
  71. package/dist/agent-src/skills/logging-monitoring/SKILL.md +1 -1
  72. package/dist/agent-src/skills/mcp/SKILL.md +1 -1
  73. package/dist/agent-src/skills/memory-consolidation/SKILL.md +14 -1
  74. package/dist/agent-src/skills/migration-architect/SKILL.md +2 -1
  75. package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +58 -1
  76. package/dist/agent-src/skills/performance/SKILL.md +1 -1
  77. package/dist/agent-src/skills/php-debugging/SKILL.md +17 -0
  78. package/dist/agent-src/skills/readme-writing/SKILL.md +2 -0
  79. package/dist/agent-src/skills/readme-writing-package/SKILL.md +2 -0
  80. package/dist/agent-src/skills/release-comms/SKILL.md +2 -0
  81. package/dist/agent-src/skills/roadmap-writing/SKILL.md +22 -51
  82. package/dist/agent-src/skills/security-audit/SKILL.md +6 -9
  83. package/dist/agent-src/skills/sentry-integration/SKILL.md +2 -2
  84. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +8 -0
  85. package/dist/agent-src/skills/source-discovery/SKILL.md +26 -24
  86. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +55 -46
  87. package/dist/agent-src/skills/subagent-orchestration/evals/evals.json +42 -0
  88. package/dist/agent-src/skills/systematic-debugging/SKILL.md +10 -0
  89. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +10 -0
  90. package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +27 -20
  91. package/dist/agent-src/skills/worktree-lifecycle/evals/evals.json +38 -0
  92. package/dist/agent-src/templates/agent-settings.md +3 -2
  93. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +15 -1
  94. package/dist/agent-src/templates/contexts/knowledge-card.md +12 -0
  95. package/dist/agent-src/templates/roadmaps.md +14 -0
  96. package/dist/cli/commands/recordTriggerEval.js +4 -14
  97. package/dist/cli/commands/recordTriggerEval.js.map +1 -1
  98. package/dist/discovery/deprecation-report.md +1 -1
  99. package/dist/discovery/discovery-manifest.json +157 -88
  100. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  101. package/dist/discovery/discovery-manifest.summary.md +6 -6
  102. package/dist/discovery/orphan-report.md +1 -1
  103. package/dist/discovery/packs.json +13 -10
  104. package/dist/discovery/trust-report.md +3 -3
  105. package/dist/discovery/workspaces.json +14 -9
  106. package/dist/install/install.mjs +12 -7
  107. package/dist/mcp/registry-manifest.json +4 -4
  108. package/dist/router.json +1 -1
  109. package/dist/scripts/_lib/claude_settings_hooks.js +8 -0
  110. package/dist/scripts/_lib/claude_settings_hooks.js.map +1 -1
  111. package/dist/scripts/_lib/trigger_eval_floors.js +24 -0
  112. package/dist/scripts/_lib/trigger_eval_floors.js.map +1 -0
  113. package/dist/scripts/condense.js +12 -2
  114. package/dist/scripts/condense.js.map +1 -1
  115. package/dist/server/schemas/settings.js +5 -2
  116. package/dist/server/schemas/settings.js.map +1 -1
  117. package/docs/CLAIMS.md +54 -5
  118. package/docs/architecture.md +4 -4
  119. package/docs/archive/CHANGELOG-pre-8.12.0.md +304 -0
  120. package/docs/benchmark.md +90 -0
  121. package/docs/catalog.md +8 -5
  122. package/docs/command-flows.md +2 -1
  123. package/docs/contracts/ai-council-config.md +97 -0
  124. package/docs/contracts/command-clusters.md +1 -0
  125. package/docs/contracts/evidence-based-pruning.md +1 -0
  126. package/docs/contracts/hook-architecture-v1.md +25 -0
  127. package/docs/contracts/kernel-membership.md +35 -0
  128. package/docs/contracts/measurement-baseline.md +1 -0
  129. package/docs/contracts/persona-schema.md +49 -0
  130. package/docs/contracts/provider-lifecycle.md +29 -4
  131. package/docs/contracts/release-sizing.md +22 -0
  132. package/docs/contracts/write-engine.md +38 -1
  133. package/docs/customization.md +12 -0
  134. package/docs/decisions/ADR-002-kernel-bucket-overrides.md +11 -0
  135. package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +11 -0
  136. package/docs/decisions/ADR-006-skill-tools-python-pilot.md +1 -1
  137. package/docs/decisions/ADR-028-root-layout.md +1 -1
  138. package/docs/decisions/ADR-038-canonical-settings-path.md +10 -0
  139. package/docs/decisions/ADR-092-defer-command-tier-alias-removal.md +29 -5
  140. package/docs/decisions/ADR-093-ai-council-config-user-global.md +1 -1
  141. package/docs/decisions/ADR-100-global-knowledge-card-sharing.md +7 -0
  142. package/docs/decisions/ADR-103-global-knowledge-default-off-until-measured.md +2 -2
  143. package/docs/decisions/ADR-105-automatic-subagent-orchestration.md +1 -1
  144. package/docs/decisions/ADR-114-commit-policy-iron-law-override.md +11 -0
  145. package/docs/decisions/ADR-116-memory-tripwire-activation-path.md +11 -1
  146. package/docs/decisions/ADR-117-subagents-auto-default-on.md +2 -1
  147. package/docs/decisions/ADR-118-loop-engineering-boundaries.md +162 -0
  148. package/docs/decisions/ADR-119-global-knowledge-default-on.md +104 -0
  149. package/docs/decisions/ADR-120-council-chairman-mode.md +70 -0
  150. package/docs/decisions/ADR-121-knowledge-sensitivity-classes.md +90 -0
  151. package/docs/decisions/ADR-200-python-to-typescript-migration.md +11 -1
  152. package/docs/decisions/ADR-rule-kernel-and-router.md +11 -0
  153. package/docs/decisions/INDEX.md +13 -9
  154. package/docs/design/council-vs-solo-baseline.md +92 -0
  155. package/docs/design/cross-model-parity-eval.md +82 -0
  156. package/docs/design/length-neutral-judge-rerun.md +92 -0
  157. package/docs/design/utilization-window-criteria.md +51 -0
  158. package/docs/featured-skills.md +2 -2
  159. package/docs/getting-started-by-role.md +1 -1
  160. package/docs/getting-started.md +2 -2
  161. package/docs/governance-advantage.md +1 -1
  162. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +68 -0
  163. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +80 -5
  164. package/docs/guidelines/agent-infra/rule-body-migration-inventory.md +241 -0
  165. package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +80 -3
  166. package/docs/guidelines/code-clarity.md +191 -1
  167. package/docs/guidelines/design-antipatterns.md +20 -0
  168. package/docs/guidelines/php/php-coding-patterns.md +12 -2
  169. package/docs/maintainers/branch-protection.md +87 -0
  170. package/docs/maintainers/system-map.md +85 -0
  171. package/docs/proof.md +32 -15
  172. package/docs/wedge/production-validator/production-validator.md +27 -0
  173. package/package.json +1 -1
  174. package/src/config/agent-settings.template.yml +38 -9
  175. package/src/scripts/_cli/cmd_doctor.ts +129 -1
  176. package/src/scripts/_lib/auto_dispatch.corpus.test.ts +87 -0
  177. package/src/scripts/_lib/claude_settings_hooks.ts +8 -0
  178. package/src/scripts/_lib/knowledge_global.ts +50 -2
  179. package/src/scripts/_lib/knowledge_global_promote.ts +150 -0
  180. package/src/scripts/_lib/knowledge_global_redaction.ts +42 -4
  181. package/src/scripts/_lib/lexical_index.ts +15 -2
  182. package/src/scripts/_lib/orchestration_record.ts +14 -0
  183. package/src/scripts/_lib/trigger_eval_floors.ts +31 -0
  184. package/src/scripts/ai_council/chairman.ts +90 -0
  185. package/src/scripts/ai_council/clients.ts +18 -3
  186. package/src/scripts/ai_council/config.ts +157 -0
  187. package/src/scripts/ai_council/debate_gates.ts +89 -0
  188. package/src/scripts/ai_council/orchestrator.ts +252 -2
  189. package/src/scripts/ai_council/prompts.ts +121 -11
  190. package/src/scripts/ai_council/replay.ts +17 -0
  191. package/src/scripts/ai_council/stance_tally.ts +184 -0
  192. package/src/scripts/ai_tells_rules.ts +433 -0
  193. package/src/scripts/bench_humanizer_eval.ts +240 -0
  194. package/src/scripts/bench_persona_placebo.ts +308 -0
  195. package/src/scripts/bench_quality_rerun.ts +357 -0
  196. package/src/scripts/build_discovery_manifest.ts +6 -0
  197. package/src/scripts/build_proof.ts +30 -9
  198. package/src/scripts/check_artefact_count_messaging.ts +56 -0
  199. package/src/scripts/check_claims.ts +40 -0
  200. package/src/scripts/check_knowledge_cards.ts +33 -4
  201. package/src/scripts/check_portability.ts +1 -0
  202. package/src/scripts/check_rule_invariants.ts +10 -3
  203. package/src/scripts/complexity_report.ts +776 -0
  204. package/src/scripts/condense.ts +16 -2
  205. package/src/scripts/consumer_matrix.ts +292 -14
  206. package/src/scripts/council_cli.ts +203 -1
  207. package/src/scripts/detect_ai_tells.ts +312 -0
  208. package/src/scripts/explain_run.ts +593 -0
  209. package/src/scripts/install.ts +12 -0
  210. package/src/scripts/knowledge_global_cli.ts +235 -46
  211. package/src/scripts/lint_framework_leakage.ts +88 -7
  212. package/src/scripts/lint_framework_leakage_allowlist.json +59 -572
  213. package/src/scripts/lint_knowledge_scale.ts +30 -0
  214. package/src/scripts/lint_originality_shingles.ts +210 -0
  215. package/src/scripts/orchestration_record.ts +1 -0
  216. package/src/scripts/rule_backlinks.ts +0 -0
  217. package/src/scripts/schemas/agent-settings.schema.json +11 -0
  218. package/src/scripts/self_review_gate.ts +41 -15
  219. package/src/scripts/skill_eval_coverage.ts +71 -3
  220. package/src/scripts/skill_linter.ts +1 -0
  221. package/src/scripts/trigger_eval_rotation.ts +344 -0
  222. package/src/scripts/update_counts.ts +5 -17
  223. package/src/scripts/worktree_cleanup_check.ts +263 -0
  224. package/src/server/schemas/settings.ts +8 -3
  225. package/src/scripts/analysis_freshness.ts +0 -362
  226. package/src/scripts/export_replay_corpus.ts +0 -208
@@ -27,6 +27,7 @@ import { REPO, LEDGER_REL, load_ledger, pointer_unresolved } from './check_claim
27
27
  import { collectSkillGaps } from './check_skill_gaps.js';
28
28
  import { loadRows as loadComparisonRows } from './check_comparison.js';
29
29
  import { computeStatus as domainSoundnessStatus } from './domain_soundness_status.js';
30
+ import { computeCoverage } from './skill_eval_coverage.js';
30
31
 
31
32
  const _FILE = fileURLToPath(import.meta.url);
32
33
  const OUT_REL = 'docs/proof.md';
@@ -104,20 +105,40 @@ function render(): string {
104
105
  L.push(`Benchmark results — **including the runs where the package changed nothing** —`);
105
106
  L.push(`live in [\`${BENCH_REL}\`](benchmark.md). We do not delete a measured null to`);
106
107
  L.push('make a number look better; the null is the evidence of honesty.');
108
+ L.push('');
109
+ L.push('The freshest example: the **persona-placebo benchmark** <!-- claim:persona-identity-placebo-null -->');
110
+ L.push('(2026-07-12, 3 arms × 2 providers, blind rubric judge, pre-registered');
111
+ L.push('hypotheses) measured whether famous-figure persona framing improves decision');
112
+ L.push('answers over the bare method text it wraps. It does not (Δ=0.17, p=0.607) —');
113
+ L.push('while provider diversity moved judged quality ~15× more than persona identity.');
114
+ L.push('The measured null closed a planned feature (persona panel-mode) instead of');
115
+ L.push('shipping theater; the full per-cell data is committed at');
116
+ L.push('`internal/bench/reports/persona-placebo.json`.');
107
117
  } else {
108
118
  L.push('Benchmark results are published under `docs/` including measured nulls.');
109
119
  }
110
120
  L.push('');
121
+ const cov = computeCoverage();
122
+ const prio = cov.tiers.priority;
123
+ const other = cov.tiers.other;
124
+ const prioLine =
125
+ prio.covered === prio.total
126
+ ? `\`rich\` + routers) are **fully covered (${prio.covered} of ${prio.total})**, the long tail`
127
+ : `\`rich\` + routers, **${prio.covered} of ${prio.total}**) are partially covered; the long tail`;
111
128
  L.push('**Behavioural-eval coverage — the honest baseline.** Skill *quality* is only');
112
- L.push('as good as its measurement. Today **2 of 264** skills carry a behavioural');
113
- L.push('`evals.json`, and the highest-traffic / highest-cost tiers (default-surface +');
114
- L.push('`rich` + routers, **0 of 35**) are not yet covered. We publish that gap rather');
115
- L.push('than imply "264 evaluated skills": coverage is measured per tier');
116
- L.push('(`./scripts-run src/scripts/skill_eval_coverage`) and **CI-ratcheted so it can');
117
- L.push('only rise** — a merged change can never lower it. Authoring the priority-tier');
118
- L.push('evals is gated on per-case human ratification (a generated assertion that');
119
- L.push('checks the wrong property is worse than none), so the number grows');
120
- L.push('deliberately, not overnight.');
129
+ L.push(`as good as its measurement. Today **${cov.overall.covered} of ${cov.overall.total}** skills carry a behavioural`);
130
+ L.push('`evals.json`; the highest-traffic / highest-cost tiers (default-surface +');
131
+ L.push(prioLine);
132
+ L.push(`(${other.covered} of ${other.total}) is not. We publish that gap rather than imply`);
133
+ L.push(`"${cov.overall.total} evaluated skills": coverage is measured per tier`);
134
+ L.push('(`./scripts-run src/scripts/skill_eval_coverage`), **CI-ratcheted so it can');
135
+ L.push('only rise**, and the priority tiers carry a hard **tier floor**: every');
136
+ L.push('rich / default-surface / router skill MUST have a behavioural eval or an');
137
+ L.push('explicit exemption-with-reason in `internal/evals/tier-floor-exemptions.json`');
138
+ L.push('— no silent exemptions (the bright line deliberately replaces a');
139
+ L.push('weighted-coverage score). Authoring long-tail evals is gated on per-case');
140
+ L.push('human ratification (a generated assertion that checks the wrong property is');
141
+ L.push('worse than none), so the number grows deliberately, not overnight.');
121
142
  L.push('');
122
143
  const ds = domainSoundnessStatus();
123
144
  L.push('**Non-coding domain soundness — scoped, not proven.** The `finance` /');
@@ -113,6 +113,49 @@ export function scan_text(
113
113
  return { findings, seen };
114
114
  }
115
115
 
116
+ /** Structured-surface totals — generated files whose counts are YAML fields,
117
+ * not prose, so the KIND_PATTERNS prose scan cannot see them. CAPABILITIES.yaml
118
+ * proved this gap: it drifted to 268/177 while every prose surface said
119
+ * 271/178, because only its own `--check` guarded it and a stale commit can
120
+ * land through parallel merges. This scan makes the messaging gate a second,
121
+ * independent net over the same canonical counts. */
122
+ export const STRUCTURED_SURFACES: ReadonlyArray<{
123
+ file: string;
124
+ fields: ReadonlyArray<[kind: string, pattern: RegExp]>;
125
+ }> = [
126
+ {
127
+ file: 'CAPABILITIES.yaml',
128
+ fields: [
129
+ ['skills', /^\s*skills_total:\s*(\d+)\s*$/m],
130
+ ['commands', /^\s*commands_total:\s*(\d+)\s*$/m],
131
+ ],
132
+ },
133
+ ];
134
+
135
+ export function scan_structured(
136
+ rel: string,
137
+ text: string,
138
+ fields: ReadonlyArray<[string, RegExp]>,
139
+ expected: Record<string, number>,
140
+ ): { findings: Finding[]; seen: Record<string, Set<number>> } {
141
+ const findings: Finding[] = [];
142
+ const seen: Record<string, Set<number>> = {};
143
+ for (const [kind, pattern] of fields) {
144
+ const m = text.match(pattern);
145
+ if (m === null) {
146
+ continue; // absent field is the generator's own --check's problem
147
+ }
148
+ const found = Number.parseInt(m[1]!, 10);
149
+ (seen[kind] ??= new Set()).add(found);
150
+ const exp = expected[kind]!;
151
+ if (found !== exp) {
152
+ const line = text.slice(0, m.index ?? 0).split('\n').length;
153
+ findings.push({ file: rel, line, kind, found, expected: exp, approx: false });
154
+ }
155
+ }
156
+ return { findings, seen };
157
+ }
158
+
116
159
  export function main(argv: readonly string[] = process.argv.slice(2)): number {
117
160
  const QUIET = argv.includes('--quiet');
118
161
  const expected: Record<string, number> = {};
@@ -140,6 +183,19 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
140
183
  }
141
184
  }
142
185
 
186
+ for (const { file, fields } of STRUCTURED_SURFACES) {
187
+ const p = path.join(ROOT, file);
188
+ if (!fs.existsSync(p)) {
189
+ process.stderr.write(` ⚠️ surface missing (skipped): ${file}\n`);
190
+ continue;
191
+ }
192
+ const { findings, seen } = scan_structured(file, fs.readFileSync(p, 'utf-8'), fields, expected);
193
+ allFindings.push(...findings);
194
+ for (const [kind, nums] of Object.entries(seen)) {
195
+ for (const n of nums) (global_seen[kind] ??= new Set()).add(n);
196
+ }
197
+ }
198
+
143
199
  // Internal-inconsistency check — the regression case this gate exists
144
200
  // for: multiple DIFFERENT numbers for one kind across the surfaces.
145
201
  const inconsistent: string[] = [];
@@ -42,6 +42,13 @@ const SURFACE_ROOTS = ['README.md', 'docs'];
42
42
  const CLAIM_MARKER = /<!--\s*claim:([A-Za-z0-9._-]+)\s*-->/g;
43
43
  const URL_DATED = /^https?:\/\/\S+\(\d{4}-\d{2}-\d{2}\)\s*$/;
44
44
 
45
+ /** Witness sweep (P1.2) — marketing-class surfaces where a bare number must
46
+ * not appear as a capability claim. docs/proof.md and docs/comparison.yaml
47
+ * are structurally witnessed (pointer columns + their own linters). */
48
+ const WITNESS_SURFACES = ['README.md', 'CAPABILITIES.yaml'];
49
+ /** A percentage or multiplier reading as a measured capability figure. */
50
+ const QUANTIFIED_CLAIM = /\b\d+(?:\.\d+)?\s*(?:%|[x×](?![A-Za-z0-9]))/;
51
+
45
52
  class ExitCode extends Error {
46
53
  code: number;
47
54
  constructor(code: number) {
@@ -224,6 +231,39 @@ function main(argv: string[] = process.argv.slice(2)): number {
224
231
  if (un) findings.push({ id: entry.id, file: LEDGER_REL, reason: `backed entry has dangling evidence — ${un}` });
225
232
  }
226
233
 
234
+ // 3. Witness sweep (road-to-opt-subagent-harvest P1.2): a QUANTIFIED
235
+ // capability claim on a marketing-class surface must be witnessed — a
236
+ // `<!-- claim:ID -->` marker on the same line, or an explicit
237
+ // `unverified` annotation. Unmarkered numbers are exactly how an
238
+ // "84.8%"-style figure spreads across surfaces with no methodology
239
+ // (the anti-lesson this check encodes). Fenced code blocks are skipped.
240
+ for (const rel of WITNESS_SURFACES) {
241
+ const abs = path.join(REPO, rel);
242
+ let text: string;
243
+ try {
244
+ text = fs.readFileSync(abs, 'utf-8');
245
+ } catch {
246
+ continue;
247
+ }
248
+ let inFence = false;
249
+ const lines = text.split('\n');
250
+ for (let i = 0; i < lines.length; i++) {
251
+ const line = lines[i] as string;
252
+ if (/^\s*(```|~~~)/.test(line)) {
253
+ inFence = !inFence;
254
+ continue;
255
+ }
256
+ if (inFence) continue;
257
+ if (!QUANTIFIED_CLAIM.test(line)) continue;
258
+ if (/<!--\s*claim:/.test(line) || /unverified/i.test(line)) continue;
259
+ findings.push({
260
+ id: '(unmarkered)',
261
+ file: `${rel}:${i + 1}`,
262
+ reason: `quantified claim without a claim marker or 'unverified' annotation — ${line.trim().slice(0, 70)}`,
263
+ });
264
+ }
265
+ }
266
+
227
267
  if (findings.length > 0) {
228
268
  process.stderr.write(`❌ check_claims: ${findings.length} unbacked/dangling claim(s):\n`);
229
269
  for (const f of findings) {
@@ -105,13 +105,17 @@ function _frontmatter_get(text: string, ...keys: string[]): string {
105
105
  // ---------------------------------------------------------------------------
106
106
 
107
107
  /**
108
- * Global-store-only checks (ADR-100): tier validity, provenance footer,
109
- * and a redaction-clean assertion (the secret/PII patterns must have been
110
- * halted/cleaned before the card was written — never present in a global card).
108
+ * Global-store-only checks (ADR-100 + Phase 1 sensitivity axis,
109
+ * road-to-feedback-8.11 / successor note to ADR-119): tier validity,
110
+ * sensitivity validity, provenance footer (incl. the promotion audit-trail
111
+ * fields), and a redaction-clean assertion (the secret/PII patterns must
112
+ * have been halted/cleaned before the card was written — never present in a
113
+ * global card).
111
114
  */
112
115
  function _check_global_card(rel: string, text: string, fm: Record<string, string>): string[] {
113
116
  const errors: string[] = [];
114
117
  const valid_tiers = _kg !== null ? _kg.TIERS : ['public', 'vendor', 'proprietary'];
118
+ const valid_sensitivities = _kg !== null ? _kg.SENSITIVITIES : ['prohibited', 'project', 'shareable'];
115
119
 
116
120
  // G1 — tier present and valid
117
121
  const tier = (fm['tier'] ?? '').trim();
@@ -121,7 +125,27 @@ function _check_global_card(rel: string, text: string, fm: Record<string, string
121
125
  errors.push(`${rel}:0 — G1: tier '${tier}' not in ${_pyReprList(_sorted(valid_tiers))}`);
122
126
  }
123
127
 
124
- // G2 — provenance footer present with all fields
128
+ // G4 — sensitivity present and valid
129
+ const sensitivity = (fm['sensitivity'] ?? '').trim();
130
+ if (!sensitivity) {
131
+ errors.push(`${rel}:0 — G4: global card missing 'sensitivity' in frontmatter`);
132
+ } else if (!valid_sensitivities.includes(sensitivity)) {
133
+ errors.push(
134
+ `${rel}:0 — G4: sensitivity '${sensitivity}' not in ${_pyReprList(_sorted(valid_sensitivities))}`,
135
+ );
136
+ }
137
+
138
+ // G6 — a `prohibited` card must never be in the global store at all: it
139
+ // contains redaction-class content and should never have left the
140
+ // project. Hard error regardless of anything else on the card.
141
+ if (sensitivity === 'prohibited') {
142
+ errors.push(
143
+ `${rel}:0 — G6: sensitivity 'prohibited' must never be in the global store ` +
144
+ '(redaction-class content — this card should never have been promoted)',
145
+ );
146
+ }
147
+
148
+ // G2 + G5 — provenance footer present with all promotion audit-trail fields
125
149
  if (_kg !== null) {
126
150
  const prov = _kg.parse_provenance_footer(text);
127
151
  if (!_pyTruthyObj(prov)) {
@@ -132,6 +156,11 @@ function _check_global_card(rel: string, text: string, fm: Record<string, string
132
156
  errors.push(`${rel}:0 — G2: provenance footer missing '${field}'`);
133
157
  }
134
158
  }
159
+ for (const field of ['source_repo', 'owner', 'review_after', 'promotion_reason']) {
160
+ if (!prov[field]) {
161
+ errors.push(`${rel}:0 — G5: provenance footer missing '${field}'`);
162
+ }
163
+ }
135
164
  }
136
165
  }
137
166
 
@@ -468,6 +468,7 @@ const _TASK_DETECTOR_SKIP = [
468
468
  // CI-shaped literals; its mechanics doc and the execution loop +
469
469
  // authoring skill enumerate the same literals to detect them.
470
470
  'rules/roadmap-ci-steps-policy.md',
471
+ 'contexts/execution/roadmap-ci-steps-mechanics.md',
471
472
  'contexts/execution/roadmap-process-loop.md',
472
473
  'skills/roadmap-writing/SKILL.md',
473
474
  ];
@@ -64,7 +64,12 @@ function loadEntries(root: string): InvariantEntry[] {
64
64
  if (!Array.isArray(parsed)) {
65
65
  throw new Error(`${INVARIANTS_JSON}: expected a top-level array`);
66
66
  }
67
- for (const entry of parsed as InvariantEntry[]) {
67
+ // A leading `{"_meta": ...}` element carries the change-process pointer
68
+ // (JSON has no comments); it is not an invariant entry.
69
+ const entries = (parsed as Array<InvariantEntry | { _meta: unknown }>).filter(
70
+ (e): e is InvariantEntry => !('_meta' in e),
71
+ );
72
+ for (const entry of entries) {
68
73
  if (
69
74
  typeof entry.rule !== 'string' ||
70
75
  typeof entry.file !== 'string' ||
@@ -77,7 +82,7 @@ function loadEntries(root: string): InvariantEntry[] {
77
82
  );
78
83
  }
79
84
  }
80
- return parsed as InvariantEntry[];
85
+ return entries;
81
86
  }
82
87
 
83
88
  /** Check one entry against pre-normalised file contents. */
@@ -144,7 +149,9 @@ function formatText(misses: Miss[], invariantCount: number): string {
144
149
  lines.push(
145
150
  '\nA kernel rule lost a load-bearing clause — likely a merge or condensation ' +
146
151
  'dropped it silently (see the #840/#844 incident in this file header). ' +
147
- 'Restore the clause or deliberately update tests/golden/invariants.json.',
152
+ 'Restore the clause, or reword it via the documented change process: ' +
153
+ 'docs/contracts/kernel-membership.md § 10 — Changing a protected invariant ' +
154
+ '(never "update the gate green").',
148
155
  );
149
156
  return lines.join('\n');
150
157
  }