@event4u/agent-config 14.14.0 → 14.14.1

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 (66) 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 +33 -0
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/pr/create.md +16 -1
  7. package/dist/agent-src/contexts/execution/terminal-states.md +25 -4
  8. package/dist/agent-src/rules/missing-skill-recovery.md +2 -2
  9. package/dist/agent-src/rules/token-budget-discipline.md +2 -2
  10. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  11. package/dist/cli/registry.js +1 -0
  12. package/dist/cli-delegate/{chunk-ILMUPLGW.js → chunk-7RXIKF62.js} +159 -86
  13. package/dist/cli-delegate/cmd_conformance.js +1 -1
  14. package/dist/cli-delegate/cmd_doctor.js +1 -1
  15. package/dist/discovery/deprecation-report.md +1 -1
  16. package/dist/discovery/discovery-manifest.json +5 -5
  17. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  18. package/dist/discovery/discovery-manifest.summary.md +1 -1
  19. package/dist/discovery/dormancy-report.md +1 -1
  20. package/dist/discovery/orphan-report.md +1 -1
  21. package/dist/discovery/packs.json +2 -2
  22. package/dist/discovery/trust-report.md +1 -1
  23. package/dist/discovery/workspaces.json +2 -2
  24. package/dist/hooks/dispatch.js +528 -371
  25. package/dist/mcp/registry-manifest.json +2 -2
  26. package/dist/mcp/server.json +2 -2
  27. package/dist/mcp/server.mjs +185 -98
  28. package/package.json +1 -1
  29. package/src/config/assurance-capability-registry.json +1 -1
  30. package/src/config/evaluator-budgets.json +4 -4
  31. package/src/config/gate-coverage.yml +62 -2
  32. package/src/config/gate-reachability-exemptions.json +1 -0
  33. package/src/config/gate-violation-baselines.json +4 -3
  34. package/src/config/web-launch-readiness.json +4 -2
  35. package/src/scripts/_cli/_doctor_emit.ts +71 -0
  36. package/src/scripts/_cli/_doctor_strict.ts +163 -0
  37. package/src/scripts/_cli/cmd_doctor.ts +16 -37
  38. package/src/scripts/_dispatch.bash +11 -0
  39. package/src/scripts/_lib/branch_convergence.ts +186 -0
  40. package/src/scripts/_lib/context_observation.ts +132 -0
  41. package/src/scripts/_lib/continuation_ladder.ts +188 -0
  42. package/src/scripts/_lib/experiment_binding.ts +95 -0
  43. package/src/scripts/_lib/ignored_blocker.ts +8 -1
  44. package/src/scripts/_lib/outcome_envelope.ts +6 -1
  45. package/src/scripts/_lib/outcome_vocabularies.ts +135 -5
  46. package/src/scripts/_lib/release_highlights.ts +12 -3
  47. package/src/scripts/_lib/repeated_failure.ts +19 -2
  48. package/src/scripts/_lib/runtime_journal.ts +11 -4
  49. package/src/scripts/check_agent_artifact_location.ts +337 -0
  50. package/src/scripts/check_artefact_count_messaging.ts +74 -8
  51. package/src/scripts/check_enforcement_coverage.ts +40 -1
  52. package/src/scripts/check_release_highlights.ts +17 -1
  53. package/src/scripts/check_web_launch_readiness.ts +310 -20
  54. package/src/scripts/evolution_lab.ts +53 -1
  55. package/src/scripts/generate_capability_matrix.ts +16 -9
  56. package/src/scripts/grade_target_readiness.ts +221 -2
  57. package/src/scripts/hook_effect_doctor.ts +47 -4
  58. package/src/scripts/hooks/run_continuation_hook.ts +78 -88
  59. package/src/scripts/hooks/session_eol_hook.ts +12 -1
  60. package/src/scripts/install-hooks.sh +18 -0
  61. package/src/scripts/lint_code_comments.ts +106 -1
  62. package/src/scripts/release_drill.ts +57 -1
  63. package/src/scripts/release_publication.ts +58 -0
  64. package/src/scripts/roadmap_context.ts +15 -0
  65. package/src/scripts/skill_scout.ts +633 -0
  66. package/src/scripts/sync_pr_branch.ts +521 -42
@@ -20,10 +20,14 @@
20
20
  * - `check_command_count_messaging.ts` keeps the command-specific
21
21
  * active-vs-shim split checks.
22
22
  *
