@aragon-agent/cli 0.6.43 → 0.6.45

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 (251) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +69 -2
  3. package/dist/agent/controller.d.ts +69 -0
  4. package/dist/agent/controller.js +224 -11
  5. package/dist/agent/governance-view.d.ts +40 -0
  6. package/dist/agent/governance-view.js +40 -0
  7. package/dist/agent/governance-wiring.d.ts +162 -0
  8. package/dist/agent/governance-wiring.js +470 -0
  9. package/dist/agent/plan-prompt.d.ts +7 -0
  10. package/dist/agent/plan-prompt.js +2 -1
  11. package/dist/agent/reducer.d.ts +33 -1
  12. package/dist/agent/reducer.js +45 -9
  13. package/dist/agent/system-prompt.d.ts +19 -0
  14. package/dist/agent/system-prompt.js +9 -1
  15. package/dist/cli.js +45 -1
  16. package/dist/commands/builtins.js +10 -4
  17. package/dist/commands/governance-command.d.ts +35 -0
  18. package/dist/commands/governance-command.js +292 -0
  19. package/dist/commands/governance-runs-table.d.ts +40 -0
  20. package/dist/commands/governance-runs-table.js +130 -0
  21. package/dist/commands/registry.d.ts +12 -0
  22. package/dist/config/app-paths.d.ts +10 -0
  23. package/dist/config/app-paths.js +12 -0
  24. package/dist/config/cli-commands.d.ts +18 -0
  25. package/dist/config/cli-commands.js +47 -1
  26. package/dist/config/env.d.ts +2 -1
  27. package/dist/config/env.js +10 -1
  28. package/dist/config/governance-config.d.ts +125 -0
  29. package/dist/config/governance-config.js +164 -0
  30. package/dist/config/governance-launch.d.ts +71 -0
  31. package/dist/config/governance-launch.js +58 -0
  32. package/dist/config/load.d.ts +15 -0
  33. package/dist/config/load.js +26 -1
  34. package/dist/config/model-profile-store.d.ts +4 -2
  35. package/dist/config/schema.d.ts +22 -0
  36. package/dist/config/schema.js +6 -0
  37. package/dist/config/store.js +14 -1
  38. package/dist/config/ui-state.d.ts +11 -0
  39. package/dist/config/ui-state.js +11 -0
  40. package/dist/diagnostics/doctor.js +20 -0
  41. package/dist/governance/card-normalize.d.ts +24 -0
  42. package/dist/governance/card-normalize.js +76 -0
  43. package/dist/governance/copy.d.ts +109 -0
  44. package/dist/governance/copy.js +223 -0
  45. package/dist/governance/engine/aftermath.d.ts +49 -0
  46. package/dist/governance/engine/aftermath.js +134 -0
  47. package/dist/governance/engine/artifact-persist.d.ts +35 -0
  48. package/dist/governance/engine/artifact-persist.js +86 -0
  49. package/dist/governance/engine/budget.d.ts +52 -0
  50. package/dist/governance/engine/budget.js +112 -0
  51. package/dist/governance/engine/cards.d.ts +18 -0
  52. package/dist/governance/engine/cards.js +186 -0
  53. package/dist/governance/engine/digest.d.ts +32 -0
  54. package/dist/governance/engine/digest.js +63 -0
  55. package/dist/governance/engine/engine-core.d.ts +219 -0
  56. package/dist/governance/engine/engine-core.js +562 -0
  57. package/dist/governance/engine/engine.d.ts +68 -0
  58. package/dist/governance/engine/engine.js +314 -0
  59. package/dist/governance/engine/estimate.d.ts +38 -0
  60. package/dist/governance/engine/estimate.js +46 -0
  61. package/dist/governance/engine/inspector.d.ts +16 -0
  62. package/dist/governance/engine/inspector.js +396 -0
  63. package/dist/governance/engine/integration.d.ts +35 -0
  64. package/dist/governance/engine/integration.js +220 -0
  65. package/dist/governance/engine/lifecycle.d.ts +29 -0
  66. package/dist/governance/engine/lifecycle.js +656 -0
  67. package/dist/governance/engine/pause.d.ts +56 -0
  68. package/dist/governance/engine/pause.js +107 -0
  69. package/dist/governance/engine/phase-members.d.ts +15 -0
  70. package/dist/governance/engine/phase-members.js +34 -0
  71. package/dist/governance/engine/phase-planner.d.ts +53 -0
  72. package/dist/governance/engine/phase-planner.js +282 -0
  73. package/dist/governance/engine/rebuild.d.ts +27 -0
  74. package/dist/governance/engine/rebuild.js +57 -0
  75. package/dist/governance/engine/report.d.ts +66 -0
  76. package/dist/governance/engine/report.js +220 -0
  77. package/dist/governance/engine/run-digest.d.ts +20 -0
  78. package/dist/governance/engine/run-digest.js +42 -0
  79. package/dist/governance/engine/spec-builder.d.ts +117 -0
  80. package/dist/governance/engine/spec-builder.js +321 -0
  81. package/dist/governance/engine/stage-runner.d.ts +22 -0
  82. package/dist/governance/engine/stage-runner.js +664 -0
  83. package/dist/governance/engine/start-input.d.ts +19 -0
  84. package/dist/governance/engine/start-input.js +111 -0
  85. package/dist/governance/engine/state-machine.d.ts +101 -0
  86. package/dist/governance/engine/state-machine.js +586 -0
  87. package/dist/governance/engine/submission-queries.d.ts +42 -0
  88. package/dist/governance/engine/submission-queries.js +97 -0
  89. package/dist/governance/engine/submission-render.d.ts +12 -0
  90. package/dist/governance/engine/submission-render.js +92 -0
  91. package/dist/governance/engine/submissions.d.ts +27 -0
  92. package/dist/governance/engine/submissions.js +455 -0
  93. package/dist/governance/engine/visibility.d.ts +104 -0
  94. package/dist/governance/engine/visibility.js +223 -0
  95. package/dist/governance/governed-dispatch.d.ts +19 -0
  96. package/dist/governance/governed-dispatch.js +17 -0
  97. package/dist/governance/limits.d.ts +107 -0
  98. package/dist/governance/limits.js +131 -0
  99. package/dist/governance/posture-transition.d.ts +38 -0
  100. package/dist/governance/posture-transition.js +44 -0
  101. package/dist/governance/posture.d.ts +35 -0
  102. package/dist/governance/posture.js +59 -0
  103. package/dist/governance/profiles.d.ts +48 -0
  104. package/dist/governance/profiles.js +140 -0
  105. package/dist/governance/prompts/orchestrator-block.d.ts +40 -0
  106. package/dist/governance/prompts/orchestrator-block.js +128 -0
  107. package/dist/governance/prompts/plan-addendum.d.ts +22 -0
  108. package/dist/governance/prompts/plan-addendum.js +60 -0
  109. package/dist/governance/prompts/refusals.d.ts +48 -0
  110. package/dist/governance/prompts/refusals.js +82 -0
  111. package/dist/governance/prompts/role-blocks.d.ts +40 -0
  112. package/dist/governance/prompts/role-blocks.js +255 -0
  113. package/dist/governance/report-reader.d.ts +31 -0
  114. package/dist/governance/report-reader.js +57 -0
  115. package/dist/governance/roles.d.ts +83 -0
  116. package/dist/governance/roles.js +142 -0
  117. package/dist/governance/rules/claims.d.ts +83 -0
  118. package/dist/governance/rules/claims.js +250 -0
  119. package/dist/governance/rules/elimination.d.ts +66 -0
  120. package/dist/governance/rules/elimination.js +105 -0
  121. package/dist/governance/rules/events-table.d.ts +46 -0
  122. package/dist/governance/rules/events-table.js +94 -0
  123. package/dist/governance/rules/failure-analysis.d.ts +28 -0
  124. package/dist/governance/rules/failure-analysis.js +93 -0
  125. package/dist/governance/rules/ledger-replay.d.ts +53 -0
  126. package/dist/governance/rules/ledger-replay.js +53 -0
  127. package/dist/governance/rules/ledger-state.d.ts +85 -0
  128. package/dist/governance/rules/ledger-state.js +175 -0
  129. package/dist/governance/rules/ledger.d.ts +228 -0
  130. package/dist/governance/rules/ledger.js +560 -0
  131. package/dist/governance/rules/rca.d.ts +68 -0
  132. package/dist/governance/rules/rca.js +220 -0
  133. package/dist/governance/rules/settlement.d.ts +129 -0
  134. package/dist/governance/rules/settlement.js +363 -0
  135. package/dist/governance/rules/suspicion.d.ts +66 -0
  136. package/dist/governance/rules/suspicion.js +169 -0
  137. package/dist/governance/store/artifacts.d.ts +81 -0
  138. package/dist/governance/store/artifacts.js +173 -0
  139. package/dist/governance/store/atomic.d.ts +79 -0
  140. package/dist/governance/store/atomic.js +119 -0
  141. package/dist/governance/store/events-log.d.ts +35 -0
  142. package/dist/governance/store/events-log.js +86 -0
  143. package/dist/governance/store/run-lock.d.ts +51 -0
  144. package/dist/governance/store/run-lock.js +122 -0
  145. package/dist/governance/store/run-store.d.ts +229 -0
  146. package/dist/governance/store/run-store.js +644 -0
  147. package/dist/governance/store/scoreboard-export.d.ts +53 -0
  148. package/dist/governance/store/scoreboard-export.js +65 -0
  149. package/dist/governance/tools/child-tools.d.ts +31 -0
  150. package/dist/governance/tools/child-tools.js +65 -0
  151. package/dist/governance/tools/guard.d.ts +71 -0
  152. package/dist/governance/tools/guard.js +194 -0
  153. package/dist/governance/tools/inspector-tools.d.ts +63 -0
  154. package/dist/governance/tools/inspector-tools.js +424 -0
  155. package/dist/governance/tools/lead-tools.d.ts +42 -0
  156. package/dist/governance/tools/lead-tools.js +226 -0
  157. package/dist/governance/tools/normalize-util.d.ts +101 -0
  158. package/dist/governance/tools/normalize-util.js +230 -0
  159. package/dist/governance/tools/scan-incomplete.d.ts +79 -0
  160. package/dist/governance/tools/scan-incomplete.js +486 -0
  161. package/dist/governance/tools/shared-tools.d.ts +44 -0
  162. package/dist/governance/tools/shared-tools.js +125 -0
  163. package/dist/governance/tools/submit-normalizers.d.ts +28 -0
  164. package/dist/governance/tools/submit-normalizers.js +474 -0
  165. package/dist/governance/tools/submit-tools.d.ts +26 -0
  166. package/dist/governance/tools/submit-tools.js +171 -0
  167. package/dist/governance/types.d.ts +661 -0
  168. package/dist/governance/types.js +27 -0
  169. package/dist/proc/kill-tree.d.ts +19 -1
  170. package/dist/proc/kill-tree.js +32 -5
  171. package/dist/proc/limits.d.ts +19 -0
  172. package/dist/proc/limits.js +19 -0
  173. package/dist/proc/supervisor.js +8 -1
  174. package/dist/session/validate-session.js +32 -1
  175. package/dist/team/runtime.d.ts +8 -0
  176. package/dist/team/runtime.js +9 -0
  177. package/dist/team/subagent.d.ts +23 -0
  178. package/dist/team/subagent.js +14 -3
  179. package/dist/team/types.d.ts +6 -0
  180. package/dist/tools/bounded-spawn.d.ts +56 -0
  181. package/dist/tools/bounded-spawn.js +76 -0
  182. package/dist/tools/index.d.ts +30 -7
  183. package/dist/tools/index.js +14 -0
  184. package/dist/tools/plan-tools.d.ts +14 -2
  185. package/dist/tools/plan-tools.js +5 -2
  186. package/dist/tools/search-tools.js +52 -44
  187. package/dist/ui/App.js +145 -25
  188. package/dist/ui/BottomStatusRow.js +1 -1
  189. package/dist/ui/Composer.d.ts +7 -1
  190. package/dist/ui/Composer.js +9 -6
  191. package/dist/ui/GovernancePanel.d.ts +50 -0
  192. package/dist/ui/GovernancePanel.js +77 -0
  193. package/dist/ui/GovernanceRun.d.ts +18 -0
  194. package/dist/ui/GovernanceRun.js +11 -0
  195. package/dist/ui/ScrollbackShell.d.ts +35 -7
  196. package/dist/ui/ScrollbackShell.js +1 -1
  197. package/dist/ui/StatusBar.d.ts +15 -2
  198. package/dist/ui/StatusBar.js +10 -4
  199. package/dist/ui/Transcript.js +3 -0
  200. package/dist/ui/entries/GovernanceCard.d.ts +30 -0
  201. package/dist/ui/entries/GovernanceCard.js +32 -0
  202. package/dist/ui/governance-copy.d.ts +69 -0
  203. package/dist/ui/governance-copy.js +104 -0
  204. package/dist/ui/governance-status.d.ts +145 -0
  205. package/dist/ui/governance-status.js +326 -0
  206. package/dist/ui/interaction-copy.d.ts +4 -0
  207. package/dist/ui/interaction-copy.js +5 -0
  208. package/dist/ui/interaction-hints.d.ts +17 -0
  209. package/dist/ui/interaction-hints.js +14 -2
  210. package/dist/ui/layout/governance-board.d.ts +121 -0
  211. package/dist/ui/layout/governance-board.js +382 -0
  212. package/dist/ui/layout/governance-card.d.ts +53 -0
  213. package/dist/ui/layout/governance-card.js +134 -0
  214. package/dist/ui/layout/governance-chip.d.ts +38 -0
  215. package/dist/ui/layout/governance-chip.js +64 -0
  216. package/dist/ui/layout/governance-panel.d.ts +85 -0
  217. package/dist/ui/layout/governance-panel.js +358 -0
  218. package/dist/ui/layout/governance-roster.d.ts +65 -0
  219. package/dist/ui/layout/governance-roster.js +275 -0
  220. package/dist/ui/layout/status-detail-layout.js +3 -3
  221. package/dist/ui/layout/status-layout.d.ts +5 -2
  222. package/dist/ui/layout/status-layout.js +10 -6
  223. package/dist/ui/layout/virtual-window.js +11 -0
  224. package/dist/ui/overlays/GovernanceBoardOverlay.d.ts +41 -0
  225. package/dist/ui/overlays/GovernanceBoardOverlay.js +76 -0
  226. package/dist/ui/overlays/GovernanceSettingsPage.d.ts +48 -0
  227. package/dist/ui/overlays/GovernanceSettingsPage.js +93 -0
  228. package/dist/ui/overlays/HelpOverlay.js +4 -3
  229. package/dist/ui/overlays/QuestionOverlay.d.ts +9 -1
  230. package/dist/ui/overlays/QuestionOverlay.js +4 -2
  231. package/dist/ui/overlays/SettingsScreen.d.ts +7 -0
  232. package/dist/ui/overlays/SettingsScreen.js +21 -1
  233. package/dist/ui/overlays/governance-settings.d.ts +79 -0
  234. package/dist/ui/overlays/governance-settings.js +140 -0
  235. package/dist/ui/overlays/model-profile-state.d.ts +6 -1
  236. package/dist/ui/overlays/model-profile-state.js +10 -0
  237. package/dist/ui/palettes.d.ts +17 -0
  238. package/dist/ui/palettes.js +9 -0
  239. package/dist/ui/scrollback/LiveTail.d.ts +3 -1
  240. package/dist/ui/scrollback/budget.d.ts +12 -6
  241. package/dist/ui/scrollback/budget.js +11 -4
  242. package/dist/ui/scrollback/live-preview.js +2 -0
  243. package/dist/ui/scrollback/settled-boundary.js +3 -0
  244. package/dist/ui/scrollback/tail-anchor.d.ts +5 -2
  245. package/dist/ui/scrollback/tail-anchor.js +3 -1
  246. package/dist/ui/shortcuts.js +2 -2
  247. package/dist/ui/theme.d.ts +7 -0
  248. package/dist/ui/theme.js +1 -0
  249. package/dist/ui/transcript-text.js +9 -0
  250. package/dist/ui/use-wheel-routing.js +3 -1
  251. package/package.json +2 -2
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The event catalogue - Appendix A of the design, 44 rows (governance-mode AC-15).
3
+ *
4
+ * ASCII ONLY (`governance/` is glyph-scanned).
5
+ *
6
+ * THIS TABLE IS THE GOLDEN SOURCE. `governance-ledger.test.ts` pins every row against
7
+ * the reference spec (`token-economy-rules.md` v2.0); a change here is a scoring-rule
8
+ * change, so it must be mirrored in the design document and the golden test in the same
9
+ * commit. Nothing else in the tree may hard-code a delta: settlement, RCA expansion and
10
+ * the inspector tool all look values up here, which is what keeps the engine's
11
+ * automatic events and the inspector's judgement events on ONE accounting path (I-G7).
12
+ *
13
+ * Settlement semantics (design 5.3 / RV-9):
14
+ * provisional (P) - positive; held in escrow until integration passes; clawback-able.
15
+ * confirmed (C) - positive; straight into `confirmed`; not clawback-able.
16
+ * immediate (I) - positive scores go straight into `confirmed` (same as C, but the
17
+ * reference spec calls the column "Immediate"); negative scores are
18
+ * deducted from `confirmed` at once.
19
+ */
20
+ export type EventRole = 'DEV' | 'REV' | 'TEST' | 'ALL';
21
+ export type Settlement = 'provisional' | 'confirmed' | 'immediate';
22
+ /**
23
+ * Who may book an event: E engine, A engine on a mechanical signature (appealable),
24
+ * K a claim ruled on by the inspector, S inspector judgement (evidence required),
25
+ * R inspector root-cause analysis expanded by the engine.
26
+ */
27
+ export type Bookkeeper = 'E' | 'A' | 'K' | 'S' | 'R';
28
+ export declare const EVENT_CODES: readonly ["D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15", "D16", "D17", "D18", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "T10", "C1", "C2", "C3", "C4"];
29
+ export type EventCode = (typeof EVENT_CODES)[number];
30
+ export interface EventDef {
31
+ code: EventCode;
32
+ role: EventRole;
33
+ /** The catalogue delta. C2 is -5 for everyone; the -2 relief is applied by RCA. */
34
+ delta: number;
35
+ settlement: Settlement;
36
+ bookers: readonly Bookkeeper[];
37
+ /** Short English title, ASCII. Used in ledger rows and the board. */
38
+ title: string;
39
+ }
40
+ export declare const EVENTS_TABLE: Readonly<Record<EventCode, EventDef>>;
41
+ export declare function isEventCode(value: unknown): value is EventCode;
42
+ export declare function eventDef(code: EventCode): EventDef;
43
+ /** True when the inspector may book this code through `ledger_apply` (judgement events). */
44
+ export declare function isInspectorBookable(code: EventCode): boolean;
45
+ /** The codes `ledger_apply` accepts, in catalogue order. Used in refusal texts. */
46
+ export declare function inspectorBookableCodes(): EventCode[];
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The event catalogue - Appendix A of the design, 44 rows (governance-mode AC-15).
3
+ *
4
+ * ASCII ONLY (`governance/` is glyph-scanned).
5
+ *
6
+ * THIS TABLE IS THE GOLDEN SOURCE. `governance-ledger.test.ts` pins every row against
7
+ * the reference spec (`token-economy-rules.md` v2.0); a change here is a scoring-rule
8
+ * change, so it must be mirrored in the design document and the golden test in the same
9
+ * commit. Nothing else in the tree may hard-code a delta: settlement, RCA expansion and
10
+ * the inspector tool all look values up here, which is what keeps the engine's
11
+ * automatic events and the inspector's judgement events on ONE accounting path (I-G7).
12
+ *
13
+ * Settlement semantics (design 5.3 / RV-9):
14
+ * provisional (P) - positive; held in escrow until integration passes; clawback-able.
15
+ * confirmed (C) - positive; straight into `confirmed`; not clawback-able.
16
+ * immediate (I) - positive scores go straight into `confirmed` (same as C, but the
17
+ * reference spec calls the column "Immediate"); negative scores are
18
+ * deducted from `confirmed` at once.
19
+ */
20
+ export const EVENT_CODES = [
21
+ 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14',
22
+ 'D15', 'D16', 'D17', 'D18',
23
+ 'R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', 'R9', 'R10', 'R11', 'R12',
24
+ 'T1', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'T8', 'T9', 'T10',
25
+ 'C1', 'C2', 'C3', 'C4',
26
+ ];
27
+ function def(code, role, delta, settlement, bookers, title) {
28
+ return { code, role, delta, settlement, bookers, title };
29
+ }
30
+ const ROWS = [
31
+ // --- Development D1-D18 ---
32
+ def('D1', 'DEV', 15, 'provisional', ['E'], 'review passed with no changes'),
33
+ def('D2', 'DEV', 5, 'provisional', ['E'], 'review passed with minor fixes'),
34
+ def('D3', 'DEV', 10, 'provisional', ['E'], 'all tests passed'),
35
+ def('D4', 'DEV', 5, 'provisional', ['E'], 'fully matches the specification'),
36
+ def('D5', 'DEV', -20, 'immediate', ['E'], 'code sent back for rework'),
37
+ def('D6', 'DEV', -40, 'immediate', ['S'], 'introduced a security vulnerability'),
38
+ def('D7', 'DEV', -25, 'immediate', ['E'], 'specification mismatch'),
39
+ def('D8', 'DEV', -30, 'immediate', ['E'], 'same problem rejected twice'),
40
+ def('D9', 'DEV', -20, 'immediate', ['E'], 'incomplete implementation'),
41
+ def('D10', 'DEV', 20, 'provisional', ['S'], 'proactive excellence'),
42
+ def('D11', 'DEV', -30, 'immediate', ['E'], 'skeleton submission'),
43
+ def('D12', 'DEV', 10, 'confirmed', ['E'], 'integration passed (own code clean)'),
44
+ def('D13', 'DEV', -25, 'immediate', ['R'], 'integration failure (root cause)'),
45
+ def('D14', 'DEV', -20, 'immediate', ['R', 'S'], 'contract violation (producer)'),
46
+ def('D15', 'DEV', -10, 'immediate', ['R', 'S'], 'contract violation (consumer unverified)'),
47
+ def('D16', 'DEV', 10, 'confirmed', ['S'], 'proactive contract verification'),
48
+ def('D17', 'DEV', -15, 'immediate', ['A', 'S'], 'scope narrowing'),
49
+ def('D18', 'DEV', 10, 'confirmed', ['S'], 'integration repair contribution'),
50
+ // --- Review R1-R12 ---
51
+ def('R1', 'REV', 10, 'provisional', ['E'], 'high quality review (no missed defects)'),
52
+ def('R2', 'REV', 10, 'immediate', ['E'], 'found a valid problem'),
53
+ def('R3', 'REV', 5, 'immediate', ['S'], 'efficient review'),
54
+ def('R4', 'REV', -15, 'immediate', ['K'], 'missed defect found by testing'),
55
+ def('R5', 'REV', -10, 'immediate', ['K', 'E'], 'false positive feedback'),
56
+ def('R6', 'REV', -5, 'immediate', ['S'], 'vague or unactionable feedback'),
57
+ def('R7', 'REV', -15, 'immediate', ['K'], 'did not flag an incomplete implementation'),
58
+ def('R8', 'REV', 5, 'immediate', ['S'], 'identified proactive excellence'),
59
+ def('R9', 'REV', -20, 'immediate', ['R'], 'missed integration compatibility'),
60
+ def('R10', 'REV', 10, 'confirmed', ['S'], 'performed contract verification'),
61
+ def('R11', 'REV', 5, 'confirmed', ['S'], 'cross-agent impact analysis'),
62
+ def('R12', 'REV', -10, 'immediate', ['A', 'S'], 'rubber-stamp integration check'),
63
+ // --- Testing T1-T10 ---
64
+ def('T1', 'TEST', 10, 'provisional', ['E'], 'full requirement traceability'),
65
+ def('T2', 'TEST', 10, 'immediate', ['K'], 'found a defect the review missed'),
66
+ def('T3', 'TEST', 5, 'immediate', ['S'], 'high quality test cases'),
67
+ def('T4', 'TEST', -15, 'immediate', ['R'], 'missed a defect found at integration'),
68
+ def('T5', 'TEST', -10, 'immediate', ['K', 'S'], 'false positive defect or claim'),
69
+ def('T6', 'TEST', -10, 'immediate', ['E'], 'incomplete requirement traceability'),
70
+ def('T7', 'TEST', 10, 'immediate', ['K'], 'found an incomplete implementation the review missed'),
71
+ def('T8', 'TEST', 10, 'confirmed', ['S'], 'wrote integration boundary tests'),
72
+ def('T9', 'TEST', 15, 'confirmed', ['S'], 'found an integration problem before integration'),
73
+ def('T10', 'TEST', -15, 'immediate', ['R'], 'did not test the integration boundary'),
74
+ // --- Collective C1-C4 (per active DEV/REV/TEST) ---
75
+ def('C1', 'ALL', 5, 'confirmed', ['E'], 'integration passed first time'),
76
+ def('C2', 'ALL', -5, 'immediate', ['E', 'R'], 'integration failed (first)'),
77
+ def('C3', 'ALL', -10, 'immediate', ['E'], 'repeated integration failure'),
78
+ def('C4', 'ALL', -15, 'immediate', ['R'], 'integration disaster (systemic)'),
79
+ ];
80
+ export const EVENTS_TABLE = Object.freeze(Object.fromEntries(ROWS.map((r) => [r.code, r])));
81
+ export function isEventCode(value) {
82
+ return typeof value === 'string' && Object.prototype.hasOwnProperty.call(EVENTS_TABLE, value);
83
+ }
84
+ export function eventDef(code) {
85
+ return EVENTS_TABLE[code];
86
+ }
87
+ /** True when the inspector may book this code through `ledger_apply` (judgement events). */
88
+ export function isInspectorBookable(code) {
89
+ return EVENTS_TABLE[code].bookers.includes('S');
90
+ }
91
+ /** The codes `ledger_apply` accepts, in catalogue order. Used in refusal texts. */
92
+ export function inspectorBookableCodes() {
93
+ return EVENT_CODES.filter(isInspectorBookable);
94
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * FailureAnalysis - what a terminated agent's successor is told (governance-mode 5.8).
3
+ *
4
+ * ASCII ONLY (`governance/` is glyph-scanned).
5
+ *
6
+ * DETERMINISTIC ON PURPOSE. The analysis is built from the agent's own ledger history and
7
+ * a fixed code -> advice table; no model is involved. That keeps a respawn reproducible
8
+ * from the event log alone (I-G2) and means the successor's brief cannot be steered by a
9
+ * hallucinated post-mortem.
10
+ *
11
+ * Lives in its own module (not `elimination.ts`) so `ledger.ts` can build the analysis at
12
+ * the moment of elimination without a circular import: `elimination.ts` imports the
13
+ * ledger, the ledger imports this file.
14
+ */
15
+ import type { AgentRecord, FailureAnalysis } from '../types.js';
16
+ import { type EventCode } from './events-table.js';
17
+ /** How many penalty events a successor is shown. */
18
+ export declare const FAILURE_ANALYSIS_TOP_PENALTIES = 5;
19
+ /**
20
+ * One English, ASCII advice line per NEGATIVE catalogue code. Keyed by code (not by
21
+ * array) so a missing entry is a compile error for the codes listed here and a test
22
+ * failure for any negative code added to the catalogue later.
23
+ */
24
+ export declare const AVOID_ADVICE: Readonly<Record<string, string>>;
25
+ /** Build the analysis handed to the successor of `agent`. Pure and deterministic. */
26
+ export declare function buildFailureAnalysis(agent: AgentRecord, reason: FailureAnalysis['reason']): FailureAnalysis;
27
+ /** Negative catalogue codes; the advice table must cover exactly these. */
28
+ export declare function negativeEventCodes(): EventCode[];
@@ -0,0 +1,93 @@
1
+ /**
2
+ * FailureAnalysis - what a terminated agent's successor is told (governance-mode 5.8).
3
+ *
4
+ * ASCII ONLY (`governance/` is glyph-scanned).
5
+ *
6
+ * DETERMINISTIC ON PURPOSE. The analysis is built from the agent's own ledger history and
7
+ * a fixed code -> advice table; no model is involved. That keeps a respawn reproducible
8
+ * from the event log alone (I-G2) and means the successor's brief cannot be steered by a
9
+ * hallucinated post-mortem.
10
+ *
11
+ * Lives in its own module (not `elimination.ts`) so `ledger.ts` can build the analysis at
12
+ * the moment of elimination without a circular import: `elimination.ts` imports the
13
+ * ledger, the ledger imports this file.
14
+ */
15
+ import { EVENTS_TABLE, isEventCode } from './events-table.js';
16
+ /** How many penalty events a successor is shown. */
17
+ export const FAILURE_ANALYSIS_TOP_PENALTIES = 5;
18
+ /**
19
+ * One English, ASCII advice line per NEGATIVE catalogue code. Keyed by code (not by
20
+ * array) so a missing entry is a compile error for the codes listed here and a test
21
+ * failure for any negative code added to the catalogue later.
22
+ */
23
+ export const AVOID_ADVICE = Object.freeze({
24
+ D5: 'Do not submit code that fails review; self-review against the checklist first.',
25
+ D6: 'Never introduce injection, unsafe deserialization or secret-handling flaws.',
26
+ D7: 'Implement every requirement in the spec; trace each acceptance item to code.',
27
+ D8: 'Do not resubmit work that repeats a finding that was already rejected.',
28
+ D9: 'Do not leave stubs, TODO bodies or placeholder returns in delivered code.',
29
+ D11: 'Never submit a skeleton; every function body must do real work.',
30
+ D13: 'Verify every cross-module call path before declaring the work package done.',
31
+ D14: 'Produce exactly what the documented contract promises; do not drift from it.',
32
+ D15: 'Check the producer side of every contract you consume before relying on it.',
33
+ D17: 'Declare and verify every shared interface; do not narrow the scope to avoid it.',
34
+ R4: 'Look for defects the tests will find: edge cases, error paths, boundary values.',
35
+ R5: 'Only flag problems that are real; verify each finding against the code.',
36
+ R6: 'Make each finding specific: file, issue and the exact change required.',
37
+ R7: 'Flag stubs and unfinished bodies explicitly instead of passing them.',
38
+ R9: 'Check cross-module compatibility against the contracts during every review.',
39
+ R12: 'Write a concrete integration assessment that cites contracts, files or signatures.',
40
+ T4: 'Test the defect classes that integration later exposes, not only the happy path.',
41
+ T5: 'Only report defects and claims you have reproduced or can evidence.',
42
+ T6: 'Verify every requirement in the traceability table; leave no row unverified.',
43
+ T10: 'Write tests for the module boundary and the contracts, not only internals.',
44
+ C2: 'Coordinate on interfaces early; an integration failure costs the whole team.',
45
+ C3: 'After a failed integration, fix the root cause at the boundary, not the symptom.',
46
+ C4: 'Own the integration boundary jointly; systemic failures hurt every role.',
47
+ });
48
+ /** Generic advice when the history holds no penalty to cite (e.g. a tail elimination). */
49
+ const GENERIC_ADVICE = {
50
+ depleted: 'Keep every submission complete and correct; repeated deductions ended the run.',
51
+ tail: 'Raise the quality of every submission; the lowest-ranked member of a role is replaced.',
52
+ clawback: 'Do not let unverified work reach integration; escrowed credit can be reclaimed.',
53
+ };
54
+ function isPenalty(entry) {
55
+ return entry.delta < 0 && isEventCode(entry.code);
56
+ }
57
+ /**
58
+ * Top penalty events of `agent`: most negative first; ties keep the earlier booking.
59
+ * Sorting on (delta, seq, index) makes the result independent of the sort algorithm.
60
+ */
61
+ function topPenaltiesOf(agent) {
62
+ const penalties = agent.history
63
+ .map((entry, index) => ({ entry, index }))
64
+ .filter((item) => isPenalty(item.entry));
65
+ penalties.sort((a, b) => a.entry.delta - b.entry.delta || a.entry.seq - b.entry.seq || a.index - b.index);
66
+ return penalties.slice(0, FAILURE_ANALYSIS_TOP_PENALTIES).map(({ entry }) => ({
67
+ code: entry.code,
68
+ delta: entry.delta,
69
+ reason: entry.reason,
70
+ }));
71
+ }
72
+ /** Advice lines for the cited codes, first-seen order, no duplicates. */
73
+ function adviceFor(codes) {
74
+ const lines = [];
75
+ for (const code of codes) {
76
+ const line = AVOID_ADVICE[code];
77
+ if (line !== undefined && !lines.includes(line))
78
+ lines.push(line);
79
+ }
80
+ return lines;
81
+ }
82
+ /** Build the analysis handed to the successor of `agent`. Pure and deterministic. */
83
+ export function buildFailureAnalysis(agent, reason) {
84
+ const topPenalties = topPenaltiesOf(agent);
85
+ const avoid = adviceFor(topPenalties.map((p) => p.code));
86
+ if (avoid.length === 0)
87
+ avoid.push(GENERIC_ADVICE[reason]);
88
+ return { agentId: agent.id, reason, topPenalties, avoid };
89
+ }
90
+ /** Negative catalogue codes; the advice table must cover exactly these. */
91
+ export function negativeEventCodes() {
92
+ return Object.keys(EVENTS_TABLE).filter((c) => EVENTS_TABLE[c].delta < 0);
93
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The ledger operation log and its replay (governance-mode 5.3 "crash-safe order", I-G2).
3
+ *
4
+ * ASCII ONLY (`governance/` is glyph-scanned).
5
+ *
6
+ * `events.jsonl` is the truth and `ledger.json` a checkpoint. After a crash the store
7
+ * rebuilds the ledger by folding the logged operations over the initial roster, which is
8
+ * only sound if every operation is a pure function of (state, operation). `applyOp` is that
9
+ * single dispatch point: the live engine and the replayer both call it, so there is no
10
+ * "replay variant" of any rule that could drift from the live one.
11
+ */
12
+ import type { LedgerState } from '../types.js';
13
+ import { type ClawbackRequest, type CollectiveSpec, type EliminateRequest, type LedgerEvent, type RespawnRequest, type ReverseRequest, type RosterSpec } from './ledger.js';
14
+ export type LedgerOp = {
15
+ op: 'add_agent';
16
+ spec: RosterSpec;
17
+ } | {
18
+ op: 'event';
19
+ event: LedgerEvent;
20
+ } | {
21
+ op: 'collective';
22
+ spec: CollectiveSpec;
23
+ } | {
24
+ op: 'incident';
25
+ events: LedgerEvent[];
26
+ clawbacks?: ClawbackRequest[];
27
+ } | {
28
+ op: 'confirm_escrow';
29
+ phase: number;
30
+ at: number;
31
+ seq?: number;
32
+ } | {
33
+ op: 'clawback';
34
+ request: ClawbackRequest;
35
+ } | {
36
+ op: 'reverse';
37
+ request: ReverseRequest;
38
+ } | {
39
+ op: 'eliminate';
40
+ request: EliminateRequest;
41
+ } | {
42
+ op: 'respawn';
43
+ request: RespawnRequest;
44
+ } | {
45
+ op: 'tail_check';
46
+ phase: number;
47
+ at: number;
48
+ seq?: number;
49
+ };
50
+ /** Fold one operation. Never mutates `state`; rejected / no-op operations return it as is. */
51
+ export declare function applyOp(state: LedgerState, operation: LedgerOp): LedgerState;
52
+ /** Rebuild a ledger from an initial state and its operation log. */
53
+ export declare function replay(initial: LedgerState, operations: readonly LedgerOp[]): LedgerState;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The ledger operation log and its replay (governance-mode 5.3 "crash-safe order", I-G2).
3
+ *
4
+ * ASCII ONLY (`governance/` is glyph-scanned).
5
+ *
6
+ * `events.jsonl` is the truth and `ledger.json` a checkpoint. After a crash the store
7
+ * rebuilds the ledger by folding the logged operations over the initial roster, which is
8
+ * only sound if every operation is a pure function of (state, operation). `applyOp` is that
9
+ * single dispatch point: the live engine and the replayer both call it, so there is no
10
+ * "replay variant" of any rule that could drift from the live one.
11
+ */
12
+ import { evaluateTail } from './elimination.js';
13
+ import { addAgent, applyCollective, applyIncident, apply, clawback, confirmEscrow, eliminate, respawn, reverseEntry, } from './ledger.js';
14
+ /** Fold one operation. Never mutates `state`; rejected / no-op operations return it as is. */
15
+ export function applyOp(state, operation) {
16
+ switch (operation.op) {
17
+ case 'add_agent':
18
+ return addAgent(state, operation.spec);
19
+ case 'event':
20
+ return apply(state, operation.event).state;
21
+ case 'collective':
22
+ return applyCollective(state, operation.spec).state;
23
+ case 'incident':
24
+ return applyIncident(state, {
25
+ events: operation.events,
26
+ ...(operation.clawbacks === undefined ? {} : { clawbacks: operation.clawbacks }),
27
+ }).state;
28
+ case 'confirm_escrow':
29
+ return confirmEscrow(state, operation.phase, operation.at, operation.seq).state;
30
+ case 'clawback':
31
+ return clawback(state, operation.request).state;
32
+ case 'reverse':
33
+ return reverseEntry(state, operation.request).state;
34
+ case 'eliminate':
35
+ return eliminate(state, operation.request).state;
36
+ case 'respawn':
37
+ return respawn(state, operation.request).state;
38
+ case 'tail_check':
39
+ return evaluateTail(state, {
40
+ phase: operation.phase,
41
+ at: operation.at,
42
+ ...(operation.seq === undefined ? {} : { seq: operation.seq }),
43
+ }).state;
44
+ default: {
45
+ const unreachable = operation;
46
+ throw new Error(`Unknown ledger op: ${JSON.stringify(unreachable)}`);
47
+ }
48
+ }
49
+ }
50
+ /** Rebuild a ledger from an initial state and its operation log. */
51
+ export function replay(initial, operations) {
52
+ return operations.reduce(applyOp, initial);
53
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Ledger state helpers - construction, queries and the small pure functions the booking
3
+ * code in `ledger.ts` is built from (governance-mode 5.3 / 5.8).
4
+ *
5
+ * ASCII ONLY (`governance/` is glyph-scanned).
6
+ *
7
+ * EVERYTHING HERE IS PURE AND TIME-FREE. No function reads a clock or a random source;
8
+ * `at` is always an argument. That is what lets `events.jsonl` replay rebuild a ledger
9
+ * byte-for-byte (I-G2).
10
+ *
11
+ * OBJECT KEY ORDER IS PART OF THE CONTRACT. The replay test compares `JSON.stringify` of
12
+ * two states, so records are always built through the factories below (fixed key order)
13
+ * and updated with spreads, which keep the original position of an existing key.
14
+ */
15
+ import type { AgentRecord, EscrowEntry, LedgerEntry, LedgerState, ScoredRole, StandingLabel, StandingRow } from '../types.js';
16
+ /** The inspector's identity. It is never a ledger entity (I-G5). */
17
+ export declare const INSPECTOR_ID = "insp";
18
+ export interface RosterSpec {
19
+ id: string;
20
+ role: ScoredRole;
21
+ generation?: number;
22
+ }
23
+ /** A fresh, active record. `confirmed` is explicit so respawn can start at 80. */
24
+ export declare function createAgentRecord(spec: RosterSpec, confirmed: number): AgentRecord;
25
+ /** Initial state: every roster member starts with `GOV_LIMITS.initialTokens` confirmed. */
26
+ export declare function createLedger(roster: readonly RosterSpec[]): LedgerState;
27
+ /** Add a roster member (later phases may need more DEV slots). Throws on a duplicate id. */
28
+ export declare function addAgent(state: LedgerState, spec: RosterSpec): LedgerState;
29
+ /** `>=80` NORMAL, `60-79` WARNING, `1-59` DANGER, `<=0` KILLED. Reads `confirmed` only. */
30
+ export declare function labelFor(confirmed: number): StandingLabel;
31
+ /** Active scored agents in roster order, optionally of one role. */
32
+ export declare function activeAgents(state: LedgerState, role?: ScoredRole): AgentRecord[];
33
+ /**
34
+ * Standings in roster order (stable, so the board does not reshuffle on every booking).
35
+ * An eliminated agent is always KILLED: a tail elimination can leave `confirmed` at 45,
36
+ * and a row labelled DANGER next to "eliminated" would read as a contradiction.
37
+ */
38
+ export declare function standings(state: LedgerState): StandingRow[];
39
+ /** Team health = mean `confirmed` of active agents; null when there is none. */
40
+ export declare function teamHealth(state: LedgerState): number | null;
41
+ /** Escrow still held for `phase`: held - released - clawed back. */
42
+ export declare function escrowBalance(agent: AgentRecord, phase: number): number;
43
+ /** Phases with a positive escrow balance, ascending. */
44
+ export declare function escrowPhases(agent: AgentRecord): number[];
45
+ /**
46
+ * True when `agentId` already has a booking of `code` tagged `incidentId`. Positive
47
+ * engine events use their incident id as an idempotency key (R1 `r1:<wp>`, R2
48
+ * `r2:<rejection>`), so a re-run of the settle step cannot pay twice.
49
+ */
50
+ export declare function hasBooked(state: LedgerState, agentId: string, code: LedgerEntry['code'], incidentId: string): boolean;
51
+ /** Append `entry`, folding the oldest rows once the per-agent bound is exceeded. */
52
+ export declare function appendHistory(history: LedgerEntry[], entry: LedgerEntry): LedgerEntry[];
53
+ /** Key of the per-(agent, incident) cumulative negative counter (I-G4). */
54
+ export declare function incidentKey(agentId: string, incidentId: string): string;
55
+ /** The seq an operation stamps: its own when the caller supplies one, else `state.seq + 1`. */
56
+ export declare function stampSeq(state: LedgerState, requested: number | undefined): number;
57
+ /** Build an entry with a fixed key order and no `undefined` members. */
58
+ export declare function makeEntry(fields: {
59
+ seq: number;
60
+ at: number;
61
+ code: LedgerEntry['code'];
62
+ delta: number;
63
+ settlement: LedgerEntry['settlement'];
64
+ phase: number;
65
+ by: LedgerEntry['by'];
66
+ reason: string;
67
+ wpId?: string;
68
+ incidentId?: string;
69
+ evidence?: string;
70
+ capped?: {
71
+ requested: number;
72
+ applied: number;
73
+ };
74
+ confirmedAfter: number;
75
+ provisionalAfter: number;
76
+ }): LedgerEntry;
77
+ export declare function makeEscrowEntry(fields: {
78
+ seq: number;
79
+ at: number;
80
+ phase: number;
81
+ action: EscrowEntry['action'];
82
+ amount: number;
83
+ reason: string;
84
+ code?: EscrowEntry['code'];
85
+ }): EscrowEntry;
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Ledger state helpers - construction, queries and the small pure functions the booking
3
+ * code in `ledger.ts` is built from (governance-mode 5.3 / 5.8).
4
+ *
5
+ * ASCII ONLY (`governance/` is glyph-scanned).
6
+ *
7
+ * EVERYTHING HERE IS PURE AND TIME-FREE. No function reads a clock or a random source;
8
+ * `at` is always an argument. That is what lets `events.jsonl` replay rebuild a ledger
9
+ * byte-for-byte (I-G2).
10
+ *
11
+ * OBJECT KEY ORDER IS PART OF THE CONTRACT. The replay test compares `JSON.stringify` of
12
+ * two states, so records are always built through the factories below (fixed key order)
13
+ * and updated with spreads, which keep the original position of an existing key.
14
+ */
15
+ import { GOV_LIMITS, GOV_SCHEMA_VERSION } from '../limits.js';
16
+ /** The inspector's identity. It is never a ledger entity (I-G5). */
17
+ export const INSPECTOR_ID = 'insp';
18
+ /** A fresh, active record. `confirmed` is explicit so respawn can start at 80. */
19
+ export function createAgentRecord(spec, confirmed) {
20
+ return {
21
+ id: spec.id,
22
+ role: spec.role,
23
+ generation: spec.generation ?? 0,
24
+ confirmed,
25
+ provisional: 0,
26
+ status: 'active',
27
+ replacedBy: null,
28
+ tailStrikes: 0,
29
+ history: [],
30
+ escrowHistory: [],
31
+ };
32
+ }
33
+ function assertScorable(spec) {
34
+ if (spec.id === INSPECTOR_ID || spec.role === 'INSP') {
35
+ throw new Error(`The inspector is not a ledger entity (I-G5): refusing "${spec.id}".`);
36
+ }
37
+ }
38
+ /** Initial state: every roster member starts with `GOV_LIMITS.initialTokens` confirmed. */
39
+ export function createLedger(roster) {
40
+ let state = {
41
+ schemaVersion: GOV_SCHEMA_VERSION,
42
+ seq: 0,
43
+ agents: {},
44
+ incidentNegatives: {},
45
+ failureAnalyses: {},
46
+ };
47
+ for (const spec of roster)
48
+ state = addAgent(state, spec);
49
+ return state;
50
+ }
51
+ /** Add a roster member (later phases may need more DEV slots). Throws on a duplicate id. */
52
+ export function addAgent(state, spec) {
53
+ assertScorable(spec);
54
+ if (state.agents[spec.id] !== undefined) {
55
+ throw new Error(`Ledger already has an agent "${spec.id}".`);
56
+ }
57
+ const record = createAgentRecord(spec, GOV_LIMITS.initialTokens);
58
+ return { ...state, agents: { ...state.agents, [spec.id]: record } };
59
+ }
60
+ /** `>=80` NORMAL, `60-79` WARNING, `1-59` DANGER, `<=0` KILLED. Reads `confirmed` only. */
61
+ export function labelFor(confirmed) {
62
+ if (confirmed >= GOV_LIMITS.labelWarnThreshold)
63
+ return 'NORMAL';
64
+ if (confirmed >= GOV_LIMITS.labelDangerThreshold)
65
+ return 'WARNING';
66
+ if (confirmed > 0)
67
+ return 'DANGER';
68
+ return 'KILLED';
69
+ }
70
+ /** Active scored agents in roster order, optionally of one role. */
71
+ export function activeAgents(state, role) {
72
+ return Object.values(state.agents).filter((a) => a.status === 'active' && (role === undefined || a.role === role));
73
+ }
74
+ /**
75
+ * Standings in roster order (stable, so the board does not reshuffle on every booking).
76
+ * An eliminated agent is always KILLED: a tail elimination can leave `confirmed` at 45,
77
+ * and a row labelled DANGER next to "eliminated" would read as a contradiction.
78
+ */
79
+ export function standings(state) {
80
+ return Object.values(state.agents).map((a) => ({
81
+ id: a.id,
82
+ role: a.role,
83
+ generation: a.generation,
84
+ confirmed: a.confirmed,
85
+ provisional: a.provisional,
86
+ total: a.confirmed + a.provisional,
87
+ label: a.status === 'eliminated' ? 'KILLED' : labelFor(a.confirmed),
88
+ status: a.status,
89
+ replacedBy: a.replacedBy,
90
+ }));
91
+ }
92
+ /** Team health = mean `confirmed` of active agents; null when there is none. */
93
+ export function teamHealth(state) {
94
+ const active = activeAgents(state);
95
+ if (active.length === 0)
96
+ return null;
97
+ return active.reduce((sum, a) => sum + a.confirmed, 0) / active.length;
98
+ }
99
+ /** Escrow still held for `phase`: held - released - clawed back. */
100
+ export function escrowBalance(agent, phase) {
101
+ let balance = 0;
102
+ for (const e of agent.escrowHistory) {
103
+ if (e.phase !== phase)
104
+ continue;
105
+ balance += e.action === 'held' ? e.amount : -e.amount;
106
+ }
107
+ return balance;
108
+ }
109
+ /** Phases with a positive escrow balance, ascending. */
110
+ export function escrowPhases(agent) {
111
+ const phases = [...new Set(agent.escrowHistory.map((e) => e.phase))].sort((a, b) => a - b);
112
+ return phases.filter((p) => escrowBalance(agent, p) > 0);
113
+ }
114
+ /**
115
+ * True when `agentId` already has a booking of `code` tagged `incidentId`. Positive
116
+ * engine events use their incident id as an idempotency key (R1 `r1:<wp>`, R2
117
+ * `r2:<rejection>`), so a re-run of the settle step cannot pay twice.
118
+ */
119
+ export function hasBooked(state, agentId, code, incidentId) {
120
+ const agent = state.agents[agentId];
121
+ if (agent === undefined)
122
+ return false;
123
+ return agent.history.some((e) => e.code === code && e.incidentId === incidentId);
124
+ }
125
+ /** Append `entry`, folding the oldest rows once the per-agent bound is exceeded. */
126
+ export function appendHistory(history, entry) {
127
+ const next = [...history, entry];
128
+ const excess = next.length - GOV_LIMITS.historyPerAgent;
129
+ return excess > 0 ? next.slice(excess) : next;
130
+ }
131
+ /** Key of the per-(agent, incident) cumulative negative counter (I-G4). */
132
+ export function incidentKey(agentId, incidentId) {
133
+ return `${agentId}|${incidentId}`;
134
+ }
135
+ /** The seq an operation stamps: its own when the caller supplies one, else `state.seq + 1`. */
136
+ export function stampSeq(state, requested) {
137
+ return requested ?? state.seq + 1;
138
+ }
139
+ /** Build an entry with a fixed key order and no `undefined` members. */
140
+ export function makeEntry(fields) {
141
+ const entry = {
142
+ seq: fields.seq,
143
+ at: fields.at,
144
+ code: fields.code,
145
+ delta: fields.delta,
146
+ settlement: fields.settlement,
147
+ phase: fields.phase,
148
+ by: fields.by,
149
+ reason: fields.reason,
150
+ confirmedAfter: fields.confirmedAfter,
151
+ provisionalAfter: fields.provisionalAfter,
152
+ };
153
+ if (fields.wpId !== undefined)
154
+ entry.wpId = fields.wpId;
155
+ if (fields.incidentId !== undefined)
156
+ entry.incidentId = fields.incidentId;
157
+ if (fields.evidence !== undefined)
158
+ entry.evidence = fields.evidence;
159
+ if (fields.capped !== undefined)
160
+ entry.capped = fields.capped;
161
+ return entry;
162
+ }
163
+ export function makeEscrowEntry(fields) {
164
+ const entry = {
165
+ seq: fields.seq,
166
+ at: fields.at,
167
+ phase: fields.phase,
168
+ action: fields.action,
169
+ amount: fields.amount,
170
+ reason: fields.reason,
171
+ };
172
+ if (fields.code !== undefined)
173
+ entry.code = fields.code;
174
+ return entry;
175
+ }