@event4u/agent-config 13.0.0 → 14.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 (123) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +195 -315
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/evals/roadmap.json +8 -0
  5. package/dist/agent-src/commands/fix/ci.md +39 -1
  6. package/dist/agent-src/commands/pr/create.md +65 -4
  7. package/dist/agent-src/commands/roadmap/next.md +28 -5
  8. package/dist/agent-src/commands/work.md +16 -0
  9. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +47 -0
  10. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +94 -0
  11. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +30 -0
  12. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +21 -8
  13. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +55 -8
  14. package/dist/agent-src/contexts/execution/subagent-response-contract.md +42 -0
  15. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +29 -0
  16. package/dist/agent-src/rules/command-suggestion-policy.md +33 -0
  17. package/dist/agent-src/rules/design-review-after-ui-write.md +25 -8
  18. package/dist/agent-src/rules/ui-audit-gate.md +25 -8
  19. package/dist/agent-src/scripts/gate_execute.ts +395 -0
  20. package/dist/agent-src/scripts/resume_probe.ts +422 -0
  21. package/dist/agent-src/scripts/roadmap_gates.ts +138 -4
  22. package/dist/agent-src/scripts/update_roadmap_progress.ts +53 -2
  23. package/dist/agent-src/skills/ai-council/SKILL.md +61 -0
  24. package/dist/agent-src/skills/experiment-loop/SKILL.md +116 -0
  25. package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +27 -0
  26. package/dist/agent-src/skills/experiment-loop/evals/triggers.json +17 -0
  27. package/dist/agent-src/skills/experiment-loop/references/pivot-ladder.md +54 -0
  28. package/dist/agent-src/skills/experiment-loop/references/protocol.md +61 -0
  29. package/dist/agent-src/skills/experiment-loop/references/register-format.md +66 -0
  30. package/dist/agent-src/skills/roadmap-management/SKILL.md +2 -2
  31. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  32. package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +8 -3
  33. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  34. package/dist/agent-src/templates/roadmaps.md +43 -3
  35. package/dist/cli/registry.js +1 -0
  36. package/dist/cli/registry.js.map +1 -1
  37. package/dist/cli-delegate/{chunk-N7FEST6D.js → chunk-7PZ4FSZB.js} +351 -174
  38. package/dist/cli-delegate/{chunk-3B72LSZL.js → chunk-F3YUF7SA.js} +1 -1
  39. package/dist/cli-delegate/cmd_conformance.js +336 -112
  40. package/dist/cli-delegate/cmd_doctor.js +2 -2
  41. package/dist/cli-delegate/cmd_handoff.js +1 -1
  42. package/dist/discovery/deprecation-report.md +1 -1
  43. package/dist/discovery/discovery-manifest.json +40 -18
  44. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  45. package/dist/discovery/discovery-manifest.summary.md +3 -3
  46. package/dist/discovery/dormancy-report.md +1 -1
  47. package/dist/discovery/orphan-report.md +1 -1
  48. package/dist/discovery/packs.json +6 -5
  49. package/dist/discovery/trust-report.md +2 -2
  50. package/dist/discovery/workspaces.json +5 -4
  51. package/dist/hooks/dispatch.js +2128 -1326
  52. package/dist/mcp/registry-manifest.json +3 -3
  53. package/dist/mcp/server.json +2 -2
  54. package/dist/mcp/server.mjs +1764 -899
  55. package/dist/router.json +1 -1
  56. package/dist/scripts/condense.js +1 -1
  57. package/dist/scripts/condense.js.map +1 -1
  58. package/dist/ui/assets/{index-B0aMJnuz.js → index-C1pBRm1f.js} +2 -2
  59. package/dist/ui/assets/index-C1pBRm1f.js.map +1 -0
  60. package/dist/ui/index.html +1 -1
  61. package/package.json +1 -1
  62. package/src/agent-src/scripts/gate_execute.ts +395 -0
  63. package/src/agent-src/scripts/resume_probe.ts +422 -0
  64. package/src/agent-src/scripts/roadmap_gates.ts +138 -4
  65. package/src/agent-src/scripts/update_roadmap_progress.ts +53 -2
  66. package/src/config/ci-local-parity.yml +13 -0
  67. package/src/config/evaluator-budgets.json +4 -4
  68. package/src/config/gate-coverage.yml +111 -5
  69. package/src/config/gate-violation-baselines.json +5 -5
  70. package/src/config/rule-activation-census.json +41 -0
  71. package/src/config/rule-stub-ceilings.json +52 -0
  72. package/src/scripts/_dispatch.bash +4 -0
  73. package/src/scripts/_lib/evaluator_contract.ts +159 -0
  74. package/src/scripts/_lib/gate_ledger.ts +5 -1
  75. package/src/scripts/_lib/gh_transient.ts +80 -0
  76. package/src/scripts/_lib/release_material.ts +16 -5
  77. package/src/scripts/_lib/review_independence.ts +111 -0
  78. package/src/scripts/_lib/session_register.ts +14 -0
  79. package/src/scripts/_lib/skill_catalogue.ts +20 -0
  80. package/src/scripts/_lib/skill_catalogue_series.ts +411 -0
  81. package/src/scripts/_lib/turn_end_refusals.ts +482 -0
  82. package/src/scripts/ai_council/_py_json.ts +96 -0
  83. package/src/scripts/ai_council/cli_call_budget.ts +357 -0
  84. package/src/scripts/ai_council/clients.ts +80 -143
  85. package/src/scripts/ai_council/config.ts +25 -11
  86. package/src/scripts/ai_council/probe_store.ts +196 -0
  87. package/src/scripts/ai_council/qualification.ts +425 -0
  88. package/src/scripts/ai_council/qualification_wiring.ts +243 -0
  89. package/src/scripts/ai_council/quorum_wiring.ts +211 -0
  90. package/src/scripts/ai_team/team_dispatch.ts +40 -6
  91. package/src/scripts/build_archive_index.ts +62 -3
  92. package/src/scripts/capture_skill_catalogue.ts +264 -4
  93. package/src/scripts/check_evaluator_schema.ts +249 -0
  94. package/src/scripts/check_gate_coverage.ts +93 -0
  95. package/src/scripts/check_pr_ci_current.ts +492 -0
  96. package/src/scripts/check_review_schema.ts +195 -0
  97. package/src/scripts/check_rule_activation_census.ts +451 -0
  98. package/src/scripts/check_rule_stub_ceiling.ts +1128 -0
  99. package/src/scripts/condense.ts +1 -1
  100. package/src/scripts/council_cli.ts +141 -191
  101. package/src/scripts/dispatch_r2_reviewer.ts +8 -1
  102. package/src/scripts/git_authorization_hook.ts +186 -1
  103. package/src/scripts/hook_manifest.yaml +72 -5
  104. package/src/scripts/hooks/block_unauthorized_git.ts +62 -6
  105. package/src/scripts/hooks/concern_registry.ts +4 -0
  106. package/src/scripts/hooks/dispatch_hook.ts +43 -1
  107. package/src/scripts/hooks/interruption_ledger_hook.ts +256 -0
  108. package/src/scripts/hooks/ship_diff_volume_hook.ts +180 -0
  109. package/src/scripts/hooks/turn_end_gate_hook.ts +119 -26
  110. package/src/scripts/hooks_doctor.ts +112 -0
  111. package/src/scripts/interruption_report.ts +443 -0
  112. package/src/scripts/lint_evidence_artifacts.ts +359 -0
  113. package/src/scripts/lint_roadmap_blockers.ts +65 -0
  114. package/src/scripts/lint_roadmap_complexity.ts +7 -1
  115. package/src/scripts/release.ts +38 -53
  116. package/src/scripts/rule_activation_census.ts +292 -0
  117. package/src/scripts/schemas/evaluator-output.schema.json +60 -0
  118. package/src/scripts/schemas/review-findings.schema.json +31 -0
  119. package/src/scripts/self_review_gate.ts +6 -0
  120. package/src/scripts/session_register_hook.ts +30 -1
  121. package/src/scripts/sync_pr_branch.ts +271 -0
  122. package/src/scripts/test_council_qualification.ts +213 -0
  123. package/dist/ui/assets/index-B0aMJnuz.js.map +0 -1
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Transient-failure handling for `gh` calls in the release pipeline.
3
+ *
4
+ * `gh` does not retry GitHub's 5xx responses — including the pre-flight
5
+ * "does a PR already exist" GraphQL query it runs before every `pr create`.
6
+ * The release run therefore dies at whichever step happens to catch the
7
+ * outage, after the commit and the push already landed.
8
+ *
9
+ * Pure over strings and an injected executor so the classifier and the retry
10
+ * loop are exercised by the fixture tests without a network or a real sleep.
11
+ */
12
+
13
+ export interface GhRunResult {
14
+ returncode: number;
15
+ stdout: string;
16
+ stderr: string;
17
+ }
18
+
19
+ /** Backoff between attempts. Length is the retry budget: three retries, ~23s. */
20
+ export const GH_RETRY_DELAYS_MS = [2_000, 6_000, 15_000] as const;
21
+
22
+ /**
23
+ * Retry-worthy failures only. A 4xx is the caller's fault and repeating it
24
+ * just delays the real message — the one exception is 429, which is the same
25
+ * wait-and-repeat shape as a 5xx.
26
+ */
27
+ const _TRANSIENT_RE =
28
+ /HTTP 5\d\d|HTTP 429|No server is currently available|Something went wrong while executing your query|exceeded a secondary rate limit|\b(?:ETIMEDOUT|ECONNRESET|EAI_AGAIN)\b|TLS handshake timeout/;
29
+
30
+ /**
31
+ * Whether `stderr` describes a transient GitHub failure.
32
+ *
33
+ * Deliberately reads stderr ALONE. `gh` writes errors there, while stdout on a
34
+ * failing call can still carry payload the caller asked for (`pr view --json
35
+ * body`) — and a changelog body that happens to quote `HTTP 500` must not turn
36
+ * a permanent failure into three pointless retries.
37
+ */
38
+ export function is_transient_gh_failure(stderr: string): boolean {
39
+ return _TRANSIENT_RE.test(stderr);
40
+ }
41
+
42
+ /**
43
+ * `gh` argv rendered for an error line, long values elided.
44
+ *
45
+ * The release-PR body is passed as a single `--body` argument and runs to tens
46
+ * of thousands of characters. Rendering argv verbatim is what buried the real
47
+ * one-line `gh` error under a 22k dump on 14.0.0.
48
+ */
49
+ export function gh_argv_label(args: readonly string[], max = 60): string {
50
+ return ['gh', ...args].map((a) => (a.length > max ? `${a.slice(0, max - 1)}…` : a)).join(' ');
51
+ }
52
+
53
+ /**
54
+ * Run `gh <args>` through `exec`, repeating while the failure is transient and
55
+ * the budget lasts. Returns the last result — classifying it is the caller's
56
+ * job, so a `check: false` probe keeps its own fallback behaviour.
57
+ *
58
+ * `sleep` and `notify` are injected rather than called directly so the loop is
59
+ * testable without a real 23-second wait, and so a caller running under a test
60
+ * exec-override can pass a no-op sleep while the delay sequence itself still
61
+ * runs and can be asserted.
62
+ */
63
+ export function gh_retry(
64
+ args: readonly string[],
65
+ exec: (argv: readonly string[]) => GhRunResult,
66
+ opts: { sleep?: (ms: number) => void; notify?: (message: string) => void } = {},
67
+ ): GhRunResult {
68
+ let result = exec(['gh', ...args]);
69
+ for (let i = 0; result.returncode !== 0 && i < GH_RETRY_DELAYS_MS.length; i++) {
70
+ if (!is_transient_gh_failure(result.stderr)) {
71
+ break;
72
+ }
73
+ const ms = GH_RETRY_DELAYS_MS[i]!;
74
+ const first = result.stderr.trim().split('\n')[0] ?? '';
75
+ opts.notify?.(`↻ ${gh_argv_label(args, 24)} — transient GitHub failure, retry in ${ms / 1_000}s: ${first}`);
76
+ opts.sleep?.(ms);
77
+ result = exec(['gh', ...args]);
78
+ }
79
+ return result;
80
+ }
@@ -21,7 +21,18 @@ export interface ChangelogSection {
21
21
  body: string;
22
22
  }