23
- * Scope: flagship surfaces only (SURFACES below). Dated census / analysis
24
- * snapshots (SKILL_CENSUS, skills-taxonomy, positioning-evidence, …) carry
25
- * point-in-time counts by design and are deliberately out of scope — the
26
- * gate's charter is the surfaces a fresh reader treats as current.
23
+ * Scope: flagship surfaces (SURFACES below) PLUS every governed rule under
24
+ * `src/rules/` (RULE_SURFACE_DIR). Rules were the largest hole this gate had:
25
+ * they are the most-delivered surface this package ships — a wrong self-count
26
+ * there reaches every consumer session — and the list below named sixteen doc
27
+ * paths and no rule path. Dated census / analysis snapshots (SKILL_CENSUS,
28
+ * skills-taxonomy, positioning-evidence, …) carry point-in-time counts by
29
+ * design and are deliberately out of scope — the gate's charter is the surfaces
30
+ * a fresh reader treats as current.
27
31
  *
28
32
  * Exit codes: 0 clean · 1 drift or internal inconsistency.
29
33
  */
@@ -66,6 +70,41 @@ export const SURFACES: readonly string[] = [
66
70
  // absent there. A gate must judge repo content, not untracked local state.
67
71
  ];
68
72
 
73
+ /**
74
+ * Governed rules, enumerated rather than listed.
75
+ *
76
+ * A hand-maintained list of 120 rule paths would go stale on the first rule
77
+ * added, which is the drift class this gate exists to catch — so the rule
78
+ * surface is a directory, walked at run time.
79
+ */
80
+ export const RULE_SURFACE_DIR = 'src/rules';
81
+
82
+ export function rule_surfaces(root: string = ROOT): string[] {
83
+ const dir = path.join(root, RULE_SURFACE_DIR);
84
+ if (!fs.existsSync(dir)) {
85
+ return [];
86
+ }
87
+ return fs
88
+ .readdirSync(dir)
89
+ .filter((f) => f.endsWith('.md'))
90
+ .sort()
91
+ .map((f) => `${RULE_SURFACE_DIR}/${f}`);
92
+ }
93
+
94
+ /**
95
+ * A count that belongs to a dated measurement, not to this package's live
96
+ * totals.
97
+ *
98
+ * The gate's charter already excludes point-in-time snapshots; until now it
99
+ * could only express that by leaving a whole FILE out. A rule may carry a dated
100
+ * host measurement inside a paragraph of live prose, and neither excluding the
101
+ * rule nor rewriting the measurement to today's total is correct — the second
102
+ * falsifies recorded evidence. The marker is per line, and it is a claim a
103
+ * reviewer can falsify: the line must name the date or the artefact the figure
104
+ * was measured against.
105
+ */
106
+ export const DATED_MEASUREMENT_MARKER = '<!-- count: dated -->';
107
+
69
108
  /** kind → canonical-count resolver. "governed rules" is the canonical total
70
109
  * phrasing for rules; bare "N rules" is NOT matched (too many legitimate
71
110
  * subset scopes: kernel rules, router rules, maintainer-only rules …). */
