@event4u/agent-config 14.13.0 → 14.14.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 (101) 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 +116 -387
  5. package/dist/agent-src/commands/analyze/inbox.md +36 -0
  6. package/dist/agent-src/rules/code-comment-discipline.md +6 -0
  7. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
  8. package/dist/agent-src/scripts/guarded_baseline.ts +22 -7
  9. package/dist/agent-src/scripts/stubs_due.ts +118 -2
  10. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -8
  11. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  12. package/dist/cli-delegate/cmd_conformance.js +38 -1
  13. package/dist/discovery/deprecation-report.md +1 -1
  14. package/dist/discovery/discovery-manifest.json +4 -4
  15. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  16. package/dist/discovery/discovery-manifest.summary.md +1 -1
  17. package/dist/discovery/dormancy-report.md +1 -1
  18. package/dist/discovery/orphan-report.md +1 -1
  19. package/dist/discovery/packs.json +2 -2
  20. package/dist/discovery/trust-report.md +1 -1
  21. package/dist/discovery/workspaces.json +2 -2
  22. package/dist/hooks/dispatch.js +1438 -711
  23. package/dist/mcp/registry-manifest.json +2 -2
  24. package/dist/mcp/server.json +2 -2
  25. package/dist/mcp/server.mjs +112 -17
  26. package/docs/guidelines/agent-infra/guarded-baseline.md +1 -1
  27. package/docs/guidelines/code-clarity.md +18 -0
  28. package/package.json +1 -1
  29. package/src/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
  30. package/src/agent-src/scripts/guarded_baseline.ts +22 -7
  31. package/src/agent-src/scripts/stubs_due.ts +118 -2
  32. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -8
  33. package/src/config/estate-count-budget.json +20 -1
  34. package/src/config/gate-coverage.yml +150 -0
  35. package/src/config/gate-violation-baselines.json +8 -3
  36. package/src/config/preamble-payload-budget.json +19 -11
  37. package/src/config/rule-stub-ceilings.json +14 -7
  38. package/src/scripts/_dispatch.bash +0 -4
  39. package/src/scripts/_lib/activation_ladder.ts +47 -3
  40. package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
  41. package/src/scripts/_lib/adr_frontmatter.ts +26 -0
  42. package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
  43. package/src/scripts/_lib/carrier_status.ts +118 -0
  44. package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
  45. package/src/scripts/_lib/corpus_manifest.ts +726 -0
  46. package/src/scripts/_lib/delivery_arm_experiment.ts +18 -2
  47. package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
  48. package/src/scripts/_lib/evaluation_cascade.ts +452 -0
  49. package/src/scripts/_lib/evolution_roi.ts +562 -0
  50. package/src/scripts/_lib/harness_evolution_guards.ts +10 -0
  51. package/src/scripts/_lib/lexical_shortlist.ts +215 -0
  52. package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
  53. package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
  54. package/src/scripts/_lib/pathology_archive.ts +393 -0
  55. package/src/scripts/_lib/promotion_capability.ts +315 -0
  56. package/src/scripts/_lib/promotion_evidence.ts +414 -0
  57. package/src/scripts/_lib/promotion_review.ts +294 -0
  58. package/src/scripts/_lib/prompt_shape.ts +92 -0
  59. package/src/scripts/_lib/release_highlights.ts +70 -1
  60. package/src/scripts/_lib/release_material.ts +125 -2
  61. package/src/scripts/_lib/routing_corpus.ts +307 -0
  62. package/src/scripts/_lib/routing_index_input.ts +104 -0
  63. package/src/scripts/_lib/rule_injection.ts +22 -1
  64. package/src/scripts/_lib/semantic_noop.ts +167 -0
  65. package/src/scripts/activation_receipt.ts +258 -0
  66. package/src/scripts/ai_council/cross_exam.ts +128 -0
  67. package/src/scripts/ai_council/explain_route.ts +157 -0
  68. package/src/scripts/ai_council/information_gain.ts +293 -0
  69. package/src/scripts/ai_council/leakage_corpus.ts +385 -0
  70. package/src/scripts/ai_council/leakage_patterns.ts +453 -0
  71. package/src/scripts/ai_council/minority_retention.ts +171 -0
  72. package/src/scripts/ai_council/recouncil_savings.ts +299 -0
  73. package/src/scripts/ai_council/replay_route.ts +223 -0
  74. package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
  75. package/src/scripts/ai_council/routing_training_row.ts +197 -0
  76. package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
  77. package/src/scripts/check_adr_frontmatter.ts +4 -9
  78. package/src/scripts/check_estate_count.ts +205 -24
  79. package/src/scripts/check_release_highlights.ts +96 -13
  80. package/src/scripts/check_roadmap_trackable.ts +17 -2
  81. package/src/scripts/corpus_manifest.ts +235 -0
  82. package/src/scripts/evolution_lab.ts +181 -8
  83. package/src/scripts/hook_manifest.json +1 -1
  84. package/src/scripts/hook_manifest.yaml +28 -6
  85. package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
  86. package/src/scripts/hooks/concern_registry.ts +2 -0
  87. package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
  88. package/src/scripts/language_mirror_hook.ts +14 -2
  89. package/src/scripts/lint_carrier_integrity.ts +820 -0
  90. package/src/scripts/lint_code_comments.ts +643 -0
  91. package/src/scripts/lint_plan_risk_register.ts +39 -19
  92. package/src/scripts/lint_promotion_paths.ts +779 -0
  93. package/src/scripts/llm_propose.ts +256 -0
  94. package/src/scripts/measure_delivery_sets.ts +361 -0
  95. package/src/scripts/measure_routing_signal.ts +307 -0
  96. package/src/scripts/model_rule_injection.ts +19 -3
  97. package/src/scripts/probe_council_retention.ts +495 -0
  98. package/src/scripts/release.ts +21 -37
  99. package/src/scripts/release_drill.ts +143 -0
  100. package/src/scripts/release_env.ts +35 -0
  101. package/src/scripts/release_publication.ts +84 -0
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * `corpus_manifest` — pin the metered-proposer experiment's subject, and check
4
+ * that a fresh checkout reproduces it.
5
+ *
6
+ * Two verbs and no third. `capture` writes the pin from the tree as it stands;
7
+ * `verify` re-captures and reports every difference against a pin on disk.
8
+ * There is deliberately no `update` verb: a pin that can be refreshed in place
9
+ * is a pin that silently follows the tree, which is the property it exists not
10
+ * to have.
11
+ *
12
+ * `verify` exits 3 when the SUBJECT differs and 0 when only the explanatory
13
+ * fields do. That split is the whole point of the exit code — a different
14
+ * runtime version is a fact worth printing and is not a reason to refuse a
15
+ * comparison, while a different subject means the two runs measured different
16
+ * things and no amount of green elsewhere repairs it.
17
+ *
18
+ * Nothing here spends: it reads files and shells out to `git` for the commit.
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as os from 'node:os';
22
+ import * as path from 'node:path';
23
+ import process from 'node:process';
24
+ import { fileURLToPath } from 'node:url';
25
+
26
+ import { partitionActive } from '../install/partitionEligibility.js';
27
+ import {
28
+ type CorpusManifest,
29
+ captureManifest,
30
+ diffManifests,
31
+ parseManifest,
32
+ serialiseManifest,
33
+ subjectsEquivalent,
34
+ } from './_lib/corpus_manifest.js';
35
+
36
+ const _HERE = fileURLToPath(import.meta.url);
37
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
38
+
39
+ export const EXIT_OK = 0;
40
+ export const EXIT_ERROR = 1;
41
+ export const EXIT_USAGE = 2;
42
+ /** The subject differs. Distinct from a plain error so a runner can branch. */
43
+ export const EXIT_SUBJECT_DIFFERS = 3;
44
+
45
+ /**
46
+ * The enumeration rule this manifest pins under, as an ID rather than prose.
47
+ *
48
+ * It is part of the digest, so changing the rule changes the subject even when
49
+ * every file hash is unchanged. That is correct: a corpus of the same five
50
+ * files selected by a different rule is a different experiment, and a digest
51
+ * that could not see the difference would let the selection semantics be
52
+ * amended without the pin noticing.
53
+ */
54
+ export const ENUMERATION_RULE_ID = 'claude-rules-md-bytesorted-first-N/v1';
55
+
56
+ const USAGE = `usage: corpus_manifest capture --out FILE [--limit N]
57
+ corpus_manifest verify --manifest FILE
58
+
59
+ capture write the subject pin from the tree as it stands
60
+ verify re-capture and report every difference against FILE
61
+
62
+ --limit N corpus size, on CAPTURE only; defaults to max_candidates from the
63
+ pre-registered budget, which is the ceiling the run guard aborts
64
+ on. verify re-captures at the size its own manifest pinned, so it
65
+ REFUSES --limit rather than accepting a flag it cannot honour
66
+
67
+ Exit: 0 ok · 1 error · 2 usage · 3 the SUBJECT differs
68
+ `;
69
+
70
+ /**
71
+ * The corpus size, read from the pre-registered budget rather than defaulted.
72
+ *
73
+ * Hardcoding five here would put a second copy of a pre-registered number in a
74
+ * file nobody would think to check when the budget changed, and the two would
75
+ * disagree in the direction that matters: a manifest pinning more subjects than
76
+ * the run guard admits describes an experiment that cannot be run.
77
+ */
78
+ export function defaultLimit(repoRoot: string = REPO_ROOT): number {
79
+ const raw = JSON.parse(
80
+ fs.readFileSync(path.join(repoRoot, 'src', 'config', 'harness-evolution-budget.json'), 'utf-8'),
81
+ ) as { budget?: { max_candidates?: unknown } };
82
+ const n = raw.budget?.max_candidates;
83
+ if (typeof n !== 'number' || !Number.isInteger(n) || n <= 0) {
84
+ throw new Error('max_candidates missing or not a positive integer in the pre-registered budget');
85
+ }
86
+ return n;
87
+ }
88
+
89
+ interface Parsed {
90
+ verb?: string;
91
+ out?: string;
92
+ manifest?: string;
93
+ limit?: number;
94
+ }
95
+
96
+ export function parseArgs(argv: readonly string[]): Parsed | string {
97
+ const p: Parsed = {};
98
+ for (let i = 0; i < argv.length; i += 1) {
99
+ const a = argv[i] as string;
100
+ if (!a.startsWith('--') && p.verb === undefined) {
101
+ p.verb = a;
102
+ continue;
103
+ }
104
+ const v = argv[i + 1];
105
+ if (v === undefined || v.startsWith('--')) return `${a} requires a value`;
106
+ i += 1;
107
+ if (a === '--out') p.out = v;
108
+ else if (a === '--manifest') p.manifest = v;
109
+ else if (a === '--limit') {
110
+ const n = Number(v);
111
+ if (!Number.isInteger(n) || n <= 0) return '--limit must be a positive integer';
112
+ p.limit = n;
113
+ } else return `unknown option '${a}'`;
114
+ }
115
+ if (p.verb === 'verify' && p.limit !== undefined) {
116
+ return (
117
+ 'verify does not take --limit: it re-captures at the size its own manifest pinned, ' +
118
+ 'because a re-capture at another corpus size is a comparison against another subject. ' +
119
+ 'Accepting the flag and then using the pinned size reported green on a run that had ' +
120
+ 'not honoured it'
121
+ );
122
+ }
123
+ return p;
124
+ }
125
+
126
+ /**
127
+ * One real capture over the real tree.
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.
132
+ * Everywhere else the field stays `null` rather than recording some other
133
+ * machine's state under this tree's name.
134
+ */
135
+ function capture(limit: number): CorpusManifest {
136
+ return captureManifest({
137
+ repoRoot: REPO_ROOT,
138
+ userHome: process.env['HOME'] ?? os.homedir(),
139
+ limit,
140
+ enumerationRule: ENUMERATION_RULE_ID,
141
+ partitionActive,
142
+ });
143
+ }
144
+
145
+ export function main(argv?: string[]): number {
146
+ const args = argv ?? process.argv.slice(2);
147
+ if (args.length === 0 || args.includes('-h') || args.includes('--help')) {
148
+ process.stdout.write(USAGE);
149
+ return args.length === 0 ? EXIT_USAGE : EXIT_OK;
150
+ }
151
+ const parsed = parseArgs(args);
152
+ if (typeof parsed === 'string') {
153
+ process.stderr.write(`corpus_manifest: error: ${parsed}\n${USAGE}`);
154
+ return EXIT_USAGE;
155
+ }
156
+
157
+ if (parsed.verb === 'capture') {
158
+ if (parsed.out === undefined) {
159
+ process.stderr.write(`corpus_manifest: error: capture requires --out FILE\n${USAGE}`);
160
+ return EXIT_USAGE;
161
+ }
162
+ let m: CorpusManifest;
163
+ try {
164
+ m = capture(parsed.limit ?? defaultLimit());
165
+ } catch (e) {
166
+ process.stderr.write(`corpus_manifest: capture refused — ${(e as Error).message}\n`);
167
+ return EXIT_ERROR;
168
+ }
169
+ fs.mkdirSync(path.dirname(path.resolve(parsed.out)), { recursive: true });
170
+ fs.writeFileSync(parsed.out, serialiseManifest(m), 'utf-8');
171
+ process.stdout.write(
172
+ `corpus_manifest: wrote ${parsed.out} · subject_digest=${m.subject_digest.slice(0, 16)} · ` +
173
+ `${String(m.included.length)} subject(s) · ${String(m.produced.length)} produced · ` +
174
+ `${String(m.user_scope.filter((t) => t.byte_identical).length)} byte-identical ` +
175
+ `twin(s), ${String(m.user_scope.filter((t) => t.causes_skip).length)} of them ` +
176
+ `causing a skip under ${String(m.generator_config['projection.scope_dedup'])}\n`,
177
+ );
178
+ if (m.tree_dirty) {
179
+ process.stdout.write(
180
+ 'corpus_manifest: WARNING the working tree is dirty, so the recorded commit does not ' +
181
+ 'describe the bytes that were hashed\n',
182
+ );
183
+ }
184
+ return EXIT_OK;
185
+ }
186
+
187
+ if (parsed.verb === 'verify') {
188
+ if (parsed.manifest === undefined) {
189
+ process.stderr.write(`corpus_manifest: error: verify requires --manifest FILE\n${USAGE}`);
190
+ return EXIT_USAGE;
191
+ }
192
+ let expected: CorpusManifest;
193
+ let actual: CorpusManifest;
194
+ try {
195
+ expected = parseManifest(JSON.parse(fs.readFileSync(parsed.manifest, 'utf-8')));
196
+ actual = capture(expected.included.length);
197
+ } catch (e) {
198
+ process.stderr.write(`corpus_manifest: verify refused — ${(e as Error).message}\n`);
199
+ return EXIT_ERROR;
200
+ }
201
+ const diffs = diffManifests(expected, actual);
202
+ for (const d of diffs) {
203
+ process.stdout.write(`corpus_manifest: DIFF ${d.field}: expected ${d.expected}, got ${d.actual}\n`);
204
+ }
205
+ if (subjectsEquivalent(expected, actual)) {
206
+ process.stdout.write(
207
+ `corpus_manifest: SUBJECT EQUIVALENT · ${String(actual.included.length)} subject(s) · ` +
208
+ `digest=${actual.subject_digest.slice(0, 16)}` +
209
+ (diffs.length > 0 ? ` · ${String(diffs.length)} explanatory difference(s) above\n` : '\n'),
210
+ );
211
+ return EXIT_OK;
212
+ }
213
+ process.stdout.write(
214
+ 'corpus_manifest: SUBJECT DIFFERS — a comparison captured against this manifest is not ' +
215
+ 'comparable to one captured here\n',
216
+ );
217
+ return EXIT_SUBJECT_DIFFERS;
218
+ }
219
+
220
+ process.stderr.write(`corpus_manifest: error: unknown verb ${JSON.stringify(parsed.verb)}\n${USAGE}`);
221
+ return EXIT_USAGE;
222
+ }
223
+
224
+ function _isCliEntry(): boolean {
225
+ try {
226
+ if (process.argv[1] === undefined) return false;
227
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
228
+ } catch {
229
+ return false;
230
+ }
231
+ }
232
+
233
+ if (_isCliEntry()) {
234
+ process.exit(main());
235
+ }
@@ -62,6 +62,12 @@ import {
62
62
  clone_candidate,
63
63
  } from './bench_ab_clone.js';
