@event4u/agent-config 17.0.0 → 17.1.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 (119) 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 +104 -485
  5. package/README.md +2 -1
  6. package/dist/agent-src/contexts/execution/host-capability-manifest.md +5 -3
  7. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  8. package/dist/agent-src/templates/roadmaps.md +5 -1
  9. package/dist/cli-delegate/{chunk-IROAQ77A.js → chunk-3PK3VZHB.js} +107 -9
  10. package/dist/cli-delegate/{chunk-2SFOOFJJ.js → chunk-BZJ4Y3CI.js} +1 -1
  11. package/dist/cli-delegate/{chunk-CAL76ADI.js → chunk-CMZEKSNN.js} +52 -10
  12. package/dist/cli-delegate/{chunk-ESUNQ5XR.js → chunk-E3CFULNX.js} +22 -4
  13. package/dist/cli-delegate/{chunk-GOMILC3O.js → chunk-QBHEI5N4.js} +4 -3
  14. package/dist/cli-delegate/{chunk-SIOMDAKL.js → chunk-VYZGJLCA.js} +29 -39
  15. package/dist/cli-delegate/chunk-W5JXMF2T.js +77 -0
  16. package/dist/cli-delegate/{chunk-4SHNERBL.js → chunk-XIAPY44N.js} +1 -1
  17. package/dist/cli-delegate/{chunk-JHMMWNJ2.js → chunk-YHAPONWV.js} +1 -1
  18. package/dist/cli-delegate/cmd_conformance.js +9 -8
  19. package/dist/cli-delegate/cmd_doctor.js +4 -4
  20. package/dist/cli-delegate/cmd_doctor_neighbours.js +2 -2
  21. package/dist/cli-delegate/cmd_explain.js +1 -1
  22. package/dist/cli-delegate/cmd_export.js +6 -6
  23. package/dist/cli-delegate/cmd_fleet.js +3 -3
  24. package/dist/cli-delegate/cmd_preflight.js +3 -3
  25. package/dist/cli-delegate/cmd_prune.js +6 -6
  26. package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
  27. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  28. package/dist/cli-delegate/cmd_sync.js +6 -6
  29. package/dist/cli-delegate/cmd_uninstall.js +6 -6
  30. package/dist/cli-delegate/cmd_update.js +9 -13
  31. package/dist/cli-delegate/cmd_validate.js +6 -6
  32. package/dist/discovery/deprecation-report.md +1 -1
  33. package/dist/discovery/discovery-manifest.json +4 -4
  34. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  35. package/dist/discovery/discovery-manifest.summary.md +1 -1
  36. package/dist/discovery/dormancy-report.md +1 -1
  37. package/dist/discovery/orphan-report.md +1 -1
  38. package/dist/discovery/packs.json +2 -2
  39. package/dist/discovery/trust-report.md +1 -1
  40. package/dist/discovery/workspaces.json +2 -2
  41. package/dist/hooks/dispatch.js +98 -74
  42. package/dist/hooks/dispatch.sha256 +1 -1
  43. package/dist/install/claudeRuleRewrite.js +10 -3
  44. package/dist/install/conflict.js +24 -2
  45. package/dist/install/conflictTracker.js +14 -3
  46. package/dist/install/install.mjs +222 -117
  47. package/dist/install/installThinLayer.js +1 -0
  48. package/dist/install/loggedWrites.js +142 -0
  49. package/dist/install/paths.js +12 -2
  50. package/dist/install/preserve.js +25 -4
  51. package/dist/install/txlog.js +10 -6
  52. package/dist/mcp/registry-manifest.json +2 -2
  53. package/dist/mcp/server.json +2 -2
  54. package/dist/mcp/server.mjs +845 -294
  55. package/dist/scripts/_lib/egress_rules.js +4 -1
  56. package/dist/scripts/_lib/identifier_redaction.js +35 -2
  57. package/dist/scripts/ai_council/seat_policy.js +7 -1
  58. package/dist/server/schemas/settings.js +1 -1
  59. package/package.json +1 -1
  60. package/src/config/ci-local-parity.yml +1 -1
  61. package/src/config/gate-coverage.yml +27 -7
  62. package/src/config/gate-violation-baselines.json +8 -2
  63. package/src/config/hook-bundle-budget.json +2 -2
  64. package/src/config/production-entries.json +18 -0
  65. package/src/config/release-gate-locality.yml +0 -7
  66. package/src/install/claudeRuleRewrite.ts +10 -1
  67. package/src/install/conflict.ts +24 -1
  68. package/src/install/conflictTracker.ts +18 -2
  69. package/src/install/installThinLayer.ts +6 -0
  70. package/src/install/loggedWrites.ts +148 -0
  71. package/src/install/paths.ts +11 -2
  72. package/src/install/preserve.ts +40 -4
  73. package/src/install/txlog.ts +10 -6
  74. package/src/scripts/_cli/cmd_conformance.ts +3 -2
  75. package/src/scripts/_cli/cmd_update.ts +15 -17
  76. package/src/scripts/_lib/council_settings_block.ts +9 -2
  77. package/src/scripts/_lib/egress_rules.ts +4 -1
  78. package/src/scripts/_lib/host_capability.ts +10 -5
  79. package/src/scripts/_lib/identifier_redaction.ts +38 -2
  80. package/src/scripts/_lib/price_freshness.ts +112 -0
  81. package/src/scripts/_lib/production_reach.ts +194 -0
  82. package/src/scripts/_lib/quota_parked.ts +17 -28
  83. package/src/scripts/_lib/release_findings_ingest.ts +13 -335
  84. package/src/scripts/_lib/tier_downshift_verdict.ts +81 -35
  85. package/src/scripts/ai_council/chairman.ts +5 -2
  86. package/src/scripts/ai_council/clients.ts +4 -3
  87. package/src/scripts/ai_council/free_hand_shadow.ts +24 -12
  88. package/src/scripts/ai_council/free_route_catalog.ts +142 -5
  89. package/src/scripts/ai_council/free_route_client.ts +4 -0
  90. package/src/scripts/ai_council/hand_payload.ts +115 -7
  91. package/src/scripts/ai_council/orchestrator.ts +7 -10
  92. package/src/scripts/ai_council/route_chooser.ts +1 -1
  93. package/src/scripts/ai_council/route_member.ts +66 -4
  94. package/src/scripts/ai_council/seat_policy.ts +8 -1
  95. package/src/scripts/ai_council/self_hosted_probe.ts +327 -0
  96. package/src/scripts/ai_council/status_surface.ts +2 -0
  97. package/src/scripts/ask_transport.ts +137 -15
  98. package/src/scripts/check_finding_dispositions.ts +25 -71
  99. package/src/scripts/check_release_pr_shape.ts +3 -3
  100. package/src/scripts/check_step_production_reach.ts +257 -0
  101. package/src/scripts/council_cli.ts +10 -8
  102. package/src/scripts/hook_manifest.json +1 -1
  103. package/src/scripts/hook_manifest.yaml +3 -0
  104. package/src/scripts/hooks/dispatch_hook.ts +2 -2
  105. package/src/scripts/hooks/payload_stub.ts +27 -0
  106. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +29 -70
  107. package/src/scripts/hooks/subagent_ledger_hook.ts +80 -0
  108. package/src/scripts/install.ts +2 -2
  109. package/src/scripts/lint_decision_classes.ts +34 -0
  110. package/src/scripts/lint_hook_manifest.ts +24 -0
  111. package/src/scripts/lint_roadmap_blockers.ts +52 -3
  112. package/src/scripts/release.ts +5 -9
  113. package/src/scripts/release_drill.ts +11 -165
  114. package/src/scripts/release_publication.ts +0 -9
  115. package/src/scripts/report_production_reach.ts +35 -0
  116. package/src/scripts/worker_reuse_shadow_report.ts +399 -1
  117. package/src/server/schemas/settings.ts +1 -1
  118. package/dist/cli-delegate/chunk-A4QJ6ENT.js +0 -50
  119. /package/dist/cli-delegate/{chunk-E6XNBVE4.js → chunk-KR5ZIFPO.js} +0 -0
