@event4u/agent-config 16.0.0 → 16.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 (246) 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 +297 -137
  5. package/CONTRIBUTING.md +9 -0
  6. package/README.md +2 -2
  7. package/dist/agent-src/commands/analyze/inbox.md +26 -0
  8. package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
  9. package/dist/agent-src/commands/challenge-me/closure.md +178 -0
  10. package/dist/agent-src/commands/challenge-me.md +9 -2
  11. package/dist/agent-src/commands/council/default.md +25 -5
  12. package/dist/agent-src/commands/feature/plan.md +28 -1
  13. package/dist/agent-src/commands/feature/roadmap.md +28 -1
  14. package/dist/agent-src/commands/implement-ticket.md +27 -0
  15. package/dist/agent-src/commands/jira-ticket.md +27 -0
  16. package/dist/agent-src/commands/pr/create.md +29 -0
  17. package/dist/agent-src/commands/pr/merge.md +60 -9
  18. package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
  19. package/dist/agent-src/commands/roadmap/create.md +74 -27
  20. package/dist/agent-src/commands/roadmap/materialize.md +27 -0
  21. package/dist/agent-src/commands/roadmap/process-full.md +123 -18
  22. package/dist/agent-src/commands/team.md +22 -0
  23. package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
  25. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
  27. package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
  28. package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
  29. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
  30. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
  31. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  32. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  33. package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
  34. package/dist/agent-src/rules/autonomous-execution.md +15 -8
  35. package/dist/agent-src/rules/delegation-policy.md +23 -45
  36. package/dist/agent-src/rules/design-fidelity.md +32 -37
  37. package/dist/agent-src/rules/evaluator-independence.md +43 -49
  38. package/dist/agent-src/rules/test-first.md +41 -0
  39. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  40. package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
  41. package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
  42. package/dist/agent-src/skills/database/data/manifest.json +4 -4
  43. package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
  44. package/dist/agent-src/skills/design-review/SKILL.md +50 -0
  45. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
  46. package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
  47. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  48. package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
  49. package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
  50. package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
  51. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
  52. package/dist/agent-src/templates/agent-settings.md +1 -1
  53. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  54. package/dist/agent-src/templates/roadmaps.md +188 -0
  55. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  56. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  57. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  58. package/dist/cli-delegate/check_update_banner.js +40 -2
  59. package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
  60. package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
  61. package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
  62. package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
  63. package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
  64. package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
  65. package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
  66. package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
  67. package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
  68. package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
  69. package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
  70. package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
  71. package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
  72. package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
  73. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  74. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  75. package/dist/cli-delegate/cmd_conformance.js +90 -56
  76. package/dist/cli-delegate/cmd_doctor.js +7 -5
  77. package/dist/cli-delegate/cmd_explain.js +2 -2
  78. package/dist/cli-delegate/cmd_export.js +9 -7
  79. package/dist/cli-delegate/cmd_fleet.js +4 -2
  80. package/dist/cli-delegate/cmd_handoff.js +4 -4
  81. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  82. package/dist/cli-delegate/cmd_migrate.js +2 -2
  83. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  84. package/dist/cli-delegate/cmd_preflight.js +4 -2
  85. package/dist/cli-delegate/cmd_prune.js +10 -8
  86. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  87. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  88. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  89. package/dist/cli-delegate/cmd_settings_get.js +28 -2
  90. package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
  91. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  92. package/dist/cli-delegate/cmd_sync.js +10 -8
  93. package/dist/cli-delegate/cmd_uninstall.js +16 -13
  94. package/dist/cli-delegate/cmd_update.js +1 -1
  95. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  96. package/dist/cli-delegate/cmd_validate.js +12 -10
  97. package/dist/cli-delegate/cmd_versions.js +1 -1
  98. package/dist/discovery/deprecation-report.md +1 -1
  99. package/dist/discovery/discovery-manifest.json +85 -38
  100. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  101. package/dist/discovery/discovery-manifest.summary.md +4 -4
  102. package/dist/discovery/dormancy-report.md +1 -1
  103. package/dist/discovery/orphan-report.md +1 -1
  104. package/dist/discovery/packs.json +10 -8
  105. package/dist/discovery/trust-report.md +3 -3
  106. package/dist/discovery/workspaces.json +8 -6
  107. package/dist/hooks/dispatch.js +1832 -1007
  108. package/dist/install/claudeRuleRewrite.js +14 -3
  109. package/dist/install/conflict.js +60 -10
  110. package/dist/install/conflictTracker.js +218 -0
  111. package/dist/install/fsPrimitives.js +54 -0
  112. package/dist/install/install.mjs +2007 -1481
  113. package/dist/install/manifestFiles.js +259 -0
  114. package/dist/install/preflight.js +14 -2
  115. package/dist/install/preserve.js +157 -0
  116. package/dist/install/recordedOwnership.js +132 -0
  117. package/dist/install/txlog.js +11 -2
  118. package/dist/mcp/registry-manifest.json +3 -3
  119. package/dist/mcp/server.json +2 -2
  120. package/dist/mcp/server.mjs +398 -39
  121. package/dist/router.json +1 -1
  122. package/dist/scripts/_lib/agent_settings.js +3 -2
  123. package/dist/scripts/_lib/fs_atomic.js +167 -0
  124. package/dist/scripts/_lib/installed_tools.js +460 -0
  125. package/dist/scripts/_lib/lean_projection_mode.js +3 -2
  126. package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
  127. package/dist/server/routes/install.js +8 -0
  128. package/dist/server/routes/wizard.js +9 -3
  129. package/dist/server/schemas/settings.js +17 -5
  130. package/dist/shared/missionExecution.js +97 -0
  131. package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
  132. package/dist/ui/index.html +1 -1
  133. package/docs/MIGRATION.md +103 -0
  134. package/docs/contracts/settings-classes.md +26 -7
  135. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  136. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  137. package/docs/guidelines/design-fidelity-routing.md +29 -0
  138. package/package.json +1 -1
  139. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  140. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  141. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  142. package/src/config/agent-settings.template.yml +139 -27
  143. package/src/config/auto-rule-budget.json +16 -0
  144. package/src/config/ci-local-parity.yml +18 -5
  145. package/src/config/continuity-surface.json +21 -0
  146. package/src/config/gate-coverage.yml +146 -13
  147. package/src/config/gate-violation-baselines.json +6 -6
  148. package/src/config/hook-token-budget.json +2 -0
  149. package/src/config/loop-surfaces.yaml +215 -0
  150. package/src/config/platform-anchor.json +3 -2
  151. package/src/config/release-gate-locality.yml +11 -0
  152. package/src/config/routing-coverage-seed.json +18 -4
  153. package/src/config/rule-enforcement-baseline.json +0 -1
  154. package/src/install/claudeRuleRewrite.ts +16 -2
  155. package/src/install/conflict.ts +65 -9
  156. package/src/install/conflictTracker.ts +299 -0
  157. package/src/install/fsPrimitives.ts +54 -0
  158. package/src/install/manifestFiles.ts +312 -0
  159. package/src/install/preflight.ts +16 -2
  160. package/src/install/preserve.ts +205 -0
  161. package/src/install/recordedOwnership.ts +149 -0
  162. package/src/install/txlog.ts +11 -2
  163. package/src/install/types.ts +19 -4
  164. package/src/scripts/_cli/cmd_conformance.ts +88 -15
  165. package/src/scripts/_cli/cmd_doctor.ts +4 -3
  166. package/src/scripts/_cli/cmd_route_explain.ts +9 -2
  167. package/src/scripts/_cli/cmd_settings_get.ts +44 -0
  168. package/src/scripts/_cli/doctor_execution.ts +90 -0
  169. package/src/scripts/_lib/activation_payload.ts +247 -0
  170. package/src/scripts/_lib/agent_settings.ts +4 -2
  171. package/src/scripts/_lib/authority_path.ts +102 -0
  172. package/src/scripts/_lib/cascade_base.ts +94 -0
  173. package/src/scripts/_lib/changelog_eras.ts +7 -2
  174. package/src/scripts/_lib/continuation_ladder.ts +149 -2
  175. package/src/scripts/_lib/council_transport.ts +129 -0
  176. package/src/scripts/_lib/delivery_ready.ts +112 -0
  177. package/src/scripts/_lib/forge_protection.ts +267 -0
  178. package/src/scripts/_lib/hook_platform_keys.ts +27 -0
  179. package/src/scripts/_lib/json_python_parity.ts +127 -0
  180. package/src/scripts/_lib/lean_projection_mode.ts +14 -3
  181. package/src/scripts/_lib/loop_surfaces.ts +382 -0
  182. package/src/scripts/_lib/mission_record.ts +190 -0
  183. package/src/scripts/_lib/obligation_frequency.ts +217 -0
  184. package/src/scripts/_lib/obligations.ts +402 -0
  185. package/src/scripts/_lib/orchestration_record.ts +11 -20
  186. package/src/scripts/_lib/release_highlights.ts +199 -10
  187. package/src/scripts/_lib/release_holds.ts +493 -0
  188. package/src/scripts/_lib/release_migration_gate.ts +184 -0
  189. package/src/scripts/_lib/rides_along.ts +102 -0
  190. package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
  191. package/src/scripts/_lib/test_delta.ts +166 -0
  192. package/src/scripts/_lib/test_provenance.ts +171 -0
  193. package/src/scripts/_lib/typed_op_grant.ts +246 -0
  194. package/src/scripts/_lib/typed_op_watch.ts +185 -0
  195. package/src/scripts/ai_council/config.ts +8 -11
  196. package/src/scripts/ai_council/fallback_config.ts +5 -3
  197. package/src/scripts/ai_council/ownership_classes.ts +118 -0
  198. package/src/scripts/ask_block_census.ts +285 -15
  199. package/src/scripts/check_enforcement_matrix.ts +624 -0
  200. package/src/scripts/check_gate_reachability.ts +173 -10
  201. package/src/scripts/check_generator_sync.ts +954 -0
  202. package/src/scripts/check_preamble_payload_budget.ts +75 -2
  203. package/src/scripts/check_release_highlights.ts +33 -1
  204. package/src/scripts/check_release_holds.ts +567 -0
  205. package/src/scripts/check_rule_projection_integrity.ts +22 -12
  206. package/src/scripts/check_test_delta.ts +294 -0
  207. package/src/scripts/check_test_weakening.ts +299 -0
  208. package/src/scripts/closure_scan.ts +333 -0
  209. package/src/scripts/compile_hook_manifest.ts +43 -3
  210. package/src/scripts/council_record_shape.ts +209 -0
  211. package/src/scripts/hook_manifest.json +1 -1
  212. package/src/scripts/hook_manifest.yaml +88 -9
  213. package/src/scripts/hooks/concern_registry.ts +4 -0
  214. package/src/scripts/hooks/design_pass_hook.ts +128 -3
  215. package/src/scripts/hooks/evidence_independence.ts +96 -0
  216. package/src/scripts/hooks/memory_recall_hook.ts +540 -0
  217. package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
  218. package/src/scripts/hooks/rule_inject_hook.ts +49 -1
  219. package/src/scripts/hooks/run_continuation_hook.ts +17 -20
  220. package/src/scripts/hooks_doctor.ts +85 -0
  221. package/src/scripts/hooks_status.ts +19 -0
  222. package/src/scripts/install.ts +106 -206
  223. package/src/scripts/janitor.ts +7 -0
  224. package/src/scripts/lint_decision_classes.ts +464 -0
  225. package/src/scripts/lint_hook_manifest.ts +11 -0
  226. package/src/scripts/lint_major_migration_sections.ts +450 -0
  227. package/src/scripts/lint_plan_risk_register.ts +47 -3
  228. package/src/scripts/lint_roadmap_blockers.ts +61 -0
  229. package/src/scripts/lint_roadmap_producers.ts +202 -0
  230. package/src/scripts/measure_rule_budget.ts +101 -5
  231. package/src/scripts/new_roadmap.ts +37 -0
  232. package/src/scripts/orchestration_record.ts +0 -5
  233. package/src/scripts/release.ts +14 -98
  234. package/src/scripts/release_drill.ts +267 -1
  235. package/src/scripts/release_publication.ts +51 -0
  236. package/src/scripts/report_enforcement_drift.ts +566 -0
  237. package/src/scripts/report_host_injection_effect.ts +3 -11
  238. package/src/scripts/report_standing_payload_by_host.ts +26 -152
  239. package/src/scripts/schemas/agent-settings.schema.json +23 -0
  240. package/src/scripts/schemas/command.schema.json +4 -0
  241. package/src/scripts/scope_growth.ts +219 -0
  242. package/src/scripts/trigger_eval_grandfather.json +0 -1
  243. package/src/scripts/ui_conformance_probe.ts +622 -0
  244. package/src/server/schemas/settings.ts +31 -7
  245. package/src/shared/missionExecution.ts +126 -0
  246. package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
