@event4u/agent-config 14.18.0 → 14.20.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 (210) 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 +120 -129
  5. package/README.md +71 -149
  6. package/dist/agent-src/README.md +1 -1
  7. package/dist/agent-src/commands/agent-handoff.md +44 -43
  8. package/dist/agent-src/commands/review/changes.md +19 -19
  9. package/dist/agent-src/commands/review.md +2 -2
  10. package/dist/agent-src/contexts/execution/host-capability-manifest.md +37 -4
  11. package/dist/agent-src/rules/autonomous-execution.md +1 -1
  12. package/dist/agent-src/rules/git-history-discipline.md +2 -2
  13. package/dist/agent-src/rules/guidelines.md +1 -1
  14. package/dist/agent-src/rules/session-canary.md +2 -2
  15. package/dist/agent-src/rules/token-efficiency.md +1 -1
  16. package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
  17. package/dist/agent-src/skills/adversarial-review/SKILL.md +0 -8
  18. package/dist/agent-src/skills/canvas-design/SKILL.md +1 -1
  19. package/dist/agent-src/skills/design-intelligence/SKILL.md +1 -1
  20. package/dist/agent-src/skills/design-intelligence/data/app-interface.csv +1 -1
  21. package/dist/agent-src/skills/design-intelligence/data/motion.csv +17 -17
  22. package/dist/agent-src/skills/design-intelligence/data/ux-guidelines.csv +2 -2
  23. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +17 -0
  24. package/dist/agent-src/skills/design-intelligence/references/design-rules-checklist.md +4 -4
  25. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  26. package/dist/agent-src/skills/design-variations/SKILL.md +1 -1
  27. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
  28. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +1 -1
  29. package/dist/agent-src/skills/fe-design/SKILL.md +32 -5
  30. package/dist/agent-src/skills/fe-design/references/craft-floor.md +7 -0
  31. package/dist/agent-src/skills/fe-design/references/design-patterns.md +47 -2
  32. package/dist/agent-src/skills/laravel-scheduling/SKILL.md +3 -1
  33. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  34. package/dist/agent-src/skills/project-analyzer/SKILL.md +0 -6
  35. package/dist/agent-src/skills/react-native-setup/SKILL.md +3 -3
  36. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  37. package/dist/agent-src/skills/sequential-thinking/SKILL.md +18 -8
  38. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
  39. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  40. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
  41. package/dist/agent-src/skills/ui-apply-generic/SKILL.md +1 -1
  42. package/dist/agent-src/skills/ui-component-architect/SKILL.md +1 -1
  43. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +17 -2
  44. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  45. package/dist/agent-src/templates/roadmaps.md +14 -1
  46. package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  47. package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  48. package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
  49. package/dist/cli/commands/recordTriggerEval.js +2 -2
  50. package/dist/cli/main.js +1 -1
  51. package/dist/cli/mcp/dispatch.js +10 -0
  52. package/dist/cli/mcp/stdio.js +33 -2
  53. package/dist/cli/mcp/telemetry.js +227 -0
  54. package/dist/cli-delegate/{chunk-AKJGUQNO.js → chunk-C6IPZRDA.js} +484 -353
  55. package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
  56. package/dist/cli-delegate/{chunk-7RXIKF62.js → chunk-NUMQHLS5.js} +304 -136
  57. package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-PI2GU3DP.js} +163 -1
  58. package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
  59. package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
  60. package/dist/cli-delegate/cmd_adr_effective.js +318 -81
  61. package/dist/cli-delegate/cmd_conformance.js +489 -121
  62. package/dist/cli-delegate/cmd_doctor.js +2 -2
  63. package/dist/cli-delegate/cmd_export.js +2 -2
  64. package/dist/cli-delegate/cmd_handoff.js +42 -12
  65. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  66. package/dist/cli-delegate/cmd_prune.js +2 -2
  67. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  68. package/dist/cli-delegate/cmd_session_recycle.js +59 -902
  69. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  70. package/dist/cli-delegate/cmd_sync.js +2 -2
  71. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  72. package/dist/cli-delegate/cmd_validate.js +2 -2
  73. package/dist/discovery/deprecation-report.md +1 -1
  74. package/dist/discovery/discovery-manifest.json +34 -33
  75. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  76. package/dist/discovery/discovery-manifest.summary.md +1 -1
  77. package/dist/discovery/dormancy-report.md +1 -1
  78. package/dist/discovery/orphan-report.md +1 -1
  79. package/dist/discovery/packs.json +2 -2
  80. package/dist/discovery/trust-report.md +1 -1
  81. package/dist/discovery/workspaces.json +2 -2
  82. package/dist/hooks/dispatch.js +4455 -3025
  83. package/dist/install/install.mjs +975 -689
  84. package/dist/mcp/registry-manifest.json +2 -2
  85. package/dist/mcp/server.json +2 -2
  86. package/dist/mcp/server.mjs +2087 -1134
  87. package/dist/scripts/_lib/model_tier.js +1 -1
  88. package/dist/scripts/mcp_server/telemetry.js +148 -0
  89. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +1 -1
  90. package/docs/guidelines/agent-infra/naming.md +1 -1
  91. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  92. package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
  93. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
  94. package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
  95. package/docs/guidelines/design-antipatterns.md +87 -64
  96. package/docs/guidelines/redundancy-taxonomy.md +28 -0
  97. package/package.json +1 -1
  98. package/src/agent-src/README.md +1 -1
  99. package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  100. package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  101. package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
  102. package/src/config/assurance-capability-registry.json +9 -0
  103. package/src/config/ci-local-parity.yml +6 -0
  104. package/src/config/gate-coverage.yml +225 -0
  105. package/src/config/gate-violation-baselines.json +18 -6
  106. package/src/config/release-gate-locality.yml +12 -0
  107. package/src/scripts/_cli/cmd_doctor.ts +2 -2
  108. package/src/scripts/_cli/cmd_handoff.ts +1 -1
  109. package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
  110. package/src/scripts/_cli/cmd_update.ts +1 -1
  111. package/src/scripts/_cli/cmd_versions.ts +1 -1
  112. package/src/scripts/_lib/adr_frontmatter.ts +44 -0
  113. package/src/scripts/_lib/audit_field_provenance.ts +44 -3
  114. package/src/scripts/_lib/consequence_objects.ts +152 -0
  115. package/src/scripts/_lib/exec_evidence.ts +7 -0
  116. package/src/scripts/_lib/global_deploy_inventory.ts +2 -2
  117. package/src/scripts/_lib/host_capability.ts +38 -0
  118. package/src/scripts/_lib/host_permission_checks.ts +251 -0
  119. package/src/scripts/_lib/install_reach_checks.ts +33 -1
  120. package/src/scripts/_lib/mcp_bridge.ts +222 -10
  121. package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
  122. package/src/scripts/_lib/model_tier.ts +1 -1
  123. package/src/scripts/_lib/obligation_frequency.ts +2 -2
  124. package/src/scripts/_lib/orchestration_record.ts +23 -1
  125. package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
  126. package/src/scripts/_lib/release_highlights.ts +93 -0
  127. package/src/scripts/_lib/release_material.ts +64 -1
  128. package/src/scripts/_lib/release_position.ts +96 -0
  129. package/src/scripts/_lib/review_skipped_record.ts +17 -1
  130. package/src/scripts/_lib/runtime_journal.ts +26 -3
  131. package/src/scripts/_lib/runtime_wiring_checks.ts +12 -1
  132. package/src/scripts/_lib/security_lint.ts +179 -7
  133. package/src/scripts/_lib/self_repair.ts +141 -6
  134. package/src/scripts/_lib/self_repair_store.ts +273 -7
  135. package/src/scripts/_lib/session_register.ts +11 -6
  136. package/src/scripts/_lib/sqlite_schema.ts +22 -0
  137. package/src/scripts/_lib/subagent_capsule.ts +155 -3
  138. package/src/scripts/_lib/surface.ts +86 -0
  139. package/src/scripts/_lib/ui_authority.ts +116 -0
  140. package/src/scripts/adr/regenerate_index.ts +54 -1
  141. package/src/scripts/adr_cite_check.ts +71 -15
  142. package/src/scripts/ai_council/clients.ts +1 -1
  143. package/src/scripts/autonomy_friction_corpus.ts +229 -0
  144. package/src/scripts/build_proof.ts +15 -2
  145. package/src/scripts/build_rule_trigger_matrix.ts +5 -0
  146. package/src/scripts/check_beta_review_markers.ts +141 -17
  147. package/src/scripts/check_enforcement_coverage.ts +1 -1
  148. package/src/scripts/check_enforcement_denominator.ts +121 -11
  149. package/src/scripts/check_finding_dispositions.ts +66 -9
  150. package/src/scripts/check_gate_coverage.ts +96 -0
  151. package/src/scripts/check_mcp_doc_drift.ts +217 -0
  152. package/src/scripts/check_pack_size.ts +321 -3
  153. package/src/scripts/check_release_highlights.ts +74 -1
  154. package/src/scripts/check_skill_activation_claim.ts +179 -0
  155. package/src/scripts/check_trigger_evals.ts +1 -1
  156. package/src/scripts/conformance_scan.ts +44 -3
  157. package/src/scripts/explain_run.ts +1 -1
  158. package/src/scripts/generate_capability_matrix.ts +1 -1
  159. package/src/scripts/git_authorization_hook.ts +75 -1
  160. package/src/scripts/handoff_context_hook.ts +54 -7
  161. package/src/scripts/hook_manifest.json +1 -1
  162. package/src/scripts/hook_manifest.yaml +14 -11
  163. package/src/scripts/hooks/augment-dispatcher.sh +1 -1
  164. package/src/scripts/hooks/category_a.ts +291 -0
  165. package/src/scripts/hooks/cline-dispatcher.sh +1 -1
  166. package/src/scripts/hooks/cursor-dispatcher.sh +11 -5
  167. package/src/scripts/hooks/dispatch_hook.ts +17 -22
  168. package/src/scripts/hooks/git_command_classifier.ts +156 -1
  169. package/src/scripts/hooks/host_lowering.ts +215 -0
  170. package/src/scripts/hooks/host_lowering.yaml +185 -0
  171. package/src/scripts/hooks/host_semantics.ts +105 -37
  172. package/src/scripts/hooks/journal_record_hook.ts +10 -0
  173. package/src/scripts/hooks/permission_gate.ts +117 -0
  174. package/src/scripts/hooks/session_eol_hook.ts +18 -7
  175. package/src/scripts/hooks_status.ts +12 -10
  176. package/src/scripts/install.ts +57 -86
  177. package/src/scripts/install_anthropic_key.sh +2 -2
  178. package/src/scripts/lint_agent_security.ts +316 -25
  179. package/src/scripts/lint_confusables.ts +42 -6
  180. package/src/scripts/lint_design_antipattern_parity.ts +80 -0
  181. package/src/scripts/lint_evidence_artifacts.ts +45 -1
  182. package/src/scripts/lint_handoffs.ts +0 -132
  183. package/src/scripts/lint_hidden_unicode.ts +49 -7
  184. package/src/scripts/lint_hook_manifest.ts +87 -3
  185. package/src/scripts/lint_instruction_smuggling.ts +42 -6
  186. package/src/scripts/lint_mcp_config_security.ts +42 -6
  187. package/src/scripts/lint_motion_authority_drift.ts +731 -0
  188. package/src/scripts/lint_readme_size.ts +158 -12
  189. package/src/scripts/lint_reasoning_fixtures.ts +216 -0
  190. package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
  191. package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
  192. package/src/scripts/lint_skill_trigger_contradiction.ts +161 -0
  193. package/src/scripts/mcp_server/resources.ts +41 -0
  194. package/src/scripts/mcp_server/telemetry.ts +19 -4
  195. package/src/scripts/measure_sibling_naming.ts +150 -0
  196. package/src/scripts/orchestration_record.ts +12 -1
  197. package/src/scripts/redact_hook_capture.ts +1 -1
  198. package/src/scripts/release.ts +24 -24
  199. package/src/scripts/release_publication.ts +6 -2
  200. package/src/scripts/report_skill_activation.ts +319 -7
  201. package/src/scripts/schemas/review-findings.schema.json +5 -0
  202. package/src/scripts/schemas/skill.schema.json +2 -2
  203. package/src/scripts/self_repair_cli.ts +31 -1
  204. package/src/scripts/session_canary_hook.ts +1 -1
  205. package/src/scripts/session_register_hook.ts +4 -3
  206. package/src/scripts/skill_scout.ts +69 -0
  207. package/src/scripts/trigger_eval_grandfather.json +5 -1
  208. package/src/scripts/validate_agent_settings.ts +1 -1
  209. package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
  210. package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