@@ -202,27 +202,6 @@ interface WorldConfig {
202
202
  merge_fails_hard?: boolean;
203
203
  /** PR checks fail (watch exits non-zero) — the release must die. */
204
204
  checks_fail?: boolean;
205
- /**
206
- * Step 7's world — two knobs, because the step asks two questions.
207
- *
208
- * It VERIFIES: the ledger is produced by the self-review workflow, so the
209
- * only things a scenario can vary are whether the file is on the remote
210
- * branch and what the disposition gate answers. An earlier version of this
211
- * step ingested, and carried four more knobs for run discovery and artifact
212
- * download; those went with it when the owner moved the ingest into CI.
213
- */
214
- ledger_on_branch?: boolean;
215
- /**
216
- * Whether the ledger is on the TRUNK — the ref the merged path asks.
217
- *
218
- * Separate from `ledger_on_branch` because the two states worth testing are
219
- * exactly the ones a single boolean cannot express: present on the branch
220
- * and not on the trunk, and the reverse. Defaults to `ledger_on_branch`, so
221
- * every scenario written before this knob keeps its answer.
222
- */
223
- ledger_on_trunk?: boolean;
224
- /** Exit code + streams the disposition gate answers with. */
225
- disposition_verdict?: { status: number; stdout: string; stderr: string };
226
205
  /**
227
206
  * Content `git show <target>:CHANGELOG.md` returns.
228
207
  *
@@ -277,8 +256,7 @@ interface WorldConfig {
277
256
  tag_already_remote?: boolean;
278
257
  /**
279
258
  * The release PR is ALREADY merged when the run starts — the real
280
- * resume-after-merge state, in which steps 1 through 6 skip, step 7 still
281
- * verifies the ledger (on the trunk, since the branch is gone) and step 8
259
+ * resume-after-merge state, in which steps 1 through 7 skip and step 8
282
260
  * is the first step that does work.
283
261
  *
284
262
  * Added 2026-09-02 with `guard_release_branch_push`. Before that guard, a
@@ -383,9 +361,6 @@ class FakeWorld {
383
361
  private merge_races_once: boolean;
384
362
  private merge_fails_hard: boolean;
385
363
  private checks_fail: boolean;
386
- private readonly ledger_on_branch: boolean;
387
- private readonly ledger_on_trunk: boolean | undefined;
388
- private readonly disposition_verdict: { status: number; stdout: string; stderr: string };
389
364
  private readonly changelog: string;
390
365
  /** Working-tree content; see `WorldConfig.changelog_file`. */
391
366
  readonly changelog_file: string;
@@ -410,12 +385,6 @@ class FakeWorld {
410
385
  this.checks_fail = cfg.checks_fail ?? false;
411
386
  this.pr_merged = cfg.pr_already_merged ?? false;
412
387
  this.release_verify_fails = cfg.release_verify_fails ?? false;
413
- // Defaults keep every pre-2026-09-11 scenario green: the ledger is
414
- // already on the branch and the gate is happy, so step 7 is a two-call
415
- // no-op and the sequencing scenarios stay about sequencing.
416
- this.ledger_on_branch = cfg.ledger_on_branch ?? true;
417
- this.ledger_on_trunk = cfg.ledger_on_trunk;
418
- this.disposition_verdict = cfg.disposition_verdict ?? { status: 0, stdout: '', stderr: '' };
419
388
  }
420
389
 
421
390
  exec(args: readonly string[]): ExecResult {
@@ -590,21 +559,6 @@ class FakeWorld {
590
559
  return OK;
591
560
  }
592
561
 
593
- // Step 7 — the findings ledger.
594
- if (cmd.startsWith('git cat-file -e ')) {
595
- // REF-AWARE, because one boolean for every ref made the two states
596
- // that distinguish right from wrong inexpressible: on the branch
597
- // but not the trunk, and the reverse. A fourth review named the
598
- // merged-path scenario as asserting a string in the argv rather
599
- // than the ref that was read.
600
- const onTrunk = this.ledger_on_trunk ?? this.ledger_on_branch;
601
- const present = cmd.includes('/main:') ? onTrunk : this.ledger_on_branch;
602
- return present ? OK : { ...OK, status: 1 };
603
- }
604
- if (cmd.includes('check_finding_dispositions --release')) {
605
- return { ...this.disposition_verdict };
606
- }
607
-
608
562
  throw new Error(`FakeWorld: unscripted command: ${cmd}`);
609
563
  }
610
564
  }