@@ -170,6 +170,50 @@ var init_settingsCarveOut = __esm({
170
170
  }
171
171
  });
172
172
 
173
+ // src/scripts/_lib/settings_renamed_keys.ts
174
+ function _read(tree, dotted) {
175
+ let cur = tree;
176
+ for (const part of dotted.split(".")) {
177
+ if (cur === null || typeof cur !== "object" || Array.isArray(cur)) return void 0;
178
+ cur = cur[part];
179
+ }
180
+ return cur;
181
+ }
182
+ function _write(tree, dotted, value) {
183
+ const parts = dotted.split(".");
184
+ let cur = tree;
185
+ for (const part of parts.slice(0, -1)) {
186
+ const next = cur[part];
187
+ if (next === null || typeof next !== "object" || Array.isArray(next)) cur[part] = {};
188
+ cur = cur[part];
189
+ }
190
+ cur[parts[parts.length - 1]] = value;
191
+ }
192
+ function applyRenamedKeys(layer) {
193
+ for (const [oldKey, newKey] of RENAMED_KEYS) {
194
+ const oldValue = _read(layer, oldKey);
195
+ if (oldValue === void 0) continue;
196
+ if (_read(layer, newKey) === void 0) _write(layer, newKey, oldValue);
197
+ if (_warned.has(oldKey)) continue;
198
+ _warned.add(oldKey);
199
+ process.stderr.write(
200
+ `\u26A0\uFE0F settings: \`${oldKey}\` was renamed to \`${newKey}\`. The old key still works for one minor; rename it in your .agent-settings.yml.
201
+ `
202
+ );
203
+ }
204
+ return layer;
205
+ }
206
+ var RENAMED_KEYS, _warned;
207
+ var init_settings_renamed_keys = __esm({
208
+ "src/scripts/_lib/settings_renamed_keys.ts"() {
209
+ "use strict";
210
+ RENAMED_KEYS = /* @__PURE__ */ new Map([
211
+ ["planning.challenge_on_create", "planning.closure_pass"]
212
+ ]);
213
+ _warned = /* @__PURE__ */ new Set();
214
+ }
215
+ });
216
+
173
217
  // src/scripts/_lib/agent_settings.ts