@@ -3,7 +3,9 @@
3
3
  // Per `agents/roadmaps/archive/road-to-mcp-full-coverage.md` §Phase 1 J4 +
4
4
  // `docs/contracts/mcp-tool-stub-envelope.md`, both transports log every
5
5
  // `tools/call` with `{tool_name, client_id_hash, ts, transport,
6
- // outcome}`. Payload bodies are never logged; the client identifier is
6
+ // outcome}`. The stdio-lite surface (`src/cli/mcp/`) appends a sixth,
7
+ // optional `host` field; callers that do not know their client omit it and
8
+ // their records stay byte-identical to the frozen five-field envelope. Payload bodies are never logged; the client identifier is
7
9
  // hashed at the server boundary so the queryable store never sees raw
8
10
  // identity.
9
11
  //
@@ -107,15 +109,26 @@ export function build_record(options: {
107
109
  transport: string;
108
110
  client_id_hash_value?: string | null | undefined;
109
111
  ts?: string | null | undefined;
112
+ host?: string | null | undefined;
110
113
  }): Record<string, unknown> {
111
- const { tool_name, outcome, transport, client_id_hash_value, ts } = options;
112
- return {
114
+ const { tool_name, outcome, transport, client_id_hash_value, ts, host } = options;
115
+ const record: Record<string, unknown> = {
113
116
  tool_name,
114
117
  client_id_hash: client_id_hash_value || hash_client_id(),
115
118
  ts: ts || _now_iso(),
116
119
  transport,
117
120
  outcome,
118
121
  };
122
+ // `host` is APPENDED, and only when a caller supplies one, so a record
123
+ // written by a caller that does not know its client stays byte-identical
124
+ // to the five-field envelope the stub contract froze. It is a closed
125
+ // vocabulary resolved at the boundary (see `src/cli/mcp/telemetry.ts`),
126
+ // never a free-form string: a record type that cannot hold arbitrary text
127
+ // has no scrubber to fail.
128
+ if (typeof host === 'string' && host !== '') {
129
+ record.host = host;
130
+ }
131
+ return record;
119
132
  }
120
133
 
121
134
  /**
@@ -132,13 +145,15 @@ export function record_call(options: {
132
145
  transport: string;
133
146
  consumer_root?: string | null | undefined;
134
147
  client_id_hash_value?: string | null | undefined;
148
+ host?: string | null | undefined;
135
149
  }): Record<string, unknown> | null {
136
- const { tool_name, outcome, transport, consumer_root, client_id_hash_value } = options;
150
+ const { tool_name, outcome, transport, consumer_root, client_id_hash_value, host } = options;
137
151
  const record = build_record({
138
152
  tool_name,
139
153
  outcome,
140
154
  transport,
141
155
  client_id_hash_value,
156
+ host,
142
157
  });
143
158
  const target = _resolve_log_path(consumer_root ?? undefined);
144
159
  try {
@@ -0,0 +1,150 @@
1
+ /**
2
+ * measure_sibling_naming — how many skill descriptions name another skill.
3
+ *
4
+ * `road-to-one-motion-authority` step 5.2. An inbox census claimed "44/299
5
+ * descriptions name a sibling" and shipped no definition of *naming* and no
6
+ * script, so the figure could be neither reproduced nor refuted. A companion
7
+ * claim of "218/299 bodies" reproduced under no reading of the tree at all.
8
+ * This script exists so the next such number is falsifiable.
9
+ *
10
+ * WHAT "NAMES A SIBLING" MEANS HERE, stated because the census did not.
11
+ *
12
+ * A description names a sibling when it contains the exact `name:` value of a
13
+ * DIFFERENT shipped skill, delimited so it is not a fragment of a longer
14
+ * identifier. `\b` is not enough: it puts a boundary between `brand` and the
15
+ * hyphen in `brand-identity`, so a bare `\b`-matched `brand` would score every
16
+ * mention of `brand-identity` as naming `brand` too. The delimiter here is
17
+ * "not `[A-Za-z0-9-]`" on both sides, which is the smallest rule that keeps
18
+ * `mcp` out of `mcp-builder` and `laravel` out of `laravel-dto`.
19
+ *
20
+ * A skill naming ITSELF does not count — that is a description, not a pointer.
21
+ *
22
+ * WHAT THE NUMBER IS AND IS NOT.
23
+ *
24
+ * A KNOWN AND UNFIXABLE FALSE POSITIVE, named rather than left for a reader to
25
+ * find: some skill names are ordinary English words, so a description can score
26
+ * a match by accident. `canvas-design` scores `brand` on the phrase "brand
27
+ * assets", which is not a pointer to the `brand` skill. Excluding short or
28
+ * common names would trade this for a false negative on the skills whose names
29
+ * really are those words, and there is no rule that gets both. The count is
30
+ * therefore an upper bound; the per-skill list is printed so a reader can see
31
+ * which matches are real.
32
+ *
33
+ * It is a count of descriptions that mention a sibling by name. It is NOT a
34
+ * measure of routing quality: a description can name a sibling uselessly, and a
35
+ * description that names none can be perfectly routable on its own keywords.
36
+ * The reason the count is worth having is narrower — the router reads
37
+ * descriptions and nothing else, so a family whose members never point at each
38
+ * other is a family the router cannot traverse.
39
+ *
40
+ * Exit code is 0 unless `--min <n>` is given and the count falls below it.
41
+ */
42
+
43
+ import fs from 'node:fs';
44
+ import path from 'node:path';
45
+ import { fileURLToPath, pathToFileURL } from 'node:url';
46
+
47
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
48
+ const REPO_ROOT = path.resolve(HERE, '..', '..');
49
+ const SKILLS_REL = path.join('src', 'skills');
50
+
51
+ export interface SkillRecord { name: string; description: string }
52
+
53
+ /** Read `name:` and `description:` out of a SKILL.md frontmatter block. */
54
+ export function parseSkill(text: string): SkillRecord | null {
55
+ if (!text.startsWith('---')) return null;
56
+ const end = text.indexOf('\n---', 3);
57
+ if (end < 0) return null;
58
+ const fm = text.slice(3, end);
59
+ const name = /^name:\s*(.+)$/m.exec(fm)?.[1]?.trim() ?? '';
60
+ let description = /^description:\s*(.+)$/m.exec(fm)?.[1]?.trim() ?? '';
61
+ if ((description.startsWith('"') && description.endsWith('"'))
62
+ || (description.startsWith("'") && description.endsWith("'"))) {
63
+ description = description.slice(1, -1);
64
+ }
65
+ description = description.replace(/\\"/g, '"');
66
+ if (name === '') return null;
67
+ return { name, description };
68
+ }
69
+
70
+ export function loadSkills(root: string): SkillRecord[] {
71
+ const dir = path.join(root, SKILLS_REL);
72
+ if (!fs.existsSync(dir)) return [];
73
+ const out: SkillRecord[] = [];
74
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
75
+ if (!entry.isDirectory()) continue;
76
+ const file = path.join(dir, entry.name, 'SKILL.md');
77
+ if (!fs.existsSync(file)) continue;
78
+ const rec = parseSkill(fs.readFileSync(file, 'utf-8'));
79
+ if (rec !== null) out.push(rec);
80
+ }
81
+ return out.sort((a, b) => a.name.localeCompare(b.name));
82
+ }
83
+
84
+ /** Identifier-boundary containment: `mcp` is not found inside `mcp-builder`. */
85
+ export function namesIdentifier(haystack: string, id: string): boolean {
86
+ let from = 0;
87
+ for (;;) {
88
+ const i = haystack.indexOf(id, from);
89
+ if (i < 0) return false;
90
+ const before = i === 0 ? '' : haystack[i - 1] ?? '';
91
+ const after = haystack[i + id.length] ?? '';
92
+ const isPart = (c: string): boolean => c !== '' && /[A-Za-z0-9-]/.test(c);
93
+ if (!isPart(before) && !isPart(after)) return true;
94
+ from = i + 1;
95
+ }
96
+ }
97
+
98
+ /** For each skill, the OTHER skills its description names. Sorted, deterministic. */
99
+ export function siblingsNamed(skills: readonly SkillRecord[]): Map<string, string[]> {
100
+ const names = skills.map((s) => s.name);
101
+ const out = new Map<string, string[]>();
102
+ for (const s of skills) {
103
+ const hits = names
104
+ .filter((n) => n !== s.name && namesIdentifier(s.description, n))
105
+ .sort();
106
+ out.set(s.name, hits);
107
+ }
108
+ return out;
109
+ }
110
+
111
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
112
+ const rootFlag = argv.indexOf('--root');
113
+ const root = rootFlag >= 0 ? (argv[rootFlag + 1] ?? REPO_ROOT) : REPO_ROOT;
114
+ const minFlag = argv.indexOf('--min');
115
+ const min = minFlag >= 0 ? Number(argv[minFlag + 1]) : null;
116
+ const json = argv.includes('--json');
117
+
118
+ const skills = loadSkills(root);
119
+ const map = siblingsNamed(skills);
120
+ const naming = [...map].filter(([, v]) => v.length > 0);
121
+
122
+ if (json) {
123
+ process.stdout.write(`${JSON.stringify({
124
+ total: skills.length,
125
+ naming: naming.length,
126
+ entries: Object.fromEntries(naming),
127
+ }, null, 1)}\n`);
128
+ } else {
129
+ process.stdout.write(`scanned: ${String(skills.length)}\n`);
130
+ process.stdout.write(
131
+ `sibling-naming: ${String(naming.length)}/${String(skills.length)} description(s) name at least one other shipped skill\n\n`,
132
+ );
133
+ for (const [name, hits] of naming) {
134
+ process.stdout.write(` ${name} → ${hits.join(', ')}\n`);
135
+ }
136
+ }
137
+
138
+ if (min !== null && Number.isFinite(min) && naming.length < min) {
139
+ process.stderr.write(
140
+ `\n❌ measure_sibling_naming: ${String(naming.length)} below the declared floor of ${String(min)}\n`,
141
+ );
142
+ return 1;
143
+ }
144
+ return 0;
145
+ }
146
+
147
+ if (process.argv[1] !== undefined) {
148
+ const invoked = pathToFileURL(path.resolve(process.argv[1])).href;
149
+ if (invoked === import.meta.url) process.exitCode = main();
150
+ }
@@ -10,7 +10,7 @@
10
10
  * ./scripts-run src/scripts/orchestration_record \