@@ -777,48 +731,20 @@ const SCENARIOS: Record<string, Scenario> = {
777
731
  },
778
732
  },
779
733
 
780
- 'findings-ledger-verified-on-the-remote-branch': {
734
+ 'no-findings-ledger-does-not-stop-the-release': {
781
735
  summary:
782
- 'step 7: the ledger is on the remote branch and the gate passes — the release continues without producing anything',
783
- // Step 7 VERIFIES. The ingest lives in the self-review workflow, which
784
- // commits the ledger to the release branch; two review rounds showed no
785
- // placement inside this script can produce it, because the gate it
786
- // anticipates already reds the check step 6 waits on.
787
- // `resume: false` is load-bearing, not tidiness. `resume` defaults to
788
- // TRUE here, and on a resumed run the PR number is already in hand — so
789
- // a scenario that kept the default could not see the `--pr` flag being
790
- // dropped, which is exactly the hole this scenario asserts against.
791
- config: { ledger_on_branch: true, resume: false },
736
+ 'step 7: a release waits for no review ledger — everything on main is already reviewed and merged (owner, 2026-10-22)',
737
+ // The 17.0.0 cut stopped here for a day: a ledger the self-review never
738
+ // finished, on a branch whose every commit had been reviewed on main.
739
+ // The world scripts no ledger command, so reading one would throw;
740
+ // `resume: false` so a first run is covered, not only a resumed one.
741
+ config: { resume: false },
792
742
  expect_success: true,
793
743
  verify: (w) => {
794
744
  const f: string[] = [];
795
- const probe = w.calls.find((c) => c.startsWith('git cat-file -e '));
796
- _expect(probe !== undefined, 'the ledger presence was never probed', f);
797
745
  _expect(
798
- (probe ?? '').includes('origin/'),
799
- `the probe read a local ref, which a failed push makes true: ${probe ?? '(none)'}`,
800
- f,
801
- );
802
- _expect(
803
- !w.calls.some((c) => c.includes('--ingest')),
804
- 'step 7 ingested — that belongs to the workflow now, not the release',
805
- f,
806
- );
807
- _expect(
808
- !w.calls.some((c) => c.startsWith('gh run download')),
809
- 'step 7 downloaded an artifact — the release no longer produces the ledger',
810
- f,
811
- );
812
- // `--pr` is what makes the gate compare the review's own report
813
- // against the committed ledger. The PR number used to come only
814
- // from the resume-time probe, so on a FIRST run — this scenario —
815
- // the flag was silently dropped and the release passed a strictly
816
- // weaker check than the one it was trying to pre-satisfy.
817
- _expect(
818
- w.calls.some(
819
- (c) => c.includes('check_finding_dispositions --release') && c.includes('--pr '),
820
- ),
821
- 'the disposition gate ran without --pr, so an un-ingested finding would pass here',
746
+ !w.calls.some((c) => c.includes('check_finding_dispositions') || c.startsWith('git cat-file -e ')),
747
+ 'the release read the findings ledger',
822
748
  f,
823
749
  );
824
750
  _expect(
@@ -826,87 +752,7 @@ const SCENARIOS: Record<string, Scenario> = {
826
752
  'the release never reached the merge',
827
753
  f,
828
754
  );
829
- return f;
830
- },
831
- },
832
- 'findings-ledger-absent-stops-the-release': {
833
- summary:
834
- 'step 7: no ledger on the remote branch — the release STOPS rather than merging and tagging without one',
835
- config: { ledger_on_branch: false },
836
- expect_success: false,
837
- verify: (w, error) => {
838
- const f: string[] = [];
839
- _expect(
840
- (error ?? '').includes('is not on origin/'),
841
- `the stop did not name the ref it checked: ${error ?? '(no error)'}`,
842
- f,
843
- );
844
- _expect(
845
- !w.calls.includes(`gh pr merge ${w.branch} --merge --delete-branch`),
846
- 'merged with no ledger — the failure this step exists to end',
847
- f,
848
- );
849
- _expect(!w.tag_remote, 'tagged with no ledger', f);
850
- return f;
851
- },
852
- },
853
- 'findings-ledger-absent-after-a-hand-merge-still-stops': {
854
- summary:
855
- 'step 7: the PR is already merged and no ledger reached the trunk — the release STOPS instead of tagging a version whose ledger does not exist',
856
- // The reachable path to a shipped version with no ledger, and the one
857
- // the old code asserted away: the ingest produces nothing, step 7
858
- // stops, a human merges the PR, and the resumed run used to print "the
859
- // ledger rode in with it" without reading anything.
860
- // The two knobs differ on purpose: the ledger IS on the release branch
861
- // and is NOT on the trunk. A run that read the branch ref would pass
862
- // here, which is the wrong answer — the branch is deleted and the merge
863
- // is what decides whether the ledger shipped.
864
- config: { pr_already_merged: true, ledger_on_branch: true, ledger_on_trunk: false },
865
- expect_success: false,
866
- verify: (w, error) => {
867
- const f: string[] = [];
868
- _expect(
869
- (error ?? '').includes('already merged'),
870
- `the stop did not name the merged state: ${error ?? '(no error)'}`,
871
- f,
872
- );
873
- _expect(
874
- w.calls.some((c) => c.startsWith('git cat-file -e ') && c.includes('/main:')),
875
- 'the merged path never asked the trunk whether the ledger is there',
876
- f,
877
- );
878
- _expect(!w.tag_remote, 'tagged a version whose findings ledger does not exist', f);
879
- return f;
880
- },
881
- },
882
- 'findings-ledger-undispositioned-stops-and-shows-why': {
883
- summary:
884
- 'step 7: the disposition gate refuses — the release stops and the operator is shown the gate report, not just its scan line',
885
- config: {
886
- ledger_on_branch: true,
887
- disposition_verdict: {
888
- status: 1,
889
- stdout: 'scanned: 1',
890
- stderr: '- `a1` (critical security: x): no disposition status',
891
- },
892
- },
893
- expect_success: false,
894
- verify: (w, error) => {
895
- const f: string[] = [];
896
- // The defect an independent review reproduced: the stop message
897
- // preferred stdout, so the operator saw `scanned: 1` and the entire
898
- // per-finding diagnosis — which the gate writes to stderr — was
899
- // discarded on the one path where the message has to carry content.
900
- _expect(
901
- (error ?? '').includes('no disposition status'),
902
- `the gate's own diagnosis was swallowed: ${error ?? '(no error)'}`,
903
- f,
904
- );
905
- _expect(
906
- !w.calls.includes(`gh pr merge ${w.branch} --merge --delete-branch`),
907
- 'merged over an undispositioned ledger',
908
- f,
909
- );
755
+ _expect(w.tag_remote, 'the release never pushed its tag', f);
910
756
  return f;
911
757
  },
912
758
  },
@@ -229,15 +229,6 @@ export function _failed_checks_report(names: readonly string[]): string {
229
229
  'gate output lists the deriving commits (release-truth Phase 2).',
230
230
  );
231
231
  }
232
- if (names.includes('Blocking review findings dispositioned')) {
233
- lines.push(
234
- '',
235
- 'Dispositions: a blocking/high self-review finding has no committed',
236
- 'disposition. Ingest + adjudicate it in',
237
- 'agents/evidence/release-findings/<version>.json (release-truth Phase 3):',
238
- ' ./scripts-run src/scripts/check_finding_dispositions --ingest <findings.json>',
239
- );
240
- }
241
232
  lines.push('', 'After fixing, resume with: task release -- --resume --yes', '');
242
233
  return lines.join('\n');
243
234
  }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Print the production entries and the size and digest of their import closure