174
218
  var agent_settings_exports = {};
175
219
  __export(agent_settings_exports, {
@@ -598,9 +642,9 @@ function load_agent_settings(options = {}) {
598
642
  }
599
643
  const cascade = _resolve_cascade_paths(cwd, project_path);
600
644
  const merged = template_defaults(template_path ?? void 0);
601
- _deep_merge(merged, user_global_filtered);
645
+ _deep_merge(merged, applyRenamedKeys(user_global_filtered));
602
646
  for (const p of cascade) {
603
- const layer = _read_yaml(p) ?? {};
647
+ const layer = applyRenamedKeys(_read_yaml(p) ?? {});
604
648
  if (Object.keys(layer).length > 0) {
605
649
  _deep_merge(merged, layer);
606
650
  }
@@ -911,6 +955,7 @@ var init_agent_settings = __esm({
911
955
  "use strict";
912
956
  init_user_global_paths();
913
957
  init_settingsCarveOut();
958
+ init_settings_renamed_keys();
914
959
  _require = createRequire(import.meta.url);
915
960
  Logger = class {
916
961
  name = "scripts._lib.agent_settings";
@@ -29720,6 +29765,203 @@ var init_git_common_dir = __esm({
29720
29765
  }
29721
29766
  });
29722
29767
 
29768
+ // src/shared/missionExecution.ts
29769
+ function executionPostureFromOverrides(layers) {
29770
+ const raw = {};
29771
+ for (const [key, value] of layers) {
29772
+ if (key === "execution.fix_loop_max") raw["fix_loop_max"] = value;
29773
+ else if (key === "execution.escalation") raw["escalation"] = value;
29774
+ }
29775
+ return resolveExecutionPosture(raw);
29776
+ }
29777
+ function resolveExecutionPosture(raw) {
29778
+ const block = raw ?? {};
29779
+ const rawMax = block["fix_loop_max"];
29780
+ const max = typeof rawMax === "number" && Number.isInteger(rawMax) && rawMax > 0 ? rawMax : FIX_LOOP_MAX_DEFAULT;
29781
+ const rawLadder = block["escalation"];
29782
+ const ladder = Array.isArray(rawLadder) && rawLadder.length > 0 && rawLadder.every((r) => typeof r === "string") ? rawLadder : ESCALATION_LADDER;
29783
+ return { fix_loop_max: max, escalation: ladder };
29784
+ }
29785
+ var ESCALATION_LADDER, FIX_LOOP_MAX_DEFAULT;
29786
+ var init_missionExecution = __esm({
29787
+ "src/shared/missionExecution.ts"() {
29788
+ "use strict";
29789
+ ESCALATION_LADDER = [
29790
+ "independent",
29791
+ "council",
29792
+ "team",
29793
+ "owner_owned_check"
29794
+ ];
29795
+ FIX_LOOP_MAX_DEFAULT = 10;
29796
+ }
29797
+ });
29798
+
29799
+ // src/scripts/_lib/forge_protection.ts
29800
+ function isActiveBranchRuleset(rs) {
29801
+ return rs.enforcement === "active" && rs.target === "branch";
29802
+ }
29803
+ function reachesDefaultBranch(rs, defaultBranch) {
29804
+ const include = rs.conditions?.ref_name?.include ?? [];
29805
+ return include.some(
29806
+ (p) => p === "~DEFAULT_BRANCH" || p === "~ALL" || p === `refs/heads/${defaultBranch}`
29807
+ );
29808
+ }
29809
+ function hasRule(rs, type) {
29810
+ return (rs.rules ?? []).some((r) => r.type === type);
29811
+ }
29812
+ function requiredContexts(rs) {
29813
+ for (const r of rs.rules ?? []) {
29814
+ if (r.type !== "required_status_checks") continue;
29815
+ const p = r.parameters;
29816
+ if (p === null || typeof p !== "object") continue;
29817
+ const list = p["required_status_checks"];
29818
+ if (!Array.isArray(list)) continue;
29819
+ return list.map(
29820
+ (e) => e !== null && typeof e === "object" ? e["context"] : null
29821
+ ).filter((c) => typeof c === "string");
29822
+ }
29823
+ return [];
29824
+ }
29825
+ function forgeProtectionRows(reading) {
29826
+ const rows = [];
29827
+ const rulesets = reading.rulesets;
29828
+ const branch = reading.defaultBranch;
29829
+ const covering = rulesets === null || branch === null ? null : rulesets.filter((rs) => isActiveBranchRuleset(rs) && reachesDefaultBranch(rs, branch));
29830
+ rows.push(
29831
+ covering === null ? {
29832
+ id: "default_branch_protected",
29833
+ state: "unread",
29834
+ source: SOURCE.rulesets,
29835
+ detail: "the rulesets were not queried"
29836
+ } : covering.length > 0 ? {
29837
+ id: "default_branch_protected",
29838
+ state: "satisfied",
29839
+ source: SOURCE.rulesets,
29840
+ detail: `${String(covering.length)} active branch ruleset(s) cover the default branch`
29841
+ } : {
29842
+ id: "default_branch_protected",
29843
+ state: "unsatisfied",
29844
+ source: SOURCE.rulesets,
29845
+ detail: "no active branch ruleset covers the default branch. NOTE: the classic branches/<b>/protection endpoint 404s on a ruleset-protected repository, so a 404 there is not evidence for this row."
29846
+ }
29847
+ );
29848
+ const contexts = covering === null ? null : covering.flatMap(requiredContexts);
29849
+ rows.push(
29850
+ contexts === null ? {
29851
+ id: "required_checks_present",
29852
+ state: "unread",
29853
+ source: SOURCE.rulesets,
29854
+ detail: "the rulesets were not queried"
29855
+ } : contexts.length > 0 ? {
29856
+ id: "required_checks_present",
29857
+ state: "satisfied",
29858
+ source: SOURCE.rulesets,
29859
+ detail: `${String(contexts.length)} required context(s): ${contexts.join(", ")}`
29860
+ } : {
29861
+ id: "required_checks_present",
29862
+ state: "unsatisfied",
29863
+ source: SOURCE.rulesets,
29864
+ detail: "no required status check context is configured"
29865
+ }
29866
+ );
29867
+ const noFastForward = covering === null ? null : covering.some((rs) => hasRule(rs, "non_fast_forward"));
29868
+ rows.push(
29869
+ noFastForward === null ? {
29870
+ id: "force_push_disabled",
29871
+ state: "unread",
29872
+ source: SOURCE.rulesets,
29873
+ detail: "the rulesets were not queried"
29874
+ } : {
29875
+ id: "force_push_disabled",
29876
+ state: noFastForward ? "satisfied" : "unsatisfied",
29877
+ source: SOURCE.rulesets,
29878
+ detail: noFastForward ? "a non_fast_forward rule is active on the default branch" : "no non_fast_forward rule covers the default branch"
29879
+ }
29880
+ );
29881
+ rows.push(
29882
+ reading.allowAutoMerge === null ? {
29883
+ id: "auto_merge_available",
29884
+ state: "unread",
29885
+ source: SOURCE.repo,
29886
+ detail: "the repository record was not queried"
29887
+ } : {
29888
+ id: "auto_merge_available",
29889
+ state: reading.allowAutoMerge ? "satisfied" : "unsatisfied",
29890
+ source: SOURCE.repo,
29891
+ detail: reading.allowAutoMerge ? "allow_auto_merge is enabled" : "allow_auto_merge is disabled \u2014 merge delivery cannot queue behind checks"
29892
+ }
29893
+ );
29894
+ rows.push(
29895
+ reading.deployRestricted === null ? {
29896
+ id: "deploy_via_pipeline_only",
29897
+ state: "unread",
29898
+ source: SOURCE.environments,
29899
+ detail: "the environments were not queried"
29900
+ } : {
29901
+ id: "deploy_via_pipeline_only",
29902
+ state: reading.deployRestricted ? "satisfied" : "unsatisfied",
29903
+ source: SOURCE.environments,
29904
+ detail: reading.deployRestricted ? "every environment restricts its deployment branches" : "at least one environment accepts a deployment from any branch"
29905
+ }
29906
+ );
29907
+ return rows;
29908
+ }
29909
+ function protectionActions(rows) {
29910
+ return rows.filter((r) => r.state !== "satisfied").map((r) => `${r.id}: ${r.state} \u2014 ${r.detail} (source: ${r.source})`);
29911
+ }
29912
+ var SOURCE;
29913
+ var init_forge_protection = __esm({
29914
+ "src/scripts/_lib/forge_protection.ts"() {
29915
+ "use strict";
29916
+ SOURCE = {
29917
+ rulesets: "GET repos/{owner}/{repo}/rulesets + GET .../rulesets/{id}",
29918
+ repo: "GET repos/{owner}/{repo} (allow_auto_merge)",
29919
+ environments: "GET repos/{owner}/{repo}/environments (deployment_branch_policy)"
29920
+ };
29921
+ }
29922
+ });
29923
+
29924
+ // src/scripts/_cli/doctor_execution.ts
29925
+ function executionJson(overrides) {
29926
+ let posture;
29927
+ try {
29928
+ posture = executionPostureFromOverrides(overrides());
29929
+ } catch {
29930
+ posture = resolveExecutionPosture({});
29931
+ }
29932
+ return {
29933
+ fix_loop_max: posture.fix_loop_max,
29934
+ escalation: [...posture.escalation]
29935
+ };
29936
+ }
29937
+ function forgeProtectionJson(reading) {
29938
+ const rows = forgeProtectionRows(reading);
29939
+ return {
29940
+ rows: rows.map((r) => ({
29941
+ id: r.id,
29942
+ state: r.state,
29943
+ source: r.source,
29944
+ detail: r.detail
29945
+ })),
29946
+ actions: protectionActions(rows),
29947
+ read_from_forge: rows.some((r) => r.state !== "unread")
29948
+ };
29949
+ }
29950
+ var UNREAD_FORGE;
29951
+ var init_doctor_execution = __esm({
29952
+ "src/scripts/_cli/doctor_execution.ts"() {
29953
+ "use strict";
29954
+ init_missionExecution();
29955
+ init_forge_protection();
29956
+ UNREAD_FORGE = {
29957
+ rulesets: null,
29958
+ defaultBranch: null,
29959
+ allowAutoMerge: null,
29960
+ deployRestricted: null
29961
+ };
29962
+ }
29963
+ });
29964
+
29723
29965
  // src/scripts/ai_council/cli_agency_bounds.ts
29724
29966
  function boundFor(member) {
29725
29967
  return AGENCY_BOUNDS.find((b) => b.member === member)?.bound ?? [];
@@ -32615,7 +32857,7 @@ function buildSecondModel(entry, cls, locked, d) {
32615
32857
  if (!("second_model" in entry)) return null;
32616
32858
  if (locked.has(cls)) {
32617
32859
  throw d.error(
32618
- `decision_resolution.classes.${cls}.second_model=${d.repr(entry["second_model"])}: a second-model rung is not configurable for high-impact / user-required decisions \u2014 those classes are LOCKED to \`user\` (Iron Law) and never resolve on a model of any kind.`
32860
+ `decision_resolution.classes.${cls}.second_model=${d.repr(entry["second_model"])}: a second-model rung is not configurable for an owner-routed class (high-impact / user-required on the impact axis; product-owned / business-owned / destructive-owned on the ownership axis) \u2014 those classes are LOCKED to \`user\` (Iron Law) and never resolve on a model of any kind.`
32619
32861
  );
32620
32862
  }
32621
32863
  const raw = entry["second_model"];
@@ -32639,6 +32881,60 @@ var init_fallback_config = __esm({
32639
32881
  }
32640
32882
  });
32641
32883
 
32884
+ // src/scripts/ai_council/ownership_classes.ts
32885
+ function allOwnerLocked(impactLocked) {
32886
+ return /* @__PURE__ */ new Set([...impactLocked, ...OWNER_LOCKED_CLASSES]);
32887
+ }
32888
+ function defaultModeFor(cls) {
32889
+ return DEFAULT_RESOLUTION_MODES[cls] ?? "agent";
32890
+ }
32891
+ function ownershipModeError(cls, mode, repr) {
32892
+ if (OWNER_LOCKED_CLASSES.has(cls) && mode !== "user") {
32893
+ return `decision_resolution.classes.${cls}.mode=${repr(mode)}: class \`${cls}\` is LOCKED to \`user\` (Iron Law) \u2014 product, business and destructive decisions are owner-owned and never resolve on a model.`;
32894
+ }
32895
+ if (NEVER_OWNER_CLASSES.has(cls) && mode === "user") {
32896
+ return `decision_resolution.classes.${cls}.mode=${repr(mode)}: class \`${cls}\` is never owner-routed (Iron Law) \u2014 spend exhaustion pauses and reports, it does not ask.`;
32897
+ }
32898
+ return null;
32899
+ }
32900
+ var OWNERSHIP_CLASSES, OWNER_LOCKED_CLASSES, NEVER_OWNER_CLASSES, DEFAULT_RESOLUTION_MODES;
32901
+ var init_ownership_classes = __esm({
32902
+ "src/scripts/ai_council/ownership_classes.ts"() {
32903
+ "use strict";
32904
+ OWNERSHIP_CLASSES = [
32905
+ "deterministic",
32906
+ "reversible-technical",
32907
+ "contested-technical",
32908
+ "critical-technical",
32909
+ "product-owned",
32910
+ "business-owned",
32911
+ "destructive-owned",
32912
+ "spend-exhaustion"
32913
+ ];
32914
+ OWNER_LOCKED_CLASSES = /* @__PURE__ */ new Set([
32915
+ "product-owned",
32916
+ "business-owned",
32917
+ "destructive-owned"
32918
+ ]);
32919
+ NEVER_OWNER_CLASSES = /* @__PURE__ */ new Set(["spend-exhaustion"]);
32920
+ DEFAULT_RESOLUTION_MODES = {
32921
+ trivial: "agent",
32922
+ low_impact: "agent",
32923
+ medium_impact: "council",
32924
+ high_impact: "user",
32925
+ user_required: "user",
32926
+ deterministic: "agent",
32927
+ "reversible-technical": "agent",
32928
+ "contested-technical": "council",
32929
+ "critical-technical": "council",
32930
+ "product-owned": "user",
32931
+ "business-owned": "user",
32932
+ "destructive-owned": "user",
32933
+ "spend-exhaustion": "agent"
32934
+ };
32935
+ }
32936
+ });
32937
+
32642
32938
  // src/scripts/ai_council/py_format.ts
32643
32939
  function _pyReprStr(s) {
32644
32940
  const hasSingle = s.includes("'");
@@ -33243,14 +33539,14 @@ function _build_decision_resolution(d) {
33243
33539
  );
33244
33540
  }
33245
33541
  const classes = /* @__PURE__ */ new Map();
33246
- for (const cls of _IMPACT_CLASSES) {
33542
+ for (const cls of [..._IMPACT_CLASSES, ...OWNERSHIP_CLASSES]) {
33247
33543
  const entry_raw = _orEmpty(classes_raw[cls] ?? null);
33248
33544
  if (!_isDict(entry_raw)) {
33249
33545
  throw new CouncilConfigError(
33250
33546
  `\`decision_resolution.classes.${cls}\` must be a mapping.`
33251
33547
  );
33252
33548
  }
33253
- const mode = _get(entry_raw, "mode", _DEFAULT_RESOLUTION_MODES[cls]);
33549
+ const mode = _get(entry_raw, "mode", defaultModeFor(cls));
33254
33550
  if (!(_isStr(mode) && _VALID_RESOLUTION_MODES.has(mode))) {
33255
33551
  throw new CouncilConfigError(
33256
33552
  `decision_resolution.classes.${cls}.mode=${_pyRepr6(mode)} not in ${_sortedListRepr(_VALID_RESOLUTION_MODES)}.`
@@ -33261,7 +33557,9 @@ function _build_decision_resolution(d) {
33261
33557
  `decision_resolution.classes.${cls}.mode=${_pyRepr6(mode)}: class \`${cls}\` is LOCKED to \`user\` (Iron Law) \u2014 high-impact and user-required decisions never bypass the user.`
33262
33558
  );
33263
33559
  }
33264
- if (_LOCKED_IMPACT_CLASSES.has(cls) && "dispatch" in entry_raw) {
33560
+ const ownErr = ownershipModeError(cls, mode, _pyRepr6);
33561
+ if (ownErr !== null) throw new CouncilConfigError(ownErr);
33562
+ if (_ALL_OWNER_LOCKED.has(cls) && "dispatch" in entry_raw) {
33265
33563
  throw new CouncilConfigError(
33266
33564
  `decision_resolution.classes.${cls}.dispatch=${_pyRepr6(entry_raw.dispatch)}: dispatch is not configurable for high-impact / user-required decisions \u2014 always full council.`
33267
33565
  );
@@ -33275,7 +33573,7 @@ function _build_decision_resolution(d) {
33275
33573
  const second_model = buildSecondModel(
33276
33574
  entry_raw,
33277
33575
  cls,
33278
- _LOCKED_IMPACT_CLASSES,
33576
+ _ALL_OWNER_LOCKED,
33279
33577
  _FALLBACK_DEPS
33280
33578
  );
33281
33579
  classes.set(cls, { mode, confidence_threshold: threshold, second_model });
@@ -33967,7 +34265,7 @@ function _pyTruthy3(value) {
33967
34265
  }
33968
34266
  return Object.keys(value).length > 0;
33969
34267
  }
33970
- var import_yaml6, _VALID_PROVIDERS, _FALLBACK_DEPS, _RAW_KEY_PREFIXES, CouncilConfigError, _VALID_NECESSITY_MODES, _VALID_DISCLOSURE_MODES, _VALID_CHAIRMAN_MODES, COUNCIL_CONFIG_RELNAME, COUNCIL_CONFIG_USER_GLOBAL_REL, COUNCIL_CONFIG_ENV, _VALID_CRITIC_PROTOCOLS, _VALID_RESOLUTION_MODES, _IMPACT_CLASSES, _LOCKED_IMPACT_CLASSES, _DEFAULT_RESOLUTION_MODES, _VALID_MEMBER_MODES, _VALID_DISPATCH_MODES, DEFAULT_CLI_CALLS_PER_DAY2;
34268
+ var import_yaml6, _VALID_PROVIDERS, _FALLBACK_DEPS, _RAW_KEY_PREFIXES, CouncilConfigError, _VALID_NECESSITY_MODES, _VALID_DISCLOSURE_MODES, _VALID_CHAIRMAN_MODES, COUNCIL_CONFIG_RELNAME, COUNCIL_CONFIG_USER_GLOBAL_REL, COUNCIL_CONFIG_ENV, _VALID_CRITIC_PROTOCOLS, _VALID_RESOLUTION_MODES, _IMPACT_CLASSES, _LOCKED_IMPACT_CLASSES, _ALL_OWNER_LOCKED, _VALID_MEMBER_MODES, _VALID_DISPATCH_MODES, DEFAULT_CLI_CALLS_PER_DAY2;
33971
34269
  var init_config = __esm({
33972
34270
  "src/scripts/ai_council/config.ts"() {
33973
34271
  "use strict";
@@ -33978,6 +34276,7 @@ var init_config = __esm({
33978
34276
  init_seat_policy();
33979
34277
  init_quorum();
33980
34278
  init_fallback_config();
34279
+ init_ownership_classes();
33981
34280
  init_py_format();
33982
34281
  _VALID_PROVIDERS = /* @__PURE__ */ new Set([
33983
34282
  "anthropic",
@@ -34042,13 +34341,7 @@ var init_config = __esm({
34042
34341
  "high_impact",
34043
34342
  "user_required"
34044
34343
  ]);
34045
- _DEFAULT_RESOLUTION_MODES = {
34046
- trivial: "agent",
34047
- low_impact: "agent",
34048
- medium_impact: "council",
34049
- high_impact: "user",
34050
- user_required: "user"
34051
- };
34344
+ _ALL_OWNER_LOCKED = allOwnerLocked(_LOCKED_IMPACT_CLASSES);
34052
34345
  _VALID_MEMBER_MODES = /* @__PURE__ */ new Set(["cli", "api"]);
34053
34346
  _VALID_DISPATCH_MODES = /* @__PURE__ */ new Set(["full", "single"]);
34054
34347
  DEFAULT_CLI_CALLS_PER_DAY2 = DEFAULT_CLI_CALLS_PER_DAY;
@@ -37990,9 +38283,9 @@ function _emit_json(project_root, missing, modified, foreign, tag_drift, checks
37990
38283
  foreign,
37991
38284
  tag_drift
37992
38285
  };
37993
- if (origin !== null) {
37994
- payload["project_root_origin"] = origin;
37995
- }
38286
+ if (origin !== null) payload["project_root_origin"] = origin;
38287
+ payload["execution"] = executionJson(() => iter_setting_overrides({ cwd: project_root }));
38288
+ payload["forge_protection"] = forgeProtectionJson(UNREAD_FORGE);
37996
38289
  if (checks !== null) {
37997
38290
  payload["checks"] = checks;
37998
38291
  const drift = missing.length + modified.length + foreign.length + tag_drift.length;
@@ -38353,6 +38646,7 @@ var init_cmd_doctor = __esm({
38353
38646
  init_git_common_dir();
38354
38647
  init_sync_gitattributes();
38355
38648
  init_agent_settings();
38649
+ init_doctor_execution();
38356
38650
  init_clients();
38357
38651
  init_config();
38358
38652
  init_environment_detector();
@@ -42844,7 +43138,28 @@ var init_turn_end_gate_hook = __esm({
42844
43138
  }
42845
43139
  });
42846
43140
 
43141
+ // src/scripts/_lib/test_delta.ts
43142
+ function isCodePath(p) {
43143
+ const f = p.replace(/\\/g, "/");
43144
+ if (isTestPath(f)) return false;
43145
+ if (!/\.(ts|tsx|js|mjs|cjs)$/.test(f)) return false;
43146
+ if (f.endsWith(".d.ts")) return false;
43147
+ if (/^(dist|\.augment|\.claude|\.cursor|node_modules)\//.test(f)) return false;
43148
+ return /^(src|scripts)\//.test(f);
43149
+ }
43150
+ function isTestPath(p) {
43151
+ const f = p.replace(/\\/g, "/");
43152
+ if (/^tests\//.test(f)) return true;
43153
+ return /\.(test|spec)\.(ts|tsx|js|mjs|cjs)$/.test(f);
43154
+ }
43155
+ var init_test_delta = __esm({
43156
+ "src/scripts/_lib/test_delta.ts"() {
43157
+ "use strict";
43158
+ }
43159
+ });
43160
+
42847
43161
  // src/scripts/hooks/evidence_independence.ts
43162
+ import { spawnSync as spawnSync15 } from "node:child_process";
42848
43163
  import crypto10 from "node:crypto";
42849
43164
  import fs86 from "node:fs";
42850
43165
  import path87 from "node:path";
@@ -42942,6 +43257,31 @@ function decide(tool, prompt, priorEvaluations) {
42942
43257
  evaluations: priorEvaluations + 1
42943
43258
  };
42944
43259
  }
43260
+ function sameSessionTestFlag(command) {
43261
+ if (command === null || !/\bgit\b[^|;&]*\bcommit\b/.test(command)) return null;
43262
+ return SAME_SESSION_TEXT;
43263
+ }
43264
+ function touchesTestAndCode(paths) {
43265
+ return paths.some(isTestPath) && paths.some(isCodePath);
43266
+ }
43267
+ function _commandOf(envelope) {
43268
+ const payload = _isObject6(envelope["payload"]) ? envelope["payload"] : envelope;
43269
+ const input = _isObject6(payload["tool_input"]) ? payload["tool_input"] : payload;
43270
+ for (const key of ["command", "cmd", "shell_command"]) {
43271
+ const v = input[key];
43272
+ if (typeof v === "string" && v !== "") return v;
43273
+ }
43274
+ return null;
43275
+ }
43276
+ function _stagedPaths(consumer_root) {
43277
+ const r = spawnSync15("git", ["diff", "--cached", "--name-only"], {
43278
+ cwd: consumer_root,
43279
+ encoding: "utf8"
43280
+ });
43281
+ if (r.status !== 0) return null;
43282
+ const out = r.stdout.split("\n").map((s) => s.trim()).filter((s) => s !== "");
43283
+ return out.length === 0 ? null : out;
43284
+ }
42945
43285
  function run4(stdin_text, options) {
42946
43286
  let envelope = {};
42947
43287
  if (stdin_text.trim()) {
@@ -42964,6 +43304,15 @@ function run4(stdin_text, options) {
42964
43304
  state.evaluations = [];
42965
43305
  }
42966
43306
  const [tool, prompt] = extractDispatch(envelope);
43307
+ const flag2 = sameSessionTestFlag(_commandOf(envelope));
43308
+ if (flag2 !== null) {
43309
+ const staged = _stagedPaths(options.consumer_root);
43310
+ if (staged !== null && touchesTestAndCode(staged)) {
43311
+ process.stdout.write(`${JSON.stringify({ decision: "warn", reason: flag2 })}
43312
+ `);
43313
+ return EXIT_ALLOW5;
43314
+ }
43315
+ }
42967
43316
  const decision = decide(tool, prompt, state.evaluations.length);
42968
43317
  if (decision.evaluations > state.evaluations.length) {
42969
43318
  state.evaluations.push({
@@ -43025,12 +43374,13 @@ function _isCliEntry23() {
43025
43374
  return false;
43026
43375
  }
43027
43376
  }
43028
- var EXIT_ALLOW5, EXIT_BLOCK2, STATE_FILE4, DISPATCH_TOOLS, EVALUATION_RE, PRELOADED_VERDICT_RE, SELF_SCOPE_RE, WARN_TEXT;
43377
+ var EXIT_ALLOW5, EXIT_BLOCK2, STATE_FILE4, DISPATCH_TOOLS, EVALUATION_RE, PRELOADED_VERDICT_RE, SELF_SCOPE_RE, WARN_TEXT, SAME_SESSION_TEXT;
43029
43378
  var init_evidence_independence = __esm({
43030
43379
  "src/scripts/hooks/evidence_independence.ts"() {
43031
43380
  "use strict";
43032
43381
  init_state_io();
43033
43382
  init_hook_stdin();
43383
+ init_test_delta();
43034
43384
  EXIT_ALLOW5 = 0;
43035
43385
  EXIT_BLOCK2 = 1;
43036
43386
  STATE_FILE4 = path87.join("agents", "state", "evidence-dispatch.json");
@@ -43066,6 +43416,7 @@ var init_evidence_independence = __esm({
43066
43416
  ];
43067
43417
  SELF_SCOPE_RE = /\b(my (work|change|diff|implementation|code|fix|patch|branch|pr)|this (diff|change|pr|delta|implementation|patch)|the delta|the change i|what i (wrote|built|changed|implemented)|i just (wrote|built|changed|implemented))\b/i;
43068
43418
  WARN_TEXT = "First evaluation dispatch this turn. Two shapes fabricated a binding honest-null in the audited sessions \u2014 check your prompt for both before it goes out: (1) a verdict pre-loaded into the prompt, and (2) a scope narrowed to files you chose. A review you commissioned on your own work is admissible as gate evidence only when the prompt is recorded alongside the verdict.";
43419
+ SAME_SESSION_TEXT = "This commit stages both a test and code it could cover \u2014 the shape L0 takes in a diff, where the implementer authored the evaluator. This check reads the staged set only: it cannot tell who wrote the test, so it is a prompt to STATE the level, not a finding that you are at L0. L0 is a permitted FALLBACK, not the default: where a second session, a second model or a second provider was available, the test should have come from one of them. Say which in the commit or the PR body \u2014 a diff looks identical either way. See evaluator-independence \xA7 Tests are evaluators.";
43069
43420
  if (_isCliEntry23()) {
43070
43421
  process.exit(main31());
43071
43422
  }
@@ -45459,6 +45810,7 @@ __export(cmd_conformance_exports, {
45459
45810
  _check_lean_projection: () => _check_lean_projection,
45460
45811
  _check_router_pointers: () => _check_router_pointers,
45461
45812
  _check_txlog_clean: () => _check_txlog_clean,
45813
+ _installLogExpected: () => _installLogExpected,
45462
45814
  _parse: () => _parse4,
45463
45815
  appendConformanceReport: () => appendConformanceReport,
45464
45816
  conformanceLogPath: () => conformanceLogPath,
@@ -45472,7 +45824,7 @@ import * as fs93 from "node:fs";
45472
45824
  import * as os22 from "node:os";
45473
45825
  import * as path94 from "node:path";
45474
45826
  import process23 from "node:process";
45475
- import { spawnSync as spawnSync15 } from "node:child_process";
45827
+ import { spawnSync as spawnSync16 } from "node:child_process";
45476
45828
  import { fileURLToPath as fileURLToPath50, pathToFileURL as pathToFileURL35 } from "node:url";
45477
45829
  function print3(s = "") {
45478
45830
  process23.stdout.write(`${s}
@@ -45496,21 +45848,24 @@ function installLogPath() {
45496
45848
  }
45497
45849
  return path94.join(os22.homedir(), ".event4u", "agent-config", "install-log.jsonl");
45498
45850
  }
45499
- function _check_txlog_clean(logPath = installLogPath()) {
45500
- if (!fs93.existsSync(logPath)) {
45501
- return {
45502
- id: "txlog-clean",
45503
- status: "ok",
45504
- message: "no install transaction log \u2014 nothing to recover",
45505
- remedy: ""
45506
- };
45507
- }
45508
- const entries = readRecentEntries(logPath);
45851
+ function _installLogExpected(projectRoot) {
45852
+ return fs93.existsSync(manifest_path(projectRoot));
45853
+ }
45854
+ function _check_txlog_clean(logPath = installLogPath(), projectRoot = null) {
45855
+ const entries = fs93.existsSync(logPath) ? readRecentEntries(logPath) : [];
45509
45856
  if (entries.length === 0) {
45857
+ if (projectRoot !== null && _installLogExpected(projectRoot)) {
45858
+ return {
45859
+ id: "txlog-clean",
45860
+ status: "unknown",
45861
+ message: "install manifest present, no usable install transaction log \u2014 nothing recorded this install, so the last run cannot be confirmed complete",
45862
+ remedy: "no install path writes this log today; run `agent-config doctor` for the drift answer this check cannot give"
45863
+ };
45864
+ }
45510
45865
  return {
45511
45866
  id: "txlog-clean",
45512
45867
  status: "ok",
45513
- message: "install transaction log is empty",
45868
+ message: "no usable install transaction log and no install manifest \u2014 nothing was installed here",
45514
45869
  remedy: ""
45515
45870
  };
45516
45871
  }
@@ -45520,7 +45875,7 @@ function _check_txlog_clean(logPath = installLogPath()) {
45520
45875
  id: "txlog-clean",
45521
45876
  status: "fail",
45522
45877
  message: `install log tail is an abandoned run (abort at ${last.ts}${last.note ? `: ${last.note}` : ""})`,
45523
- remedy: "re-run `agent-config init` (recovery reverse-applies the aborted tail)"
45878
+ remedy: "re-run `agent-config init` \u2014 it re-applies the plan over the partial tail; the aborted run's writes stay on disk and are replaced only where the plan covers them"
45524
45879
  };
45525
45880
  }
45526
45881
  return {
@@ -45629,7 +45984,7 @@ function _check_hook_dispatcher(projectRoot, packageRoot = PACKAGE_ROOT2, opts =
45629
45984
  ...event === "stop" ? { stop_reason: "conformance-smoke" } : { source: "startup" }
45630
45985
  });
45631
45986
  const argv = [...runner, "--platform", platform, "--event", event];
45632
- const proc = spawnSync15(argv[0], argv.slice(1), {
45987
+ const proc = spawnSync16(argv[0], argv.slice(1), {
45633
45988
  input: payload,
45634
45989
  cwd: projectRoot,
45635
45990
  encoding: "utf8",
@@ -45791,7 +46146,7 @@ function runConformanceChecks(opts = {}) {
45791
46146
  const projectRoot = opts.projectRoot ?? process23.cwd();
45792
46147
  const packageRoot = opts.packageRoot ?? PACKAGE_ROOT2;
45793
46148
  const checks = [];
45794
- checks.push(_check_txlog_clean());
46149
+ checks.push(_check_txlog_clean(installLogPath(), projectRoot));
45795
46150
  checks.push(_check_router_pointers(packageRoot));
45796
46151
  if (opts.skipDispatcher === true) {
45797
46152
  checks.push({
@@ -45914,7 +46269,7 @@ function main38(argv = null) {
45914
46269
  print3(` \u{1F4CD} project_root: ${project_root}`);
45915
46270
  print3("conformance:");
45916
46271
  for (const c of allChecks) {
45917
- const sym = STATUS_SYMBOLS[c["status"]] ?? "?";
46272
+ const sym = CONFORMANCE_STATUS_SYMBOLS[c["status"]] ?? "?";
45918
46273
  print3(` ${sym} ${c["id"]}: ${c["message"]}`);
45919
46274
  if (c["status"] !== "ok" && c["remedy"]) {
45920
46275
  print3(` fix: ${c["remedy"]}`);
@@ -45946,7 +46301,7 @@ function _isCliEntry29() {
45946
46301
  return false;
45947
46302
  }
45948
46303
  }
45949
- var YAML7, _HERE26, PACKAGE_ROOT2, CONFORMANCE_CHECK_IDS, THIN_STUB_MARKER, USAGE5;
46304
+ var YAML7, _HERE26, PACKAGE_ROOT2, CONFORMANCE_CHECK_IDS, THIN_STUB_MARKER, CONFORMANCE_STATUS_SYMBOLS, USAGE5;
45950
46305
  var init_cmd_conformance = __esm({
45951
46306
  "src/scripts/_cli/cmd_conformance.ts"() {
45952
46307
  "use strict";
@@ -45969,6 +46324,10 @@ var init_cmd_conformance = __esm({
45969
46324
  "host-manifest"
45970
46325
  ];
45971
46326
  THIN_STUB_MARKER = "Routed rule \u2014 load the body on trigger-match";
46327
+ CONFORMANCE_STATUS_SYMBOLS = {
46328
+ ...STATUS_SYMBOLS,
46329
+ unknown: "\u2754"
46330
+ };
45972
46331
  USAGE5 = "usage: agent-config conformance [-h] [--project PROJECT] [--json]\n [--skip-dispatcher] [--funnel]\n";
45973
46332
  if (_isCliEntry29() || process23.argv[1] === _HERE26) {
45974
46333
  try {
@@ -50040,7 +50399,7 @@ function grantFile(repoRoot, runId) {
50040
50399
  }
50041
50400
  function issueBillingGrant(repoRoot, runId, now = () => /* @__PURE__ */ new Date()) {
50042
50401
  const file = grantFile(repoRoot, runId);
50043
- const existing = _read(file);
50402
+ const existing = _read2(file);
50044
50403
  if (existing !== null && existing.run_id === runId) return existing;
50045
50404
  const grant = { run_id: runId, issued_at: now().toISOString() };
50046
50405
  fs100.mkdirSync(path98.dirname(file), { recursive: true });
@@ -50050,7 +50409,7 @@ function issueBillingGrant(repoRoot, runId, now = () => /* @__PURE__ */ new Date
50050
50409
  }
50051
50410
  function isBillingGrantActive(repoRoot, runId, env = process.env, now = () => /* @__PURE__ */ new Date()) {
50052
50411
  if ((env[BILLING_GRANT_ENV] ?? "").trim() !== runId) return false;
50053
- const grant = _read(grantFile(repoRoot, runId));
50412
+ const grant = _read2(grantFile(repoRoot, runId));
50054
50413
  if (grant === null || grant.run_id !== runId) return false;
50055
50414
  const age = now().getTime() - Date.parse(grant.issued_at);
50056
50415
  return Number.isFinite(age) && age >= 0 && age <= BILLING_GRANT_MAX_AGE_MS;
@@ -50066,7 +50425,7 @@ function revokeBillingGrant(repoRoot, runId) {
50066
50425
  } catch {
50067
50426
  }
50068
50427
  }
50069
- function _read(file) {
50428
+ function _read2(file) {
50070
50429
  try {
50071
50430
  const raw = JSON.parse(fs100.readFileSync(file, "utf8"));
50072
50431
  if (raw === null || typeof raw !== "object") return null;