@@ -108,6 +147,9 @@ export function scan_text(
108
147
  for (const [kind, pattern] of KIND_PATTERNS) {
109
148
  for (let i = 0; i < lines.length; i++) {
110
149
  const re = new RegExp(pattern.source, pattern.flags);
150
+ if (lines[i]!.includes(DATED_MEASUREMENT_MARKER)) {
151
+ continue;
152
+ }
111
153
  for (const m of lines[i]!.matchAll(re)) {
112
154
  const found = Number.parseInt(m[2]!, 10);
113
155
  (seen[kind] ??= new Set()).add(found);
@@ -219,6 +261,15 @@ export interface CoverageGap {
219
261
  *
220
262
  * A position counts as anchored when some `TARGETS` pattern for the same
221
263
  * file, bound to a compatible kind, matches the same line.
264
+ *
265
+ * `src/rules/**` is scanned for VALUE drift but is deliberately excluded from
266
+ * this pass, and the reason is mechanical rather than stylistic: satisfying it
267
+ * would require `update_counts` to become a writer into `src/rules/`, where the
268
+ * kernel rules live behind `block_kernel_rule_writes`. A generator that must
269
+ * never touch part of its own target directory is a generator waiting to be
270
+ * disarmed by a path move. So a stale count in a rule fails on value and a human
271
+ * fixes it — the coverage claim this pass makes stays true of the surfaces it
272
+ * actually covers, instead of being widened into a claim it cannot keep.
222
273
  */
223
274
  export function anchor_coverage_gaps(root: string = ROOT): CoverageGap[] {
224
275
  const anchorsByFile = new Map<string, ReadonlyArray<[string, string]>>();
@@ -254,6 +305,16 @@ export function anchor_coverage_gaps(root: string = ROOT): CoverageGap[] {
254
305
 
255
306
  export function main(argv: readonly string[] = process.argv.slice(2)): number {
256
307
  const QUIET = argv.includes('--quiet');
308
+ // Enumerated, not listed. An empty walk means the rule tree moved and this
309
+ // gate is watching nothing — a dead scope, never a clean run.
310
+ const rules = rule_surfaces();
311
+ if (rules.length === 0) {
312
+ process.stderr.write(
313
+ `❌ check_artefact_count_messaging: ${RULE_SURFACE_DIR}/ resolved to no .md file — ` +
314
+ 'the rule surface moved and this gate would pass by blindness.\n',
315
+ );
316
+ return 1;
317
+ }
257
318
  // This gate walks no tree — it guards a hand-maintained surface list, and
258
319
  // every missing entry is skipped with a warning so nothing hard-breaks on a
259
320
  // doc rename. That tolerance is also the failure mode: a repo-wide docs
@@ -262,7 +323,7 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
262
323
  try {
263
324
  assertWatchlistResolves({
264
325
  gate: 'check_artefact_count_messaging',
265
- candidates: [...SURFACES, ...STRUCTURED_SURFACES.map((s) => s.file)],
326
+ candidates: [...SURFACES, ...STRUCTURED_SURFACES.map((s) => s.file), ...rules],
266
327
  repoRoot: ROOT,
267
328
  });
268
329
  } catch (exc) {
@@ -285,7 +346,7 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
285
346
 
286
347
  const allFindings: Finding[] = [];
287
348
  const global_seen: Record<string, Set<number>> = {};
288
- for (const rel of SURFACES) {
349
+ for (const rel of [...SURFACES, ...rules]) {
289
350
  const p = path.join(ROOT, rel);
290
351
  if (!fs.existsSync(p)) {
291
352
  process.stderr.write(` ⚠️ surface missing (skipped): ${rel}\n`);
@@ -347,8 +408,13 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
347
408
  process.stdout.write(` internal inconsistency — ${line}\n`);
348
409
  }
349
410
  process.stdout.write(
350
- '\nFix: run `./scripts-run src/scripts/update_counts` — every checked position\n' +
351
- 'is anchored, so the generator can write it. Never hand-type a count.\n',
411
+ '\nFix: on a flagship surface, run `./scripts-run src/scripts/update_counts` —\n' +
412
+ 'every anchored position is generator-written, so never hand-type one there.\n' +
413
+ `Under ${RULE_SURFACE_DIR}/ the generator does not write (the kernel rules live\n` +
414
+ 'there behind block_kernel_rule_writes), so a rule count is a hand edit: correct\n' +
415
+ 'the number, or — if the figure is a dated measurement rather than a live\n' +
416
+ `self-count — mark that line \`${DATED_MEASUREMENT_MARKER}\` and say what it was\n` +
417
+ 'measured against.\n',
352
418
  );
353
419
  }
354
420
 
@@ -628,6 +628,26 @@ export interface Summary {
628
628
  frequency_gap: number;
629
629
  /** Rules with no `obligation_frequency` to join — the nine kernel rules. */
630
630
  frequency_unclassified: number;
631
+ /**
632
+ * The three classes that make `undeclared` readable.
633
+ *
634
+ * WHY THEY SHIP IN THE ARTEFACT. `undeclared` is the number reviewers quote,
635
+ * and quoted bare it reads as a backlog of rules somebody forgot to wire.
636
+ * Most of it is nothing of the kind. `kernel_denied` rules cannot carry an
637
+ * `enforced_by` field at all — `block_kernel_rule_writes` refuses the write
638
+ * with no agent-accessible override, so their absence is structural.
639
+ * `observer` rules have a carrier that fires and cannot block by design.
640
+ * `carrier_less` rules have no machine carrier of any kind.
641
+ *
642
+ * A reader subtracting these from `undeclared` gets the population where
643
+ * wiring is actually the missing thing — and, more usefully, sees at a glance
644
+ * that the observer set (10) is the reachable one: a floor set against the
645
+ * full `undeclared` would stall in its second release and be ignored, which
646
+ * is the failure `check_release_highlights.ts` already documents for its own
647
+ * warning.
648
+ */
649
+ kernel_denied: number;
650
+ carrier_less: number;
631
651
  /**
632
652
  * The denominator every figure above is taken over, WITH its frame. See
633
653
  * {@link denominator_frames} for why the frame ships even when the two
@@ -652,6 +672,14 @@ export function summarise(rows: RuleCoverage[]): Summary {
652
672
  blocking_pct: rows.length === 0 ? 0 : Math.round((blocking / rows.length) * 1000) / 10,
653
673
  frequency_gap: count((r) => r.frequency_verdict === 'gap'),
654
674
  frequency_unclassified: count((r) => r.frequency_verdict === 'unclassified'),
675
+ kernel_denied: count(
676
+ (r) => KERNEL_RULE_ID_SET.has(r.id) && r.frequency_verdict === 'unclassified',
677
+ ),
678
+ carrier_less: count(
679
+ (r) =>
680
+ r.declared.length > 0 &&
681
+ r.declared.every((d) => d.startsWith('observer:maintainer-review')),
682
+ ),
655
683
  frames: denominator_frames(rows.length),
656
684
  };
657
685
  }
@@ -779,7 +807,13 @@ function main(argv: string[]): number {
779
807
  'blocking and in that bucket at once. Coverage is a ratchet: --check fails ' +
780
808
  'when blocking falls, or unwired / local_only / missing / frequency_gap ' +
781
809
  'rises. Regenerate intentionally with --write-baseline when the change is ' +
782
- 'the point.',
810
+ 'the point. READ `undeclared` WITH ITS THREE CLASSES, never bare: ' +
811
+ '`kernel_denied` cannot carry an enforced_by field at all ' +
812
+ '(block_kernel_rule_writes refuses the write, no agent-accessible ' +
813
+ 'override), `observer` has a carrier that fires and cannot block by ' +
814
+ 'design, and `carrier_less` has no machine carrier of any kind. The ' +
815
+ 'reachable population is the observer set, not `undeclared` — a floor ' +
816
+ 'set against the full number would stall in its second release.',
783
817
  summary,
784
818
  },
785
819
  null,
@@ -811,6 +845,11 @@ function main(argv: string[]): number {
811
845
  ` frequency: ${summary.frequency_gap} gap · ${summary.frequency_unclassified} unclassified ` +
812
846
  `(kernel — block_kernel_rule_writes denies the field)`,
813
847
  );
848
+ lines.push(
849
+ ` undeclared ${summary.undeclared} splits: ${summary.kernel_denied} kernel-denied · ` +
850
+ `${summary.observer} observer · ${summary.carrier_less} carrier-less — ` +
851
+ `the observer set is the reachable population`,
852
+ );
814
853
  // The denominator is published WITH its frame, and it is the only sanctioned
815
854
  // source for that number: `check_enforcement_denominator` reds when a
816
855
  // tracked doc carries an enforcement count this resolver did not produce.
@@ -280,6 +280,7 @@ export function main(argv: readonly string[]): number {
280
280
  // reaches another section, another era file, or `docs/archive/`. That is
281
281
  // what keeps eighteen historical marker lines from turning this into a
282
282
  // permanent red on every future release.
283
+ const derived = derive_categories(span);
283
284
  const drafts = stale_draft_labels(curated);
284
285
  if (drafts.length > 0) {
285
286
  process.stderr.write(
@@ -292,9 +293,24 @@ export function main(argv: readonly string[]): number {
292
293
  ' historical sections carrying the same marker are out of scope and do not ' +
293
294
  'block this release.\n',
294
295
  );
296
+ // The evidence, not just the verdict. The draft line cites SHAs and a
297
+ // deriving reason; what a releaser needs in order to write the real
298
+ // claim is the SUBJECT behind each SHA, and looking eleven of them up
299
+ // by hand is the friction that made this refusal cheaper to ignore
300
+ // than to satisfy across five releases. The `_none_` branch below has
301
+ // printed its evidence since it was built; this one now matches it.
302
+ for (const label of drafts) {
303
+ const hits = derived[label] ?? [];
304
+ if (hits.length === 0) {
305
+ continue;
306
+ }
307
+ process.stderr.write(` - **${label}:** derived from\n`);
308
+ for (const e of hits) {
309
+ process.stderr.write(` ${e}\n`);
310
+ }
311
+ }
295
312
  return 1;
296
313
  }
297
- const derived = derive_categories(span);
298
314
  const contradictions = highlight_contradictions(curated, derived);
299
315
  if (contradictions.length === 0) {
300
316
  process.stdout.write(`✅ curated head plausible for ${version} (span ${from}..${to})\n`);