11
11
  * --spawn-count 1 --token-delta -72000 --provenance measured \
12
12
  * --tier-chosen lite --tier-source inferred --task-class read-only-fanout \
13
- * [--tiers sonnet,opus] [--agent-combo implementer,judge] [--wall-clock-ms 18500] [--dispatch-outcome DONE] \
13
+ * [--rules-applied a,b] [--tiers sonnet,opus] [--agent-combo implementer,judge] [--wall-clock-ms 18500] [--dispatch-outcome DONE] \
14
14
  * [--first-pass-success true|false] [--escalated true|false] \
15
15
  * [--init-tokens 1200] [--payload-hash <hex8-64>] [--lookup-class definition|references|string-existence|report-run] \
16
16
  * [--route-taken primitive|subagent|ask] [--budget-hit true|false] [--correctness-match true|false] \
@@ -141,6 +141,17 @@ export function main(argv: string[] = process.argv.slice(2)): number {
141
141
  if (raw === undefined) return undefined;
142
142
  return raw.split(',').map((v) => v.trim()).filter(Boolean);
143
143
  })(),
144
+ // `--rules-applied=a,b` records the rules the run actually carried.
145
+ // Unlike `--skills-applied`, an OMITTED flag and an empty value mean
146
+ // the same thing here: audit-log-v1 makes `rules_applied` mandatory on
147
+ // every line, so `[]` is how "nothing observed" is spelled, and there
148
+ // is no absent-key slot to distinguish it from. What this flag replaced
149
+ // is the fabricated `['delegation-policy']` this producer wrote on
150
+ // every line until 2026-09-07.
151
+ rules_applied: str(flags, 'rules-applied')
152
+ ?.split(',')
153
+ .map((v) => v.trim())
154
+ .filter(Boolean),
144
155
  task_size_estimate: int(flags, 'task-size-estimate'),