23
23
 
24
- const _NEXT_HEADING_RE = /^##\s+\[?\d+\.\d+\.\d+/m;
24
+ /**
25
+ * Where a changelog section ends: the next release entry OR the next era
26
+ * banner. Era banners are level 1 and release entries level 2+ — the same
27
+ * invariant the release-validation `changelog-entry` gate relies on, and the
28
+ * one `lint_changelog_rollback` / `lint_breaking_changes_index` already encode
29
+ * as `/^##? /`. Without the era arm the newest entry runs to end-of-file after
30
+ * a split, which leaves it as the last `##` heading above archived banners.
31
+ *
32
+ * Exported because release.ts bounds the previous entry the same way, and two
33
+ * copies of a boundary is how one of them stays wrong.
34
+ */
35
+ export const NEXT_SECTION_RE = /^(?:##\s+\[?\d+\.\d+\.\d+|# Era:)/m;
25
36
 
26
37
  function _reEscape(s: string): string {
27
38
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -29,9 +40,9 @@ function _reEscape(s: string): string {
29
40
 
30
41
  /**
31
42
  * Extract the CHANGELOG section for `version` — heading plus body up to the
32
- * next version heading (or end of file). Returns null when no heading for
33
- * `version` exists. Matches both heading shapes the generator emits
34
- * (`## X.Y.Z (date)` and `## [X.Y.Z](compare-url) (date)`).
43
+ * next version heading or era banner (or end of file). Returns null when no
44
+ * heading for `version` exists. Matches both heading shapes the generator
45
+ * emits (`## X.Y.Z (date)` and `## [X.Y.Z](compare-url) (date)`).
35
46
  */
36
47
  export function extract_changelog_section(text: string, version: string): ChangelogSection | null {
37
48
  const headingRe = new RegExp(`^##\\s+\\[?${_reEscape(version)}\\b.*$`, 'm');
@@ -41,7 +52,7 @@ export function extract_changelog_section(text: string, version: string): Change
41
52
  }
42
53
  const bodyStart = m.index + m[0].length;
43
54
  const rest = text.slice(bodyStart);
44
- const next = _NEXT_HEADING_RE.exec(rest);
55
+ const next = NEXT_SECTION_RE.exec(rest);
45
56
  const sectionEnd = bodyStart + (next ? next.index : rest.length);
46
57
  const body = text
47
58
  .slice(bodyStart, sectionEnd)
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Review independence — a recorded property of a review, never a promise.
3
+ *
4
+ * The failure this closes: a review whose members all share a model family
5
+ * produces an artifact byte-indistinguishable from one backed by independent
6
+ * models, so a consumer reads "no findings" as acceptance either way. The
7
+ * self-review gate is the live instance — it calls ONE Anthropic client, and
8
+ * the ledger it writes says nothing about that.
9
+ *
10
+ * Derived, never set by hand: `acceptance_status` follows from
11
+ * `review_independence`, so a same-family set carrying `accepted` is
12
+ * unrepresentable rather than merely forbidden. Two fields a producer can set
13
+ * inconsistently would reintroduce the ambiguity the pair exists to remove.
14
+ *
15
+ * Evidence: agents/evidence/eval-findings/metric-loop-s03.md.
16
+ */
17
+
18
+ /** The five providers `ai_council/config.ts::_VALID_PROVIDERS` admits. */
19
+ const PROVIDER_FAMILY: Readonly<Record<string, string>> = {
20
+ anthropic: 'anthropic',
21
+ openai: 'openai',
22
+ gemini: 'google',
23
+ xai: 'xai',
24
+ perplexity: 'perplexity',
25
+ };
26
+
27
+ export type ReviewIndependence = 'cross-family' | 'same-family' | 'single-member' | 'unknown';
28
+ export type AcceptanceStatus = 'accepted' | 'provisional';
29
+
30
+ /**
31
+ * How much INDEPENDENT evidence backs the verdict — deliberately orthogonal to
32
+ * how much effort the reviewer spent.
33
+ *
34
+ * Collapsing the two is what lets a long, careful, single-model pass read as
35
+ * acceptance: effort is visible in the artifact (findings, detail, rationale)
36
+ * and independence is not, so a reader with only one axis substitutes the one
37
+ * they can see. A five-hour same-family review is `single-pass`, and a terse
38
+ * two-family one is `independent`. That inversion is the point.
39
+ */
40
+ export type Assurance = 'unreviewed' | 'single-pass' | 'independent';
41
+
42
+ export function reviewIndependence(memberNames: readonly string[]): ReviewIndependence {
43
+ const present = memberNames.map((n) => n.trim()).filter((n) => n.length > 0);
44
+ if (present.length === 0) return 'unknown';
45
+ if (present.length === 1) return 'single-member';
46
+ const families = new Set(present.map((n) => PROVIDER_FAMILY[n] ?? `unknown:${n}`));
47
+ return families.size > 1 ? 'cross-family' : 'same-family';
48
+ }
49
+
50
+ /**
51
+ * Only a cross-family set may be described as acceptance.
52
+ *
53
+ * `unknown` maps to `provisional`, not to a third value: an absent member set
54
+ * is not evidence of independence, and the safe direction on an integrity field
55
+ * is the weaker claim.
56
+ */
57
+ export function acceptanceStatus(independence: ReviewIndependence): AcceptanceStatus {
58
+ return independence === 'cross-family' ? 'accepted' : 'provisional';
59
+ }
60
+
61
+ export function assuranceFor(independence: ReviewIndependence): Assurance {
62
+ if (independence === 'cross-family') return 'independent';
63
+ if (independence === 'unknown') return 'unreviewed';
64
+ return 'single-pass';
65
+ }
66
+
67
+ export interface IndependenceFields {
68
+ readonly review_independence: ReviewIndependence;
69
+ readonly acceptance_status: AcceptanceStatus;
70
+ readonly assurance: Assurance;
71
+ readonly reviewers: readonly string[];
72
+ }
73
+
74
+ /** The three fields plus the member set they were derived from. */
75
+ export function independenceFields(memberNames: readonly string[]): IndependenceFields {
76
+ const independence = reviewIndependence(memberNames);
77
+ return {
78
+ review_independence: independence,
79
+ acceptance_status: acceptanceStatus(independence),
80
+ assurance: assuranceFor(independence),
81
+ reviewers: [...memberNames],
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Consistency violations for an artifact that already carries the fields.
87
+ *
88
+ * The gate's teeth: a producer that hand-set `accepted` beside a same-family
89
+ * independence is caught here rather than trusted.
90
+ */
91
+ export function independenceViolations(doc: Record<string, unknown>): string[] {
92
+ const out: string[] = [];
93
+ const indep = doc['review_independence'];
94
+ const accept = doc['acceptance_status'];
95
+ const assur = doc['assurance'];
96
+ if (indep === undefined) {
97
+ out.push('review_independence is absent — an artifact that does not declare its independence reads as acceptance by default');
98
+ return out;
99
+ }
100
+ const expectedAccept = acceptanceStatus(indep as ReviewIndependence);
101
+ if (accept !== expectedAccept) {
102
+ out.push(
103
+ `acceptance_status is ${String(accept)} but review_independence ${String(indep)} derives ${expectedAccept}`,
104
+ );
105
+ }
106
+ const expectedAssur = assuranceFor(indep as ReviewIndependence);
107
+ if (assur !== undefined && assur !== expectedAssur) {
108
+ out.push(`assurance is ${String(assur)} but review_independence ${String(indep)} derives ${expectedAssur}`);
109
+ }
110
+ return out;
111
+ }
@@ -212,6 +212,20 @@ export interface SessionRecord {
212
212
  started_at: string;
213
213
  /** ISO-8601 UTC, rewritten every heartbeat. The liveness signal. */
214
214
  last_seen: string;
215
+ /**
216
+ * Per-detector turn-end refusals THIS session has taken, or absent when it
217
+ * has taken none.
218
+ *
219
+ * `road-to-stop-gate-honesty` § D-2: the gate refuses turn-ends with "no
220
+ * per-session visibility into how often it happens", and a refused turn-end
221
+ * costs the user at least one extra model turn. The counts ride this
222
+ * existing write — the reader is one small `readFileSync` of a record the
223
+ * gate already maintains, so the heartbeat gains no spawn.
224
+ *
225
+ * Optional on purpose: a record written before this field existed, or by a
226
+ * session that was never refused, is still a valid record.
227
+ */
228
+ turn_end_refusals?: Record<string, number>;
215
229
  }
216
230
 
217
231
  /**
@@ -454,10 +454,27 @@ export function observationSourceOf(record: ObservationRecord): ObservationSourc
454
454
  return record.observation_source ?? 'self-report';
455
455
  }
456
456
 
457
+ /**
458
+ * The self-report path's record.
459
+ *
460
+ * `projectedSkillCount` and `projectionMode` are optional in the SAME shape the
461
+ * two host-event builders use — omitted rather than defaulted, because absence
462
+ * is not `legacy-all` and never was (see `ObservationRecord.projection_mode`).
463
+ *
464
+ * They were missing here until 2026-08-18, and the omission was load-bearing in
465
+ * one direction: the self-report path is the ONLY one that fills `bare_names`,
466
+ * so it is the only source the pointable-but-bare join below can read — and
467
+ * every claude observation in the corpus therefore carried no scope at all,
468
+ * while the codex records beside them did. A series that changes scope
469
+ * mid-flight without recording it is not comparable, which is exactly what
470
+ * claim 7 of the roadmap that asked for the field says.
471
+ */
457
472
  export function buildObservationRecord(
458
473
  report: SelectorReport,
459
474
  host: string,
460
475
  observedAt: string,
476
+ projectedSkillCount?: number,
477
+ projectionMode?: ProjectionMode,
461
478
  ): ObservationRecord {
462
479
  return {
463
480
  schema: 1,
@@ -471,6 +488,8 @@ export function buildObservationRecord(
471
488
  separating_candidates: report.candidates.filter((c) => c.separates).map((c) => c.id),
472
489
  truncation_mode: 'per-entry',
473
490
  observation_source: 'self-report',
491
+ ...(projectedSkillCount === undefined ? {} : { projected_skill_count: projectedSkillCount }),
492
+ ...(projectionMode === undefined ? {} : { projection_mode: projectionMode }),
474
493
  };
475
494
  }
476
495
 
@@ -1113,3 +1132,4 @@ export function formatReport(report: SelectorReport): string {
1113
1132
  );
1114
1133
  return lines.join('\n');
1115
1134
  }
1135
+