@aragon-agent/cli 0.6.44 → 0.6.46
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.
- package/CHANGELOG.md +44 -0
- package/README.md +120 -2
- package/dist/agent/controller.d.ts +69 -0
- package/dist/agent/controller.js +224 -11
- package/dist/agent/governance-view.d.ts +40 -0
- package/dist/agent/governance-view.js +40 -0
- package/dist/agent/governance-wiring.d.ts +162 -0
- package/dist/agent/governance-wiring.js +470 -0
- package/dist/agent/invocation-card.d.ts +77 -0
- package/dist/agent/invocation-card.js +169 -0
- package/dist/agent/plan-prompt.d.ts +7 -0
- package/dist/agent/plan-prompt.js +2 -1
- package/dist/agent/prompt-options.d.ts +6 -0
- package/dist/agent/queued-messages.d.ts +3 -0
- package/dist/agent/queued-messages.js +4 -1
- package/dist/agent/reducer.d.ts +38 -1
- package/dist/agent/reducer.js +57 -12
- package/dist/agent/system-prompt.d.ts +19 -0
- package/dist/agent/system-prompt.js +9 -1
- package/dist/cli.js +45 -1
- package/dist/commands/builtins.js +22 -4
- package/dist/commands/governance-command.d.ts +35 -0
- package/dist/commands/governance-command.js +304 -0
- package/dist/commands/governance-runs-table.d.ts +40 -0
- package/dist/commands/governance-runs-table.js +130 -0
- package/dist/commands/index-build.d.ts +8 -0
- package/dist/commands/index-build.js +11 -0
- package/dist/commands/registry.d.ts +35 -0
- package/dist/commands/registry.js +20 -7
- package/dist/commands/skills.js +36 -2
- package/dist/commands/subagent-command.js +3 -1
- package/dist/commands/team-command.d.ts +6 -0
- package/dist/commands/team-command.js +40 -3
- package/dist/config/app-paths.d.ts +10 -0
- package/dist/config/app-paths.js +12 -0
- package/dist/config/cli-commands.d.ts +18 -0
- package/dist/config/cli-commands.js +47 -1
- package/dist/config/env.d.ts +2 -1
- package/dist/config/env.js +10 -1
- package/dist/config/governance-config.d.ts +125 -0
- package/dist/config/governance-config.js +164 -0
- package/dist/config/governance-launch.d.ts +71 -0
- package/dist/config/governance-launch.js +58 -0
- package/dist/config/load.d.ts +15 -0
- package/dist/config/load.js +26 -1
- package/dist/config/model-profile-store.d.ts +4 -2
- package/dist/config/schema.d.ts +22 -0
- package/dist/config/schema.js +6 -0
- package/dist/config/store.js +14 -1
- package/dist/config/ui-state.d.ts +11 -0
- package/dist/config/ui-state.js +11 -0
- package/dist/diagnostics/doctor.js +20 -0
- package/dist/governance/card-normalize.d.ts +24 -0
- package/dist/governance/card-normalize.js +76 -0
- package/dist/governance/copy.d.ts +109 -0
- package/dist/governance/copy.js +223 -0
- package/dist/governance/engine/aftermath.d.ts +49 -0
- package/dist/governance/engine/aftermath.js +134 -0
- package/dist/governance/engine/artifact-persist.d.ts +35 -0
- package/dist/governance/engine/artifact-persist.js +86 -0
- package/dist/governance/engine/budget.d.ts +52 -0
- package/dist/governance/engine/budget.js +112 -0
- package/dist/governance/engine/cards.d.ts +18 -0
- package/dist/governance/engine/cards.js +186 -0
- package/dist/governance/engine/digest.d.ts +32 -0
- package/dist/governance/engine/digest.js +63 -0
- package/dist/governance/engine/engine-core.d.ts +219 -0
- package/dist/governance/engine/engine-core.js +562 -0
- package/dist/governance/engine/engine.d.ts +68 -0
- package/dist/governance/engine/engine.js +314 -0
- package/dist/governance/engine/estimate.d.ts +38 -0
- package/dist/governance/engine/estimate.js +46 -0
- package/dist/governance/engine/inspector.d.ts +16 -0
- package/dist/governance/engine/inspector.js +396 -0
- package/dist/governance/engine/integration.d.ts +35 -0
- package/dist/governance/engine/integration.js +220 -0
- package/dist/governance/engine/lifecycle.d.ts +29 -0
- package/dist/governance/engine/lifecycle.js +656 -0
- package/dist/governance/engine/pause.d.ts +56 -0
- package/dist/governance/engine/pause.js +107 -0
- package/dist/governance/engine/phase-members.d.ts +15 -0
- package/dist/governance/engine/phase-members.js +34 -0
- package/dist/governance/engine/phase-planner.d.ts +53 -0
- package/dist/governance/engine/phase-planner.js +282 -0
- package/dist/governance/engine/rebuild.d.ts +27 -0
- package/dist/governance/engine/rebuild.js +57 -0
- package/dist/governance/engine/report.d.ts +66 -0
- package/dist/governance/engine/report.js +220 -0
- package/dist/governance/engine/run-digest.d.ts +20 -0
- package/dist/governance/engine/run-digest.js +42 -0
- package/dist/governance/engine/spec-builder.d.ts +117 -0
- package/dist/governance/engine/spec-builder.js +321 -0
- package/dist/governance/engine/stage-runner.d.ts +22 -0
- package/dist/governance/engine/stage-runner.js +664 -0
- package/dist/governance/engine/start-input.d.ts +19 -0
- package/dist/governance/engine/start-input.js +111 -0
- package/dist/governance/engine/state-machine.d.ts +101 -0
- package/dist/governance/engine/state-machine.js +586 -0
- package/dist/governance/engine/submission-queries.d.ts +42 -0
- package/dist/governance/engine/submission-queries.js +97 -0
- package/dist/governance/engine/submission-render.d.ts +12 -0
- package/dist/governance/engine/submission-render.js +92 -0
- package/dist/governance/engine/submissions.d.ts +27 -0
- package/dist/governance/engine/submissions.js +455 -0
- package/dist/governance/engine/visibility.d.ts +104 -0
- package/dist/governance/engine/visibility.js +223 -0
- package/dist/governance/governed-dispatch.d.ts +19 -0
- package/dist/governance/governed-dispatch.js +17 -0
- package/dist/governance/limits.d.ts +107 -0
- package/dist/governance/limits.js +131 -0
- package/dist/governance/posture-transition.d.ts +38 -0
- package/dist/governance/posture-transition.js +44 -0
- package/dist/governance/posture.d.ts +35 -0
- package/dist/governance/posture.js +59 -0
- package/dist/governance/profiles.d.ts +48 -0
- package/dist/governance/profiles.js +140 -0
- package/dist/governance/prompts/orchestrator-block.d.ts +40 -0
- package/dist/governance/prompts/orchestrator-block.js +128 -0
- package/dist/governance/prompts/plan-addendum.d.ts +22 -0
- package/dist/governance/prompts/plan-addendum.js +60 -0
- package/dist/governance/prompts/refusals.d.ts +48 -0
- package/dist/governance/prompts/refusals.js +82 -0
- package/dist/governance/prompts/role-blocks.d.ts +40 -0
- package/dist/governance/prompts/role-blocks.js +255 -0
- package/dist/governance/report-reader.d.ts +31 -0
- package/dist/governance/report-reader.js +57 -0
- package/dist/governance/roles.d.ts +83 -0
- package/dist/governance/roles.js +142 -0
- package/dist/governance/rules/claims.d.ts +83 -0
- package/dist/governance/rules/claims.js +250 -0
- package/dist/governance/rules/elimination.d.ts +66 -0
- package/dist/governance/rules/elimination.js +105 -0
- package/dist/governance/rules/events-table.d.ts +46 -0
- package/dist/governance/rules/events-table.js +94 -0
- package/dist/governance/rules/failure-analysis.d.ts +28 -0
- package/dist/governance/rules/failure-analysis.js +93 -0
- package/dist/governance/rules/ledger-replay.d.ts +53 -0
- package/dist/governance/rules/ledger-replay.js +53 -0
- package/dist/governance/rules/ledger-state.d.ts +85 -0
- package/dist/governance/rules/ledger-state.js +175 -0
- package/dist/governance/rules/ledger.d.ts +228 -0
- package/dist/governance/rules/ledger.js +560 -0
- package/dist/governance/rules/rca.d.ts +68 -0
- package/dist/governance/rules/rca.js +220 -0
- package/dist/governance/rules/settlement.d.ts +129 -0
- package/dist/governance/rules/settlement.js +363 -0
- package/dist/governance/rules/suspicion.d.ts +66 -0
- package/dist/governance/rules/suspicion.js +169 -0
- package/dist/governance/store/artifacts.d.ts +81 -0
- package/dist/governance/store/artifacts.js +173 -0
- package/dist/governance/store/atomic.d.ts +79 -0
- package/dist/governance/store/atomic.js +119 -0
- package/dist/governance/store/events-log.d.ts +35 -0
- package/dist/governance/store/events-log.js +86 -0
- package/dist/governance/store/run-lock.d.ts +51 -0
- package/dist/governance/store/run-lock.js +122 -0
- package/dist/governance/store/run-store.d.ts +229 -0
- package/dist/governance/store/run-store.js +644 -0
- package/dist/governance/store/scoreboard-export.d.ts +53 -0
- package/dist/governance/store/scoreboard-export.js +65 -0
- package/dist/governance/tools/child-tools.d.ts +31 -0
- package/dist/governance/tools/child-tools.js +65 -0
- package/dist/governance/tools/guard.d.ts +71 -0
- package/dist/governance/tools/guard.js +194 -0
- package/dist/governance/tools/inspector-tools.d.ts +63 -0
- package/dist/governance/tools/inspector-tools.js +424 -0
- package/dist/governance/tools/lead-tools.d.ts +42 -0
- package/dist/governance/tools/lead-tools.js +226 -0
- package/dist/governance/tools/normalize-util.d.ts +101 -0
- package/dist/governance/tools/normalize-util.js +230 -0
- package/dist/governance/tools/scan-incomplete.d.ts +79 -0
- package/dist/governance/tools/scan-incomplete.js +486 -0
- package/dist/governance/tools/shared-tools.d.ts +44 -0
- package/dist/governance/tools/shared-tools.js +125 -0
- package/dist/governance/tools/submit-normalizers.d.ts +28 -0
- package/dist/governance/tools/submit-normalizers.js +474 -0
- package/dist/governance/tools/submit-tools.d.ts +26 -0
- package/dist/governance/tools/submit-tools.js +171 -0
- package/dist/governance/types.d.ts +661 -0
- package/dist/governance/types.js +27 -0
- package/dist/session/persist.js +10 -0
- package/dist/session/validate-session.js +36 -3
- package/dist/team/forced-mode.d.ts +19 -0
- package/dist/team/forced-mode.js +42 -20
- package/dist/team/runtime.d.ts +8 -0
- package/dist/team/runtime.js +9 -0
- package/dist/team/subagent.d.ts +23 -0
- package/dist/team/subagent.js +14 -3
- package/dist/team/types.d.ts +6 -0
- package/dist/tools/index.d.ts +30 -7
- package/dist/tools/index.js +14 -0
- package/dist/tools/plan-tools.d.ts +14 -2
- package/dist/tools/plan-tools.js +5 -2
- package/dist/ui/App.js +170 -31
- package/dist/ui/BottomStatusRow.js +1 -1
- package/dist/ui/Composer.d.ts +7 -1
- package/dist/ui/Composer.js +9 -6
- package/dist/ui/GovernancePanel.d.ts +50 -0
- package/dist/ui/GovernancePanel.js +77 -0
- package/dist/ui/GovernanceRun.d.ts +18 -0
- package/dist/ui/GovernanceRun.js +11 -0
- package/dist/ui/StatusBar.d.ts +15 -2
- package/dist/ui/StatusBar.js +10 -4
- package/dist/ui/Transcript.js +7 -1
- package/dist/ui/entries/GovernanceCard.d.ts +30 -0
- package/dist/ui/entries/GovernanceCard.js +32 -0
- package/dist/ui/entries/InvocationCard.d.ts +20 -0
- package/dist/ui/entries/InvocationCard.js +32 -0
- package/dist/ui/governance-copy.d.ts +69 -0
- package/dist/ui/governance-copy.js +104 -0
- package/dist/ui/governance-status.d.ts +145 -0
- package/dist/ui/governance-status.js +326 -0
- package/dist/ui/interaction-copy.d.ts +4 -0
- package/dist/ui/interaction-copy.js +5 -0
- package/dist/ui/interaction-hints.d.ts +17 -0
- package/dist/ui/interaction-hints.js +14 -2
- package/dist/ui/layout/governance-board.d.ts +121 -0
- package/dist/ui/layout/governance-board.js +382 -0
- package/dist/ui/layout/governance-card.d.ts +53 -0
- package/dist/ui/layout/governance-card.js +134 -0
- package/dist/ui/layout/governance-chip.d.ts +38 -0
- package/dist/ui/layout/governance-chip.js +64 -0
- package/dist/ui/layout/governance-panel.d.ts +85 -0
- package/dist/ui/layout/governance-panel.js +358 -0
- package/dist/ui/layout/governance-roster.d.ts +65 -0
- package/dist/ui/layout/governance-roster.js +275 -0
- package/dist/ui/layout/invocation-card.d.ts +41 -0
- package/dist/ui/layout/invocation-card.js +91 -0
- package/dist/ui/layout/status-detail-layout.js +3 -3
- package/dist/ui/layout/status-layout.d.ts +5 -2
- package/dist/ui/layout/status-layout.js +10 -6
- package/dist/ui/layout/virtual-window.js +22 -1
- package/dist/ui/overlays/GovernanceBoardOverlay.d.ts +41 -0
- package/dist/ui/overlays/GovernanceBoardOverlay.js +76 -0
- package/dist/ui/overlays/GovernanceSettingsPage.d.ts +48 -0
- package/dist/ui/overlays/GovernanceSettingsPage.js +93 -0
- package/dist/ui/overlays/HelpOverlay.js +4 -3
- package/dist/ui/overlays/QuestionOverlay.d.ts +9 -1
- package/dist/ui/overlays/QuestionOverlay.js +4 -2
- package/dist/ui/overlays/SettingsScreen.d.ts +7 -0
- package/dist/ui/overlays/SettingsScreen.js +21 -1
- package/dist/ui/overlays/governance-settings.d.ts +79 -0
- package/dist/ui/overlays/governance-settings.js +140 -0
- package/dist/ui/overlays/model-profile-state.d.ts +6 -1
- package/dist/ui/overlays/model-profile-state.js +10 -0
- package/dist/ui/palettes.d.ts +17 -0
- package/dist/ui/palettes.js +9 -0
- package/dist/ui/scrollback/live-preview.js +2 -0
- package/dist/ui/scrollback/settled-boundary.js +3 -0
- package/dist/ui/shortcuts.js +2 -2
- package/dist/ui/theme.d.ts +7 -0
- package/dist/ui/theme.js +1 -0
- package/dist/ui/transcript-text.js +13 -1
- package/dist/ui/use-wheel-routing.js +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Ledger - the ONE accounting path (governance-mode 5.3 / 5.8 / 5.10, I-G7).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY (`governance/` is glyph-scanned).
|
|
5
|
+
*
|
|
6
|
+
* Engine-booked events (settlement, RCA expansion, claim rulings) and inspector-booked
|
|
7
|
+
* events (`ledger_apply`) all arrive here as a `LedgerEvent`, are looked up in the same
|
|
8
|
+
* catalogue and are held to the same per-event and per-incident limits. There is no second
|
|
9
|
+
* way to change a balance, which is what makes the audit trail believable.
|
|
10
|
+
*
|
|
11
|
+
* EVERY FUNCTION IS PURE AND DETERMINISTIC (I-G2). A function takes a `LedgerState` and
|
|
12
|
+
* returns a NEW one; it never mutates its input, never reads a clock and never draws a
|
|
13
|
+
* random number - `at` travels inside the event. Replaying the stored event list therefore
|
|
14
|
+
* reproduces the checkpoint byte-for-byte. `governance-ledger.test.ts` proves it with a
|
|
15
|
+
* seeded random-sequence property test run on deep-frozen states.
|
|
16
|
+
*
|
|
17
|
+
* KILL READS `confirmed` ONLY (I-G3). A clawback shrinks `provisional`, so a primary DEV
|
|
18
|
+
* can lose most of their TOTAL without being eliminated; only a depleted `confirmed`
|
|
19
|
+
* pool, or the tail rule, removes an agent.
|
|
20
|
+
*
|
|
21
|
+
* Related modules: `ledger-state.ts` (construction + queries), `failure-analysis.ts`
|
|
22
|
+
* (successor brief), `ledger-replay.ts` (op log), `elimination.ts` (tail rule).
|
|
23
|
+
*/
|
|
24
|
+
import { GOV_LIMITS } from '../limits.js';
|
|
25
|
+
import { EVENTS_TABLE, } from './events-table.js';
|
|
26
|
+
import { buildFailureAnalysis } from './failure-analysis.js';
|
|
27
|
+
import { INSPECTOR_ID, activeAgents, appendHistory, escrowBalance, escrowPhases, incidentKey, makeEntry, makeEscrowEntry, stampSeq, } from './ledger-state.js';
|
|
28
|
+
export * from './ledger-state.js';
|
|
29
|
+
/** C2 for an agent that is not the primary cause of the failed integration (5.7). */
|
|
30
|
+
export const C2_RELIEF_DELTA = -2;
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Settlement routing
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Which pool a booking lands in. EXHAUSTIVE over the three settlements, with a throwing
|
|
36
|
+
* default: a silent fallthrough into "some pool" would corrupt balances with no trace.
|
|
37
|
+
*
|
|
38
|
+
* - provisional + positive -> escrow (clawback-able).
|
|
39
|
+
* - confirmed / immediate + positive -> `confirmed` (RV-9: an "immediate" reward is
|
|
40
|
+
* credited at once; the only difference from escrow is that it cannot be clawed back).
|
|
41
|
+
* - any negative -> deducted from `confirmed`, whatever the label says.
|
|
42
|
+
*
|
|
43
|
+
* The switch runs BEFORE the sign test so an invalid label fails even on a zero delta.
|
|
44
|
+
*/
|
|
45
|
+
export function settlementPool(settlement, delta) {
|
|
46
|
+
let credit;
|
|
47
|
+
switch (settlement) {
|
|
48
|
+
case 'provisional':
|
|
49
|
+
credit = 'provisional';
|
|
50
|
+
break;
|
|
51
|
+
case 'confirmed':
|
|
52
|
+
case 'immediate':
|
|
53
|
+
credit = 'confirmed';
|
|
54
|
+
break;
|
|
55
|
+
default: {
|
|
56
|
+
const unreachable = settlement;
|
|
57
|
+
throw new Error(`Unknown settlement "${String(unreachable)}": cannot route a booking.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return delta < 0 ? 'deduct' : credit;
|
|
61
|
+
}
|
|
62
|
+
/** Order in which one incident's events are applied so a cap truncates the right one. */
|
|
63
|
+
export function incidentPriority(code) {
|
|
64
|
+
switch (code) {
|
|
65
|
+
case 'D13':
|
|
66
|
+
case 'R9':
|
|
67
|
+
case 'T4':
|
|
68
|
+
case 'T10':
|
|
69
|
+
return 0;
|
|
70
|
+
case 'D14':
|
|
71
|
+
return 1;
|
|
72
|
+
case 'D15':
|
|
73
|
+
return 2;
|
|
74
|
+
case 'C2':
|
|
75
|
+
case 'C3':
|
|
76
|
+
case 'C4':
|
|
77
|
+
return 3;
|
|
78
|
+
default:
|
|
79
|
+
return 4;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// apply
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
function reject(code, message) {
|
|
86
|
+
return { code, message };
|
|
87
|
+
}
|
|
88
|
+
function lookupDef(event, options) {
|
|
89
|
+
const table = options.catalogue ?? EVENTS_TABLE;
|
|
90
|
+
return Object.prototype.hasOwnProperty.call(table, event.code) ? table[event.code] : undefined;
|
|
91
|
+
}
|
|
92
|
+
/** Refusals that depend on the event and roster only; never throws. */
|
|
93
|
+
function screenEvent(state, event, def) {
|
|
94
|
+
if (event.agentId === INSPECTOR_ID) {
|
|
95
|
+
return reject('INSPECTOR_NOT_SCORED', 'The inspector is not in the ledger (I-G5).');
|
|
96
|
+
}
|
|
97
|
+
if (def === undefined)
|
|
98
|
+
return reject('UNKNOWN_CODE', `Unknown event code "${event.code}".`);
|
|
99
|
+
const agent = state.agents[event.agentId];
|
|
100
|
+
if (agent === undefined)
|
|
101
|
+
return reject('UNKNOWN_AGENT', `No agent "${event.agentId}".`);
|
|
102
|
+
if (agent.status !== 'active') {
|
|
103
|
+
return reject('AGENT_ELIMINATED', `Agent "${agent.id}" has been eliminated.`);
|
|
104
|
+
}
|
|
105
|
+
if (def.role !== 'ALL' && def.role !== agent.role) {
|
|
106
|
+
return reject('ROLE_MISMATCH', `${def.code} applies to ${def.role}, not ${agent.role}.`);
|
|
107
|
+
}
|
|
108
|
+
if (event.relief === true && def.code !== 'C2') {
|
|
109
|
+
return reject('RELIEF_NOT_ALLOWED', 'Only C2 has a relieved (-2) variant.');
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
function clampPerEvent(delta) {
|
|
114
|
+
return Math.min(GOV_LIMITS.maxSingleReward, Math.max(GOV_LIMITS.maxSingleDeduction, delta));
|
|
115
|
+
}
|
|
116
|
+
/** Trim a deduction so the (agent, incident) running total never passes -50 (I-G4). */
|
|
117
|
+
function capByIncident(state, target, delta) {
|
|
118
|
+
if (delta >= 0 || target.incidentId === undefined)
|
|
119
|
+
return delta;
|
|
120
|
+
const used = state.incidentNegatives[incidentKey(target.agentId, target.incidentId)] ?? 0;
|
|
121
|
+
return Math.max(delta, GOV_LIMITS.maxIncidentNegative - used);
|
|
122
|
+
}
|
|
123
|
+
/** Move `delta` into its pool; the floor keeps `confirmed` from going below zero. */
|
|
124
|
+
function bookDelta(agent, pool, delta) {
|
|
125
|
+
switch (pool) {
|
|
126
|
+
case 'provisional':
|
|
127
|
+
return { confirmed: agent.confirmed, provisional: agent.provisional + delta, applied: delta };
|
|
128
|
+
case 'confirmed':
|
|
129
|
+
return { confirmed: agent.confirmed + delta, provisional: agent.provisional, applied: delta };
|
|
130
|
+
case 'deduct': {
|
|
131
|
+
const confirmed = Math.max(0, agent.confirmed + delta);
|
|
132
|
+
return { confirmed, provisional: agent.provisional, applied: confirmed - agent.confirmed };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Unary minus that never yields -0 (Object.is distinguishes it; JSON hides it). */
|
|
137
|
+
function negate(value) {
|
|
138
|
+
return value === 0 ? 0 : -value;
|
|
139
|
+
}
|
|
140
|
+
function putAgent(state, agent, seq) {
|
|
141
|
+
return {
|
|
142
|
+
...state,
|
|
143
|
+
seq: Math.max(state.seq, seq),
|
|
144
|
+
agents: { ...state.agents, [agent.id]: agent },
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function rejectedOutcome(state, rejection) {
|
|
148
|
+
return { state, booked: false, rejected: rejection, clipped: 0, eliminated: false };
|
|
149
|
+
}
|
|
150
|
+
function buildEventEntry(event, def, seq, booking, requested) {
|
|
151
|
+
const capped = booking.applied === requested ? undefined : { requested, applied: booking.applied };
|
|
152
|
+
return makeEntry({
|
|
153
|
+
seq,
|
|
154
|
+
at: event.at,
|
|
155
|
+
code: def.code,
|
|
156
|
+
delta: booking.applied,
|
|
157
|
+
settlement: def.settlement,
|
|
158
|
+
phase: event.phase,
|
|
159
|
+
by: event.by,
|
|
160
|
+
reason: event.reason,
|
|
161
|
+
wpId: event.wpId,
|
|
162
|
+
incidentId: event.incidentId,
|
|
163
|
+
evidence: event.evidence,
|
|
164
|
+
capped,
|
|
165
|
+
confirmedAfter: booking.confirmed,
|
|
166
|
+
provisionalAfter: booking.provisional,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function recordIncidentNegative(state, target, applied) {
|
|
170
|
+
if (applied >= 0 || target.incidentId === undefined)
|
|
171
|
+
return state.incidentNegatives;
|
|
172
|
+
const key = incidentKey(target.agentId, target.incidentId);
|
|
173
|
+
return { ...state.incidentNegatives, [key]: (state.incidentNegatives[key] ?? 0) + applied };
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Book one event.
|
|
177
|
+
*
|
|
178
|
+
* Order of operations (each step can only SHRINK the magnitude): catalogue delta ->
|
|
179
|
+
* per-event limit (+20 / -40) -> incident cap (-50 cumulative) -> floor at 0. The entry
|
|
180
|
+
* records `capped: { requested, applied }` whenever any step trimmed the amount, so the
|
|
181
|
+
* inspector can say why a figure is smaller than the catalogue's.
|
|
182
|
+
*/
|
|
183
|
+
export function apply(state, event, options = {}) {
|
|
184
|
+
const def = lookupDef(event, options);
|
|
185
|
+
const rejection = screenEvent(state, event, def);
|
|
186
|
+
if (rejection !== undefined)
|
|
187
|
+
return rejectedOutcome(state, rejection);
|
|
188
|
+
const eventDef = def;
|
|
189
|
+
const agent = state.agents[event.agentId];
|
|
190
|
+
const requested = event.relief === true ? C2_RELIEF_DELTA : eventDef.delta;
|
|
191
|
+
const wanted = capByIncident(state, event, clampPerEvent(requested));
|
|
192
|
+
const pool = settlementPool(eventDef.settlement, wanted);
|
|
193
|
+
const booking = bookDelta(agent, pool, wanted);
|
|
194
|
+
const seq = stampSeq(state, event.seq);
|
|
195
|
+
const entry = buildEventEntry(event, eventDef, seq, booking, requested);
|
|
196
|
+
const escrow = pool === 'provisional' && booking.applied > 0
|
|
197
|
+
? [
|
|
198
|
+
...agent.escrowHistory,
|
|
199
|
+
makeEscrowEntry({
|
|
200
|
+
seq,
|
|
201
|
+
at: event.at,
|
|
202
|
+
phase: event.phase,
|
|
203
|
+
action: 'held',
|
|
204
|
+
amount: booking.applied,
|
|
205
|
+
code: eventDef.code,
|
|
206
|
+
reason: event.reason,
|
|
207
|
+
}),
|
|
208
|
+
]
|
|
209
|
+
: agent.escrowHistory;
|
|
210
|
+
const updated = {
|
|
211
|
+
...agent,
|
|
212
|
+
confirmed: booking.confirmed,
|
|
213
|
+
provisional: booking.provisional,
|
|
214
|
+
history: appendHistory(agent.history, entry),
|
|
215
|
+
escrowHistory: escrow,
|
|
216
|
+
};
|
|
217
|
+
let next = putAgent(state, updated, seq);
|
|
218
|
+
next = { ...next, incidentNegatives: recordIncidentNegative(state, event, booking.applied) };
|
|
219
|
+
const depleted = updated.confirmed <= 0;
|
|
220
|
+
if (depleted)
|
|
221
|
+
next = eliminateInState(next, event.agentId, 'depleted', event.at, seq);
|
|
222
|
+
return {
|
|
223
|
+
state: next,
|
|
224
|
+
booked: true,
|
|
225
|
+
entry,
|
|
226
|
+
clipped: Math.abs(requested - booking.applied),
|
|
227
|
+
eliminated: depleted,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/** Apply a list in order; a rejected event is skipped (its outcome says why). */
|
|
231
|
+
export function applyAll(state, events, options = {}) {
|
|
232
|
+
const outcomes = [];
|
|
233
|
+
let current = state;
|
|
234
|
+
for (const event of events) {
|
|
235
|
+
const outcome = apply(current, event, options);
|
|
236
|
+
outcomes.push(outcome);
|
|
237
|
+
current = outcome.state;
|
|
238
|
+
}
|
|
239
|
+
return { state: current, outcomes };
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Expand a collective event into one `LedgerEvent` per ACTIVE scored agent, in roster
|
|
243
|
+
* order. The inspector is never present because it is never in `state.agents`.
|
|
244
|
+
*/
|
|
245
|
+
export function expandCollective(state, spec) {
|
|
246
|
+
const only = spec.participants === undefined ? undefined : new Set(spec.participants);
|
|
247
|
+
const relief = new Set(spec.reliefIds ?? []);
|
|
248
|
+
return activeAgents(state)
|
|
249
|
+
.filter((a) => only === undefined || only.has(a.id))
|
|
250
|
+
.map((a) => {
|
|
251
|
+
const event = {
|
|
252
|
+
code: spec.code,
|
|
253
|
+
agentId: a.id,
|
|
254
|
+
at: spec.at,
|
|
255
|
+
phase: spec.phase,
|
|
256
|
+
by: spec.by,
|
|
257
|
+
reason: spec.reason,
|
|
258
|
+
};
|
|
259
|
+
if (spec.wpId !== undefined)
|
|
260
|
+
event.wpId = spec.wpId;
|
|
261
|
+
if (spec.incidentId !== undefined)
|
|
262
|
+
event.incidentId = spec.incidentId;
|
|
263
|
+
if (spec.seq !== undefined)
|
|
264
|
+
event.seq = spec.seq;
|
|
265
|
+
if (spec.code === 'C2' && relief.has(a.id))
|
|
266
|
+
event.relief = true;
|
|
267
|
+
return event;
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
export function applyCollective(state, spec) {
|
|
271
|
+
return applyAll(state, expandCollective(state, spec));
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Integration passed: move every active agent's remaining escrow for `phase` into
|
|
275
|
+
* `confirmed`. Whatever a clawback already took is gone, so only the unreclaimed balance
|
|
276
|
+
* is released. An eliminated agent's escrow was forfeited when it was removed.
|
|
277
|
+
*/
|
|
278
|
+
export function confirmEscrow(state, phase, at, seqOverride) {
|
|
279
|
+
const seq = stampSeq(state, seqOverride);
|
|
280
|
+
const released = [];
|
|
281
|
+
let next = state;
|
|
282
|
+
for (const agent of activeAgents(state)) {
|
|
283
|
+
const amount = escrowBalance(agent, phase);
|
|
284
|
+
if (amount <= 0)
|
|
285
|
+
continue;
|
|
286
|
+
const confirmed = agent.confirmed + amount;
|
|
287
|
+
const provisional = agent.provisional - amount;
|
|
288
|
+
const reason = `Escrow for phase ${phase + 1} released after integration`;
|
|
289
|
+
const entry = makeEntry({
|
|
290
|
+
seq,
|
|
291
|
+
at,
|
|
292
|
+
code: 'ESCROW_RELEASE',
|
|
293
|
+
delta: amount,
|
|
294
|
+
settlement: 'escrow_release',
|
|
295
|
+
phase,
|
|
296
|
+
by: 'engine',
|
|
297
|
+
reason,
|
|
298
|
+
confirmedAfter: confirmed,
|
|
299
|
+
provisionalAfter: provisional,
|
|
300
|
+
});
|
|
301
|
+
const record = {
|
|
302
|
+
...agent,
|
|
303
|
+
confirmed,
|
|
304
|
+
provisional,
|
|
305
|
+
history: appendHistory(agent.history, entry),
|
|
306
|
+
escrowHistory: [
|
|
307
|
+
...agent.escrowHistory,
|
|
308
|
+
makeEscrowEntry({ seq, at, phase, action: 'released', amount, reason }),
|
|
309
|
+
],
|
|
310
|
+
};
|
|
311
|
+
next = putAgent(next, record, seq);
|
|
312
|
+
released.push({ agentId: agent.id, amount });
|
|
313
|
+
}
|
|
314
|
+
return { state: next, released };
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Integration failed: reclaim the culprit's escrow for `phase`. The amount counts against
|
|
318
|
+
* the same (agent, incident) -50 cap as the deductions and is applied LAST, so the cap
|
|
319
|
+
* truncates the clawback rather than the D13/D14/D15 the inspector asked for.
|
|
320
|
+
* Only `provisional` shrinks: `confirmed` (and so KILL) is untouched (I-G3).
|
|
321
|
+
*/
|
|
322
|
+
export function clawback(state, request) {
|
|
323
|
+
const agent = state.agents[request.agentId];
|
|
324
|
+
const none = { state, clawed: 0, requested: 0, capped: false };
|
|
325
|
+
if (agent === undefined || agent.status !== 'active')
|
|
326
|
+
return none;
|
|
327
|
+
const balance = escrowBalance(agent, request.phase);
|
|
328
|
+
if (balance <= 0)
|
|
329
|
+
return none;
|
|
330
|
+
const target = { agentId: agent.id, incidentId: request.incidentId };
|
|
331
|
+
// abs, not unary minus: a fully capped clawback must be +0, never the JSON-invisible -0.
|
|
332
|
+
const clawed = Math.abs(capByIncident(state, target, -balance));
|
|
333
|
+
const seq = stampSeq(state, request.seq);
|
|
334
|
+
const provisional = agent.provisional - clawed;
|
|
335
|
+
const entry = makeEntry({
|
|
336
|
+
seq,
|
|
337
|
+
at: request.at,
|
|
338
|
+
code: 'CLAWBACK',
|
|
339
|
+
delta: negate(clawed),
|
|
340
|
+
settlement: 'clawback',
|
|
341
|
+
phase: request.phase,
|
|
342
|
+
by: request.by ?? 'engine',
|
|
343
|
+
reason: request.reason,
|
|
344
|
+
incidentId: request.incidentId,
|
|
345
|
+
capped: clawed === balance ? undefined : { requested: -balance, applied: negate(clawed) },
|
|
346
|
+
confirmedAfter: agent.confirmed,
|
|
347
|
+
provisionalAfter: provisional,
|
|
348
|
+
});
|
|
349
|
+
const record = {
|
|
350
|
+
...agent,
|
|
351
|
+
provisional,
|
|
352
|
+
history: appendHistory(agent.history, entry),
|
|
353
|
+
escrowHistory: clawed > 0
|
|
354
|
+
? [
|
|
355
|
+
...agent.escrowHistory,
|
|
356
|
+
makeEscrowEntry({
|
|
357
|
+
seq,
|
|
358
|
+
at: request.at,
|
|
359
|
+
phase: request.phase,
|
|
360
|
+
action: 'clawed_back',
|
|
361
|
+
amount: clawed,
|
|
362
|
+
reason: request.reason,
|
|
363
|
+
}),
|
|
364
|
+
]
|
|
365
|
+
: agent.escrowHistory,
|
|
366
|
+
};
|
|
367
|
+
let next = putAgent(state, record, seq);
|
|
368
|
+
next = { ...next, incidentNegatives: recordIncidentNegative(state, target, negate(clawed)) };
|
|
369
|
+
return { state: next, clawed, requested: balance, capped: clawed !== balance };
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Apply one incident in the priority order D13 -> D14/D15 -> C2/C3/C4 -> clawback
|
|
373
|
+
* (5.3), so a cap that bites trims the LAST thing in that chain. Stable within a rank.
|
|
374
|
+
*/
|
|
375
|
+
export function applyIncident(state, input) {
|
|
376
|
+
const ordered = input.events
|
|
377
|
+
.map((event, index) => ({ event, index, rank: incidentPriority(event.code) }))
|
|
378
|
+
.sort((a, b) => a.rank - b.rank || a.index - b.index)
|
|
379
|
+
.map((item) => item.event);
|
|
380
|
+
const { state: afterEvents, outcomes } = applyAll(state, ordered);
|
|
381
|
+
let current = afterEvents;
|
|
382
|
+
const clawbacks = [];
|
|
383
|
+
for (const request of input.clawbacks ?? []) {
|
|
384
|
+
const outcome = clawback(current, request);
|
|
385
|
+
clawbacks.push(outcome);
|
|
386
|
+
current = outcome.state;
|
|
387
|
+
}
|
|
388
|
+
return { state: current, outcomes, clawbacks };
|
|
389
|
+
}
|
|
390
|
+
function reversalMarker(original) {
|
|
391
|
+
return `reverses:${original.seq}:${original.code}`;
|
|
392
|
+
}
|
|
393
|
+
/** The newest un-reversed negative entry of `code` (for `wpId` when given). */
|
|
394
|
+
function findReversible(agent, request) {
|
|
395
|
+
const done = new Set(agent.history.filter((e) => e.evidence?.startsWith('reverses:')).map((e) => e.evidence));
|
|
396
|
+
for (let i = agent.history.length - 1; i >= 0; i--) {
|
|
397
|
+
const e = agent.history[i];
|
|
398
|
+
if (e.code !== request.code || e.delta >= 0 || done.has(reversalMarker(e)))
|
|
399
|
+
continue;
|
|
400
|
+
if (request.wpId !== undefined && e.wpId !== request.wpId)
|
|
401
|
+
continue;
|
|
402
|
+
return e;
|
|
403
|
+
}
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Credit back the newest un-reversed deduction of `code`: the AC-24 "withdraw undoes the
|
|
408
|
+
* D5". It re-credits exactly what was DEDUCTED (a capped D5 is refunded at its capped
|
|
409
|
+
* amount) and is itself a ledger row, so the audit trail shows both halves. Does nothing
|
|
410
|
+
* when the original has been folded out of the bounded history.
|
|
411
|
+
*/
|
|
412
|
+
export function reverseEntry(state, request) {
|
|
413
|
+
const agent = state.agents[request.agentId];
|
|
414
|
+
if (agent === undefined || agent.status !== 'active')
|
|
415
|
+
return { state, reversed: false };
|
|
416
|
+
const original = findReversible(agent, request);
|
|
417
|
+
if (original === undefined)
|
|
418
|
+
return { state, reversed: false };
|
|
419
|
+
const amount = -original.delta;
|
|
420
|
+
const seq = stampSeq(state, request.seq);
|
|
421
|
+
const confirmed = agent.confirmed + amount;
|
|
422
|
+
const entry = makeEntry({
|
|
423
|
+
seq,
|
|
424
|
+
at: request.at,
|
|
425
|
+
code: original.code,
|
|
426
|
+
delta: amount,
|
|
427
|
+
settlement: 'immediate',
|
|
428
|
+
phase: original.phase,
|
|
429
|
+
by: 'engine',
|
|
430
|
+
reason: `Reversal of #${original.seq} ${original.code}: ${request.reason}`,
|
|
431
|
+
wpId: original.wpId,
|
|
432
|
+
incidentId: original.incidentId,
|
|
433
|
+
evidence: reversalMarker(original),
|
|
434
|
+
confirmedAfter: confirmed,
|
|
435
|
+
provisionalAfter: agent.provisional,
|
|
436
|
+
});
|
|
437
|
+
const record = {
|
|
438
|
+
...agent,
|
|
439
|
+
confirmed,
|
|
440
|
+
history: appendHistory(agent.history, entry),
|
|
441
|
+
};
|
|
442
|
+
let next = putAgent(state, record, seq);
|
|
443
|
+
if (original.incidentId !== undefined) {
|
|
444
|
+
const key = incidentKey(agent.id, original.incidentId);
|
|
445
|
+
const used = state.incidentNegatives[key] ?? 0;
|
|
446
|
+
next = { ...next, incidentNegatives: { ...next.incidentNegatives, [key]: used + amount } };
|
|
447
|
+
}
|
|
448
|
+
return { state: next, reversed: true, entry };
|
|
449
|
+
}
|
|
450
|
+
// ---------------------------------------------------------------------------
|
|
451
|
+
// Elimination and respawn
|
|
452
|
+
// ---------------------------------------------------------------------------
|
|
453
|
+
/** Forfeit any remaining escrow: an eliminated agent can never be paid it out. */
|
|
454
|
+
function forfeitEscrow(agent, at, seq) {
|
|
455
|
+
const phases = escrowPhases(agent);
|
|
456
|
+
if (phases.length === 0)
|
|
457
|
+
return agent;
|
|
458
|
+
const reason = 'Escrow forfeited on elimination';
|
|
459
|
+
const escrow = [...agent.escrowHistory];
|
|
460
|
+
let total = 0;
|
|
461
|
+
for (const phase of phases) {
|
|
462
|
+
const amount = escrowBalance(agent, phase);
|
|
463
|
+
total += amount;
|
|
464
|
+
escrow.push(makeEscrowEntry({ seq, at, phase, action: 'clawed_back', amount, reason }));
|
|
465
|
+
}
|
|
466
|
+
const entry = makeEntry({
|
|
467
|
+
seq,
|
|
468
|
+
at,
|
|
469
|
+
code: 'CLAWBACK',
|
|
470
|
+
delta: -total,
|
|
471
|
+
settlement: 'clawback',
|
|
472
|
+
phase: phases[phases.length - 1],
|
|
473
|
+
by: 'engine',
|
|
474
|
+
reason,
|
|
475
|
+
confirmedAfter: agent.confirmed,
|
|
476
|
+
provisionalAfter: agent.provisional - total,
|
|
477
|
+
});
|
|
478
|
+
return {
|
|
479
|
+
...agent,
|
|
480
|
+
provisional: agent.provisional - total,
|
|
481
|
+
history: appendHistory(agent.history, entry),
|
|
482
|
+
escrowHistory: escrow,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function eliminateInState(state, agentId, reason, at, seq) {
|
|
486
|
+
const agent = state.agents[agentId];
|
|
487
|
+
const analysis = buildFailureAnalysis(agent, reason);
|
|
488
|
+
const forfeited = forfeitEscrow(agent, at, seq);
|
|
489
|
+
const record = { ...forfeited, status: 'eliminated', eliminatedReason: reason };
|
|
490
|
+
const next = putAgent(state, record, seq);
|
|
491
|
+
return { ...next, failureAnalyses: { ...next.failureAnalyses, [agentId]: analysis } };
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Remove an active agent (tail rule or an explicit clawback decision). KILL by depletion
|
|
495
|
+
* happens inside `apply`; this is the entry point for the other two reasons. A no-op for
|
|
496
|
+
* an unknown or already-eliminated id, so replaying it twice is harmless.
|
|
497
|
+
*/
|
|
498
|
+
export function eliminate(state, request) {
|
|
499
|
+
const agent = state.agents[request.agentId];
|
|
500
|
+
if (agent === undefined || agent.status !== 'active') {
|
|
501
|
+
return { state, eliminated: false, analysis: null };
|
|
502
|
+
}
|
|
503
|
+
const seq = stampSeq(state, request.seq);
|
|
504
|
+
const next = eliminateInState(state, request.agentId, request.reason, request.at, seq);
|
|
505
|
+
return {
|
|
506
|
+
state: next,
|
|
507
|
+
eliminated: true,
|
|
508
|
+
analysis: next.failureAnalyses[request.agentId],
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/** `dev2` -> `dev2-r1` -> `dev2-r2`: the suffix tracks the generation. */
|
|
512
|
+
export function successorId(predecessor) {
|
|
513
|
+
return `${predecessor.id.replace(/-r\d+$/, '')}-r${predecessor.generation + 1}`;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Replace an eliminated agent with a fresh identity at `GOV_LIMITS.respawnTokens`
|
|
517
|
+
* (all confirmed, no escrow). The successor inherits NO code - only the predecessor's
|
|
518
|
+
* `FailureAnalysis`, returned for the brief. Subagent labels are capped at 12 characters,
|
|
519
|
+
* so an over-long id is a bug in the roster naming and throws.
|
|
520
|
+
*/
|
|
521
|
+
export function respawn(state, request) {
|
|
522
|
+
const old = state.agents[request.agentId];
|
|
523
|
+
const none = { state, successor: null, analysis: null };
|
|
524
|
+
if (old === undefined || old.status !== 'eliminated' || old.replacedBy !== null)
|
|
525
|
+
return none;
|
|
526
|
+
const id = successorId(old);
|
|
527
|
+
if (id.length > 12)
|
|
528
|
+
throw new Error(`Respawn id "${id}" exceeds 12 characters.`);
|
|
529
|
+
if (state.agents[id] !== undefined)
|
|
530
|
+
return none;
|
|
531
|
+
const seq = stampSeq(state, request.seq);
|
|
532
|
+
const entry = makeEntry({
|
|
533
|
+
seq,
|
|
534
|
+
at: request.at,
|
|
535
|
+
code: 'RESPAWN',
|
|
536
|
+
delta: GOV_LIMITS.respawnTokens,
|
|
537
|
+
settlement: 'confirmed',
|
|
538
|
+
phase: request.phase,
|
|
539
|
+
by: 'engine',
|
|
540
|
+
reason: `Respawned as the successor of ${old.id}`,
|
|
541
|
+
confirmedAfter: GOV_LIMITS.respawnTokens,
|
|
542
|
+
provisionalAfter: 0,
|
|
543
|
+
});
|
|
544
|
+
const successor = {
|
|
545
|
+
id,
|
|
546
|
+
role: old.role,
|
|
547
|
+
generation: old.generation + 1,
|
|
548
|
+
confirmed: GOV_LIMITS.respawnTokens,
|
|
549
|
+
provisional: 0,
|
|
550
|
+
status: 'active',
|
|
551
|
+
replacedBy: null,
|
|
552
|
+
tailStrikes: 0,
|
|
553
|
+
history: [entry],
|
|
554
|
+
escrowHistory: [],
|
|
555
|
+
};
|
|
556
|
+
const retired = { ...old, replacedBy: id };
|
|
557
|
+
const next = putAgent(putAgent(state, retired, seq), successor, seq);
|
|
558
|
+
const analysis = state.failureAnalyses[old.id] ?? buildFailureAnalysis(old, old.eliminatedReason ?? 'depleted');
|
|
559
|
+
return { state: next, successor, analysis };
|
|
560
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root-cause attribution -> ledger events (governance-mode 5.7).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY (`governance/` is glyph-scanned).
|
|
5
|
+
*
|
|
6
|
+
* The inspector reports WHO and HOW (a structured `RcaInput`); the engine owns the
|
|
7
|
+
* ARITHMETIC. That split is the point: the model supplies judgement it can justify from
|
|
8
|
+
* the code, and cannot mistype a figure, forget the C2 relief or double-count a cap.
|
|
9
|
+
* `expandRca` is pure - it returns events plus clawback requests in priority order, and
|
|
10
|
+
* the caller books them through `applyIncident` so the single-incident -50 cap truncates
|
|
11
|
+
* the right row (D13 -> D14/D15 -> C2/C3/C4 -> clawback).
|
|
12
|
+
*/
|
|
13
|
+
import type { LedgerEntry, LedgerState, RcaInput } from '../types.js';
|
|
14
|
+
import type { ClawbackRequest, IncidentOutcome, LedgerEvent } from './ledger.js';
|
|
15
|
+
type Attribution = RcaInput['attributions'][number];
|
|
16
|
+
type Level = Attribution['level'];
|
|
17
|
+
/** Recorded in the report; contributing agents carry weight but no event of their own. */
|
|
18
|
+
export declare const RCA_WEIGHTS: Readonly<Record<Level, number>>;
|
|
19
|
+
export interface RcaContext {
|
|
20
|
+
state: LedgerState;
|
|
21
|
+
phase: number;
|
|
22
|
+
at: number;
|
|
23
|
+
/** Shared by every event of the incident: the cap is per (agent, incident). */
|
|
24
|
+
incidentId: string;
|
|
25
|
+
/** Fix cycles consumed in this phase; >= 3 adds C3 for everyone. */
|
|
26
|
+
fixCycles: number;
|
|
27
|
+
by: LedgerEntry['by'];
|
|
28
|
+
/** The phase's members; absent => every active scored agent. */
|
|
29
|
+
participants?: readonly string[];
|
|
30
|
+
wpId?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface RcaWeight {
|
|
33
|
+
agentId: string;
|
|
34
|
+
level: Level;
|
|
35
|
+
weight: number;
|
|
36
|
+
}
|
|
37
|
+
export interface RcaExpansion {
|
|
38
|
+
/** True when `boundary` is false: an individual bug, so no integration events at all. */
|
|
39
|
+
individualDefect: boolean;
|
|
40
|
+
/** In application order. Book with `applyIncident` together with `clawbacks`. */
|
|
41
|
+
events: LedgerEvent[];
|
|
42
|
+
clawbacks: ClawbackRequest[];
|
|
43
|
+
weights: RcaWeight[];
|
|
44
|
+
/** Attributions that could not be applied, each with the reason. */
|
|
45
|
+
skipped: string[];
|
|
46
|
+
/** Human-readable plan, one line per decision. ASCII. */
|
|
47
|
+
breakdown: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Expand a structured RCA into ledger events (5.7 step 3):
|
|
51
|
+
*
|
|
52
|
+
* - primary DEV -> D13 -25, plus D14 -20 (producer) and/or D15 -10 (consumer_unverified);
|
|
53
|
+
* - oversight -> R9 -20 (review_integration), T4 -15 (test_defect), T10 -15
|
|
54
|
+
* (test_boundary); a missing `miss` defaults by role (REV R9, TEST T10);
|
|
55
|
+
* - contributing -> reported with weight 0.3, no event of its own;
|
|
56
|
+
* - everyone active -> C2 -5 (-2 for non-primary) or, when systemic, C4 -15 instead;
|
|
57
|
+
* - fix cycles >= 3 -> C3 -10 for everyone;
|
|
58
|
+
* - every primary has the phase's escrow clawed back.
|
|
59
|
+
*
|
|
60
|
+
* `boundary = false` is an individual bug: nothing is booked.
|
|
61
|
+
*/
|
|
62
|
+
export declare function expandRca(rca: RcaInput, ctx: RcaContext): RcaExpansion;
|
|
63
|
+
/**
|
|
64
|
+
* Report lines AFTER booking: what the cap actually did. The inspector must state any
|
|
65
|
+
* `capped` row in the settle summary (AC-17), so the engine hands it ready-made text.
|
|
66
|
+
*/
|
|
67
|
+
export declare function summarizeIncident(outcome: IncidentOutcome): string[];
|
|
68
|
+
export {};
|