64
64
  import { main as integrity_main } from './bench_ab_integrity.js';
65
+ import {
66
+ runCascade,
67
+ CHEAPEST_STAGE,
68
+ type CascadeResult,
69
+ } from './_lib/evaluation_cascade.js';
70
+ import type { MetricVector } from './_lib/evaluation_vector.js';
65
71
  import {
66
72
  type CandidateRecord,
67
73
  CandidateSchemaError,
@@ -76,6 +82,13 @@ import {
76
82
  parseCandidateRecord,
77
83
  readCandidateRecord,
78
84
  } from './_lib/candidate_record.js';
85
+ import {
86
+ PROMOTION_EVIDENCE_FIELDS,
87
+ PromotionEvidenceError,
88
+ parsePromotionEvidence,
89
+ } from './_lib/promotion_evidence.js';
90
+ import { MERGE_AUTHORITY_ROADMAP, readMergeAuthorityStatus } from './_lib/promotion_capability.js';
91
+ import { assertNotSemanticNoOp, isSemanticNoOp, SemanticNoOpError } from './_lib/semantic_noop.js';
79
92
  import {
80
93
  RECIPES,
81
94
  byteCompare,
@@ -84,6 +97,13 @@ import {
84
97
  proposeCandidates,
85
98
  serialiseCandidateRecord,
86
99
  } from './_lib/candidate_proposer.js';
100
+ import {
101
+ type RunReport,
102
+ buildRunReport,
103
+ parseMetricVectorJson,
104
+ renderRunReport,
105
+ roiFigure,
106
+ } from './_lib/evolution_roi.js';
87
107
  import {
88
108
  BudgetExceededError,
89
109
  type DisclosureRecord,
@@ -379,11 +399,11 @@ const USAGE = `usage: evolution_lab <verb> [options]
379
399
 
380
400
  inspect [--record FILE]... [--records DIR] [--clones]
381
401
  propose --observations FILE --out DIR [--force]
382
- run --record FILE... [--refresh]
402
+ run --record FILE... [--refresh] [--vector FILE]...
383
403
  [--trials-per-candidate N] [--estimated-spend-cents N]
384
404
  compare [--verbose]
385
405
  explain [--record FILE [--to STATE]] [--criteria]
386
- promote --record FILE (always refuses: blocker merge-authority)
406
+ promote --record FILE [--evidence FILE] (always refuses: blocker merge-authority)
387
407
  clean [--yes]
388
408
 
389
409
  No verb starts a resident process, a timer, or a watcher.
@@ -698,7 +718,7 @@ function verbRun(argv: readonly string[]): number {
698
718
  const flags = parseFlags(
699
719
  argv,
700
720
  ['refresh'],
701
- ['record', 'records', 'trials-per-candidate', 'estimated-spend-cents'],
721
+ ['record', 'records', 'trials-per-candidate', 'estimated-spend-cents', 'vector'],
702
722
  );
703
723
  const files: string[] = [...(flags.values.get('record') ?? [])];
704
724
  const dir = one(flags, 'records');
@@ -734,7 +754,22 @@ function verbRun(argv: readonly string[]): number {
734
754
  }
735
755
  throw e;
736
756
  }
757
+ // Evaluation evidence is parsed BEFORE the first clone, for the same reason
758
+ // the budget guard runs before it: a malformed vector discovered after the
759
+ // work is a failed run that already spent, and `parseMetricVectorJson`
760
+ // inherits `buildVector`'s refusal of a vector missing its artifact-count
761
+ // row, so this is also where that refusal lands.
762
+ const vectors: MetricVector[] = [];
763
+ for (const vf of flags.values.get('vector') ?? []) {
764
+ try {
765
+ vectors.push(parseMetricVectorJson(fs.readFileSync(vf, 'utf-8'), vf));
766
+ } catch (e) {
767
+ return fail(`vector ${vf} rejected — ${(e as Error).message}`);
768
+ }
769
+ }
737
770
  const seen = new Set<string>();
771
+ const ids: string[] = [];
772
+ const results: CascadeResult[] = [];
738
773
  for (const f of files.sort(byteCompare)) {
739
774
  let record: CandidateRecord;
740
775
  try {
@@ -754,6 +789,95 @@ function verbRun(argv: readonly string[]): number {
754
789
  }
755
790
  return fail(`candidate ${record.id} failed — ${(e as Error).message}`);
756
791
  }
792
+
793
+ // EVALUATE. Step 4.1's deterministic prefix, wired here because a
794
+ // library nothing calls has no coverage — the defect AC-3 and AC-5
795
+ // were both open on. The record is re-read from disk rather than
796
+ // reusing `record`, so stage 1 is a real schema gate at this call
797
+ // site and not a formality over an already-parsed object.
798
+ let raw: unknown;
799
+ try {
800
+ raw = JSON.parse(fs.readFileSync(f, 'utf-8'));
801
+ } catch (e) {
802
+ return fail(`${f} unreadable at evaluation — ${(e as Error).message}`);
803
+ }
804
+ const result = runCascade({
805
+ raw,
806
+ plan: {
807
+ candidates: files.length,
808
+ trialsPerCandidate: intFlag(flags, 'trials-per-candidate', 1),
809
+ estimatedSpendCents: intFlag(flags, 'estimated-spend-cents', 0),
810
+ },
811
+ budget: loadRunBudget(),
812
+ peers: ids,
813
+ // ONE evidence input, two consumers. `--vector` is the only
814
+ // measurement flag: step 5.6's run report and step 4.1's cascade
815
+ // read the same parsed vectors rather than each taking a file of
816
+ // its own, so a run cannot report an ROI over one set of numbers
817
+ // while the verdict was decided on another.
818
+ vector: vectors.find((v) => v.candidate_id === record.id),
819
+ });
820
+ ids.push(record.id);
821
+ results.push(result);
822
+ }
823
+
824
+ for (const r of results) {
825
+ if (r.outcome === 'abort') {
826
+ process.stdout.write(
827
+ `evolution_lab:cascade · ${r.candidate_id ?? '<unparsed>'} · aborted at ` +
828
+ `${r.failed_stage} · family=${r.family} · model_calls=${r.model_calls} · ${r.detail}\n`,
829
+ );
830
+ } else if (r.outcome === 'incomplete') {
831
+ process.stdout.write(
832
+ `evolution_lab:cascade · ${r.candidate_id} · passed ${r.stages_run.length} stage(s) · ` +
833
+ `model_calls=${r.model_calls} · ${r.not_reached} NOT REACHED · ${r.why}\n`,
834
+ );
835
+ } else {
836
+ process.stdout.write(
837
+ `evolution_lab:cascade · ${r.candidate_id} · passed ${r.stages_run.length} stage(s) · ` +
838
+ `model_calls=${r.model_calls} · verdict=${r.verdict.promote ? 'promote' : 'refuse'} · ` +
839
+ `${r.verdict.reason}\n`,
840
+ );
841
+ }
842
+ }
843
+
844
+ // A cascade abort is a run outcome, not a crash: the run did its job by
845
+ // refusing. The cheapest stage is named so a reader can see that a stage-1
846
+ // abort cost nothing.
847
+ const aborted = results.filter((r) => r.outcome === 'abort');
848
+ if (aborted.length > 0) {
849
+ const atCheapest = aborted.filter(
850
+ (r) => r.outcome === 'abort' && r.failed_stage === CHEAPEST_STAGE,
851
+ ).length;
852
+ process.stdout.write(
853
+ `evolution_lab:cascade · ${aborted.length} of ${results.length} aborted ` +
854
+ `(${atCheapest} at the cheapest stage, ${CHEAPEST_STAGE}, costing no model call)\n`,
855
+ );
856
+ return EXIT_REFUSED;
857
+ }
858
+ // STEP 5.6 — the run report, on the ONE path a run completes on.
859
+ //
860
+ // Placed after the clone loop and before the only success return, so there
861
+ // is no completed run without a report. Every other exit from this verb is
862
+ // an abort (budget) or a failure (unreadable record), and neither is a run
863
+ // whose ROI could be reported: nothing was cloned and nothing was spent.
864
+ let report: RunReport;
865
+ try {
866
+ report = buildRunReport({
867
+ // Deterministic and identifying: the candidate ids, in the byte
868
+ // order the run walked them. Two runs over the same record set
869
+ // produce the same id, and a run over a different set cannot
870
+ // borrow another run's report line.
871
+ run_id: `run:${[...seen].sort(byteCompare).join('+')}`,
872
+ candidates: files.length,
873
+ trials_per_candidate: intFlag(flags, 'trials-per-candidate', 1),
874
+ roi: roiFigure(vectors, intFlag(flags, 'estimated-spend-cents', 0)),
875
+ });
876
+ } catch (e) {
877
+ return fail(`run report rejected — ${(e as Error).message}`);
878
+ }
879
+ for (const line of renderRunReport(report)) {
880
+ process.stdout.write(`${line}\n`);
757
881
  }
758
882
  return EXIT_OK;
759
883
  }
@@ -854,9 +978,15 @@ function verbExplain(argv: readonly string[]): number {
854
978
  * There is no flag, no environment variable and no argument that turns this
855
979
  * into a promotion. `--approver` is deliberately NOT a flag: adding one is what
856
980
  * would let an unattended run name a human who never approved.
981
+ *
982
+ * `--evidence FILE` IS a flag, and it changes nothing about the refusal. It is
983
+ * how steps 7.1, 7.3, 7.4 and 7.5 are exercised against a refused promotion: the
984
+ * package is validated FIRST and its finding names the missing field, so an
985
+ * operator assembling one can see which field is wrong instead of only being
986
+ * told the blocker is open. Both paths still return {@link EXIT_REFUSED}.
857
987
  */
858
988
  function verbPromote(argv: readonly string[]): number {
859
- const flags = parseFlags(argv, [], ['record']);
989
+ const flags = parseFlags(argv, [], ['record', 'evidence']);
860
990
  const file = one(flags, 'record');
861
991
  if (file === undefined) {
862
992
  return usageError('promote requires --record FILE');
@@ -867,20 +997,63 @@ function verbPromote(argv: readonly string[]): number {
867
997
  } catch (e) {
868
998
  return fail(`${file} rejected — ${(e as Error).message}`);
869
999
  }
1000
+
1001
+ // 7.1 / 7.3 / 7.4 / 7.5 — the evidence package, checked BEFORE the governance
1002
+ // refusal so its finding names the missing field rather than being swallowed
1003
+ // by a blocker message the operator cannot act on.
1004
+ const evidenceFile = one(flags, 'evidence');
1005
+ if (evidenceFile === undefined) {
1006
+ process.stderr.write(
1007
+ `evolution_lab: promote REFUSED for ${record.id}\n` +
1008
+ ' evidence package: absent. A promotion carries ONE package with all ' +
1009
+ `${String(PROMOTION_EVIDENCE_FIELDS.length)} fields ` +
1010
+ `(${PROMOTION_EVIDENCE_FIELDS.join(', ')}); pass --evidence FILE.\n`,
1011
+ );
1012
+ } else {
1013
+ try {
1014
+ const evidence = parsePromotionEvidence(JSON.parse(fs.readFileSync(evidenceFile, 'utf-8')));
1015
+ assertNotSemanticNoOp(
1016
+ evidence.candidateId,
1017
+ isSemanticNoOp(
1018
+ evidence.materialImprovement.baselineText,
1019
+ evidence.materialImprovement.candidateText,
1020
+ evidence.materialImprovement.deltaPercent,
1021
+ ),
1022
+ );
1023
+ } catch (e) {
1024
+ if (e instanceof PromotionEvidenceError || e instanceof SemanticNoOpError) {
1025
+ process.stderr.write(
1026
+ `evolution_lab: promote REFUSED for ${record.id}\n evidence package: ${e.message}\n`,
1027
+ );
1028
+ } else {
1029
+ return fail(`${evidenceFile} unreadable — ${(e as Error).message}`);
1030
+ }
1031
+ }
1032
+ }
1033
+
870
1034
  let gate = 'the lifecycle gate did not refuse, which is itself a defect';
871
1035
  try {
872
1036
  assertTransition(record.lifecycle, 'promoted');
873
1037
  } catch (e) {
874
1038
  gate = (e as Error).message;
875
1039
  }
1040
+ // READ the status, never assert it. This line said `is OPEN` as a literal,
1041
+ // and on 2026-09-01 the blocker closed as `refused` — at which point the
1042
+ // refusal was still correct and its stated reason was not. Reading keeps the
1043
+ // two from diverging again, and every value the reader can return is a
1044
+ // refusing one, so no branch here can print a grant.
1045
+ const blockerStatus = readMergeAuthorityStatus();
876
1046
  process.stderr.write(
877
1047
  `evolution_lab: promote REFUSED for ${record.id}\n` +
878
1048
  ` lifecycle gate: ${gate}\n` +
879
- ' blocker: merge-authority is OPEN on road-to-governed-harness-evolution.\n' +
1049
+ ` blocker: merge-authority reads ${blockerStatus.toUpperCase()} on ` +
1050
+ `${path.basename(MERGE_AUTHORITY_ROADMAP, '.md')}.\n` +
880
1051
  ' Phases 1-6 are legal because they promote nothing (AI council 2026-08-29,\n' +
881
- ' anthropic + openai, 2/2). Phase 7 stays gated: granting merge authority\n' +
882
- ' weakens a human-in-the-loop guarantee and refusing it settles ADR-239\n' +
883
- ' Decision 3, and both are owner-reserved.\n' +
1052
+ ' anthropic + openai, 2/2). Phase 7 was gated on this blocker; on 2026-09-01\n' +
1053
+ ' the AI council settled ADR-239 Decision 3 in the REFUSING direction, scoped\n' +
1054
+ ' to PREAUTHORIZED authority, and the blocker closed as `refused`. Only\n' +
1055
+ ' `Status: resolved` AND `Disposition: granted` mint the capability, so a\n' +
1056
+ ' refusal keeps this verb shut exactly as an open blocker did.\n' +
884
1057
  ' Promotion into canonical agent-config remains a named human act performed\n' +
885
1058
  ' outside this tool. This verb will not perform it.\n',
886
1059
  );
@@ -1 +1 @@
1
- {"fingerprint":"81bdd86d:80948","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"code-graph-nudge":{"script":"src/scripts/hooks/code_graph_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"block-unauthorized-git":{"script":"src/scripts/hooks/block_unauthorized_git.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","block-unauthorized-git","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","hot-context","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","block-unauthorized-git","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","rule-inject"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","hot-context","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","block-unauthorized-git","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
1
+ {"fingerprint":"877cc83a:82357","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"code-graph-nudge":{"script":"src/scripts/hooks/code_graph_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"block-unauthorized-git":{"script":"src/scripts/hooks/block_unauthorized_git.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","block-unauthorized-git","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","hot-context","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","block-unauthorized-git","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","rule-inject"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","hot-context","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","block-unauthorized-git","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}