145
156
  wall_clock_ms: int(flags, 'wall-clock-ms'),
146
157
  dispatch_tokens: int(flags, 'dispatch-tokens'),
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Ported from the retired Python `redact_hook_capture.py` (Phase 8 / Wave 8g).
6
6
  *
7
- * Reads JSON capture files written by `dispatch_hook.py` (when
7
+ * Reads JSON capture files written by `dispatch_hook.ts` (when
8
8
  * `AGENT_HOOK_CAPTURE_DIR` is set) and produces a redacted version
9
9
  * suitable for pasting into the verified-platforms roadmap.
10
10
  *
@@ -49,8 +49,10 @@
49
49
  * Idempotency: pass `--resume` to recover from a partial failure. Each
50
50
  * step then probes existing state (branch, commit, PR, tag, GitHub
51
51
  * Release) and skips work that is already done, instead of erroring out.
52
- * Without `--resume` the pipeline still mutates git/network state, so
53
- * re-running on a dirty tree needs `--resume` (or a manual cleanup). The
52
+ * Re-running from `release/{target}` needs neither the flag nor a clean
53
+ * tree — that position, dirty, is the state `guard_release_curation` leaves
54
+ * behind, and `preflightPosition` accepts it (a dirty `main` still refuses).
55
+ * The
54
56
  * two entry points guard against colliding with each other via these same
55
57
  * probes plus the CI workflow's concurrency group — whichever starts
56
58
  * second sees the other's in-progress state and skips or refuses cleanly.
@@ -124,6 +126,7 @@ import {
124
126
  derive_category_hits,
125
127
  render_derived_head_values,
126
128
  } from './_lib/release_highlights.js';
129
+ import { preflightPosition } from './_lib/release_position.js';
127
130
  import {
128
131
  RELEASE_HEAD_DEFAULT,
129
132
  extract_changelog_section,
@@ -784,17 +787,17 @@ export function assert_scheduled_deprecations_clear(
784
787
  /**
785
788
  * Fail fast on conditions that would break the release mid-flight.
786
789
  *
787
- * In `--resume` mode two invariants are relaxed:
790
+ * The start position — which branch, and whether a dirty tree is tolerated —
791
+ * is `preflightPosition` in `_lib/release_position.ts`, and it is NO LONGER
792
+ * gated on `--resume`:
793
+ * `release/{target}` is where `guard_release_curation` leaves the operator, so
794
+ * refusing it there made the guard's own remedy unreachable. Read that
795
+ * function's header for the measurement.
788
796
  *
789
- * - The starting branch may be `release/{target}` in addition to `main` —
790
- * both are valid resume positions (mid-pipeline crash after step 1 leaves
791
- * you on the release branch).
792
- * - The target-tag-exists check is dropped — execute() probes for existing
793
- * tags/releases and skips them.
797
+ * `--resume` still relaxes ONE invariant here: the target-tag-exists check is
798
+ * dropped, because execute() probes for existing tags/releases and skips them.
794
799
  *
795
- * Tree cleanliness, gh auth, and `main` in-sync with origin are still
796
- * enforced, so resuming has the same starting posture as a fresh run; only
797
- * step-level outcomes differ.
800
+ * gh auth and `main` in-sync with origin are enforced either way.
798
801
  *
799
802
  * `opts.ci` swaps the gh-auth probe (see below) for the CI-mode variant —
800
803
  * everything else is identical between the two entry points.
@@ -832,20 +835,17 @@ function preflight(target: string, opts: { resume?: boolean; ci?: boolean } = {}
832
835
 
833
836
  const branch = git(['rev-parse', '--abbrev-ref', 'HEAD'], { capture: true });
834
837
  const release_branch = `release/${target}`;
835
- const allowed = resume ? new Set([MAIN_BRANCH, release_branch]) : new Set([MAIN_BRANCH]);
836
- if (!allowed.has(branch)) {
837
- if (resume) {
838
- die(
839
- `resume must run from '${MAIN_BRANCH}' or '${release_branch}', ` +
840
- `currently on '${branch}'`,
841
- );
842
- }
843
- die(`release must run from '${MAIN_BRANCH}', currently on '${branch}'`);
838
+ const position = preflightPosition({
839
+ branch,
840
+ mainBranch: MAIN_BRANCH,
841
+ releaseBranch: release_branch,
842
+ porcelain: git(['status', '--porcelain'], { capture: true }),
843
+ });
844
+ if (!position.proceed) {
845
+ die(position.message ?? `release cannot start from '${branch}'`);
844
846
  }
845
-
846
- const porcelain = git(['status', '--porcelain'], { capture: true });
847
- if (porcelain) {
848
- die('working tree is not clean; commit or stash first');
847
+ if (position.notice) {
848
+ process.stdout.write(`\u26a0\ufe0f ${position.notice}\n`);
849
849
  }
850
850
 
851
851
  // --force lets the remote's tag positions win over stale local tags.
@@ -731,8 +731,12 @@ export function guard_release_curation(version: string, prMerged = false): void
731
731
  marked.join('\n')
732
732
  : '') +
733
733
  '\n Stopped BEFORE committing — no release commit, no branch on ' +
734
- `${REMOTE}, no pull request, no tag. Curate the ` +
735
- '`### Release highlights` head, then re-run `task release`.',
734
+ `${REMOTE}, no pull request, no tag. HEAD is on the LOCAL ` +
735
+ `\`release/${version}\` branch and the generated section is in the working ` +
736
+ 'tree: curate the `### Release highlights` head in `CHANGELOG.md` there, then ' +
737
+ 're-run `task release`. That re-run works from this position — `preflightPosition` ' +
738
+ 'accepts the release branch with the uncommitted step-2 output, which it did not ' +
739
+ 'until 2026-09-07 (both spellings of the re-run were refused before step 1).',
736
740
  );
737
741
  }
738
742