4
+ * (road-to-a-tick-the-shipped-path-earns 3.1). Two runs over one tree print the
5
+ * same digest; a moved entry or a new edge changes it.
6
+ *
7
+ * Usage: ./scripts-run src/scripts/report_production_reach [--entries]
8
+ */
9
+ import { createHash } from 'node:crypto';
10
+ import * as path from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ import { productionReach, worktreeOf } from './_lib/production_reach.js';
14
+
15
+ const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
16
+
17
+ export function main(argv: readonly string[]): number {
18
+ const reach = productionReach(worktreeOf(REPO_ROOT));
19
+ const digest = createHash('sha256')
20
+ .update([...reach.modules].sort().join('\n'))
21
+ .update('\0')
22
+ .update([...reach.symbols].sort().join('\n'))
23
+ .digest('hex')
24
+ .slice(0, 16);
25
+ if (argv.includes('--entries')) for (const e of reach.entries) process.stdout.write(`${e}\n`);
26
+ process.stdout.write(
27
+ `production reach: ${reach.entries.size} entries · ${reach.modules.size} modules · ` +
28
+ `${reach.symbols.size} reached symbols · digest ${digest}\n`,
29
+ );
30
+ return 0;
31
+ }
32
+
33
+ if (process.argv[1] !== undefined && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
34
+ process.exit(main(process.argv.slice(2)));
35
+ }