pi-daddy 0.18.1 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +201 -0
- package/README.md +136 -23
- package/contracts/ledger/v2/README.md +59 -0
- package/contracts/ledger/v2/fixtures/capability-decision.json +95 -0
- package/contracts/ledger/v2/fixtures/check-receipt.json +40 -0
- package/contracts/ledger/v2/fixtures/child-lifecycle.json +42 -0
- package/contracts/ledger/v2/fixtures/workspace-lease.json +41 -0
- package/contracts/ledger/v2/ledger-event.schema.json +633 -0
- package/contracts/ledger/v3/README.md +36 -0
- package/contracts/ledger/v3/fixtures/capability-decision.json +98 -0
- package/contracts/ledger/v3/fixtures/check-receipt.json +42 -0
- package/contracts/ledger/v3/fixtures/child-lifecycle.json +45 -0
- package/contracts/ledger/v3/fixtures/workflow-fact.json +41 -0
- package/contracts/ledger/v3/fixtures/workspace-lease.json +43 -0
- package/contracts/ledger/v3/ledger-event.schema.json +930 -0
- package/dist/approval-prompt.d.ts +2 -1
- package/dist/approval-prompt.d.ts.map +1 -1
- package/dist/approval-prompt.js +9 -0
- package/dist/approval-prompt.js.map +1 -1
- package/dist/approval.d.ts +4 -2
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +4 -0
- package/dist/approval.js.map +1 -1
- package/dist/capabilities.d.ts +90 -0
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +114 -3
- package/dist/capabilities.js.map +1 -1
- package/dist/catalog.d.ts +15 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +54 -3
- package/dist/catalog.js.map +1 -1
- package/dist/check-runner.d.ts.map +1 -1
- package/dist/check-runner.js +19 -7
- package/dist/check-runner.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -1
- package/dist/cli.js.map +1 -1
- package/dist/correlation.d.ts.map +1 -1
- package/dist/correlation.js +10 -0
- package/dist/correlation.js.map +1 -1
- package/dist/dashboard-cli.d.ts +18 -0
- package/dist/dashboard-cli.d.ts.map +1 -0
- package/dist/dashboard-cli.js +154 -0
- package/dist/dashboard-cli.js.map +1 -0
- package/dist/dashboard-handshake.d.ts +37 -0
- package/dist/dashboard-handshake.d.ts.map +1 -0
- package/dist/dashboard-handshake.js +127 -0
- package/dist/dashboard-handshake.js.map +1 -0
- package/dist/dashboard-herdr.d.ts +54 -0
- package/dist/dashboard-herdr.d.ts.map +1 -0
- package/dist/dashboard-herdr.js +286 -0
- package/dist/dashboard-herdr.js.map +1 -0
- package/dist/dashboard-projection.d.ts +73 -0
- package/dist/dashboard-projection.d.ts.map +1 -0
- package/dist/dashboard-projection.js +294 -0
- package/dist/dashboard-projection.js.map +1 -0
- package/dist/dashboard-render.d.ts +10 -0
- package/dist/dashboard-render.d.ts.map +1 -0
- package/dist/dashboard-render.js +208 -0
- package/dist/dashboard-render.js.map +1 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +7 -1
- package/dist/definitions.js.map +1 -1
- package/dist/delegate-types.d.ts +6 -2
- package/dist/delegate-types.d.ts.map +1 -1
- package/dist/delegate-types.js.map +1 -1
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +34 -4
- package/dist/delegate.js.map +1 -1
- package/dist/delegation-approval.d.ts.map +1 -1
- package/dist/delegation-approval.js +37 -12
- package/dist/delegation-approval.js.map +1 -1
- package/dist/execution-id.d.ts +6 -0
- package/dist/execution-id.d.ts.map +1 -0
- package/dist/execution-id.js +13 -0
- package/dist/execution-id.js.map +1 -0
- package/dist/executor.d.ts +2 -1
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +1 -0
- package/dist/executor.js.map +1 -1
- package/dist/grant-env.d.ts +2 -0
- package/dist/grant-env.d.ts.map +1 -1
- package/dist/grant-env.js +26 -3
- package/dist/grant-env.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +13 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +35 -2
- package/dist/init.js.map +1 -1
- package/dist/lease-helper.d.ts +58 -0
- package/dist/lease-helper.d.ts.map +1 -0
- package/dist/lease-helper.js +94 -0
- package/dist/lease-helper.js.map +1 -0
- package/dist/lease-record.d.ts +15 -3
- package/dist/lease-record.d.ts.map +1 -1
- package/dist/lease-record.js.map +1 -1
- package/dist/ledger-events.d.ts +59 -15
- package/dist/ledger-events.d.ts.map +1 -1
- package/dist/ledger-events.js +67 -5
- package/dist/ledger-events.js.map +1 -1
- package/dist/ledger-identifiers.d.ts +7 -0
- package/dist/ledger-identifiers.d.ts.map +1 -0
- package/dist/ledger-identifiers.js +20 -0
- package/dist/ledger-identifiers.js.map +1 -0
- package/dist/ledger-report.d.ts +5 -2
- package/dist/ledger-report.d.ts.map +1 -1
- package/dist/ledger-report.js +38 -14
- package/dist/ledger-report.js.map +1 -1
- package/dist/ledger-v3-validation.d.ts +11 -0
- package/dist/ledger-v3-validation.d.ts.map +1 -0
- package/dist/ledger-v3-validation.js +265 -0
- package/dist/ledger-v3-validation.js.map +1 -0
- package/dist/ledger.d.ts +27 -9
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +38 -6
- package/dist/ledger.js.map +1 -1
- package/dist/propagation.d.ts +19 -1
- package/dist/propagation.d.ts.map +1 -1
- package/dist/propagation.js +23 -1
- package/dist/propagation.js.map +1 -1
- package/dist/refusals.d.ts +1 -1
- package/dist/refusals.d.ts.map +1 -1
- package/dist/refusals.js +1 -0
- package/dist/refusals.js.map +1 -1
- package/dist/resolve.d.ts +10 -0
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +27 -3
- package/dist/resolve.js.map +1 -1
- package/dist/routing-authority.d.ts +71 -0
- package/dist/routing-authority.d.ts.map +1 -0
- package/dist/routing-authority.js +100 -0
- package/dist/routing-authority.js.map +1 -0
- package/dist/run-child.d.ts +3 -1
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +30 -2
- package/dist/run-child.js.map +1 -1
- package/dist/run-herdr.d.ts +2 -0
- package/dist/run-herdr.d.ts.map +1 -1
- package/dist/run-herdr.js +8 -0
- package/dist/run-herdr.js.map +1 -1
- package/dist/skill-packages.d.ts +11 -5
- package/dist/skill-packages.d.ts.map +1 -1
- package/dist/skill-packages.js +20 -11
- package/dist/skill-packages.js.map +1 -1
- package/dist/workflow-fact-id.d.ts +4 -0
- package/dist/workflow-fact-id.d.ts.map +1 -0
- package/dist/workflow-fact-id.js +14 -0
- package/dist/workflow-fact-id.js.map +1 -0
- package/dist/workflow-facts.d.ts +34 -0
- package/dist/workflow-facts.d.ts.map +1 -0
- package/dist/workflow-facts.js +43 -0
- package/dist/workflow-facts.js.map +1 -0
- package/dist/workspace-lease.d.ts +15 -3
- package/dist/workspace-lease.d.ts.map +1 -1
- package/dist/workspace-lease.js +81 -24
- package/dist/workspace-lease.js.map +1 -1
- package/dist/workspace.d.ts +25 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +142 -5
- package/dist/workspace.js.map +1 -1
- package/extensions/chain-ledger.ts +4 -0
- package/extensions/chain-plan.ts +98 -0
- package/extensions/delegate-chain.ts +63 -122
- package/extensions/delegation-ledger.ts +60 -0
- package/extensions/delegation.ts +20 -14
- package/extensions/execute-child.ts +85 -21
- package/extensions/execution-occurrence.ts +20 -0
- package/extensions/grants-command.ts +33 -4
- package/extensions/grants.ts +50 -1
- package/extensions/init-command.ts +33 -2
- package/extensions/run-delegation.ts +36 -56
- package/extensions/session-report.ts +13 -20
- package/extensions/session.ts +16 -3
- package/extensions/workspace-runtime.ts +44 -4
- package/herdr-plugin/herdr-plugin.toml +18 -0
- package/package.json +22 -5
- package/src/approval-prompt.ts +2 -1
- package/src/approval.ts +4 -2
- package/src/capabilities.ts +120 -4
- package/src/catalog.ts +62 -4
- package/src/check-runner.ts +24 -8
- package/src/cli.ts +24 -1
- package/src/correlation.ts +11 -0
- package/src/dashboard-cli.ts +171 -0
- package/src/dashboard-handshake.ts +185 -0
- package/src/dashboard-herdr.ts +355 -0
- package/src/dashboard-projection.ts +390 -0
- package/src/dashboard-render.ts +254 -0
- package/src/definitions.ts +7 -1
- package/src/delegate-types.ts +6 -2
- package/src/delegate.ts +43 -4
- package/src/delegation-approval.ts +37 -12
- package/src/execution-id.ts +18 -0
- package/src/executor.ts +2 -1
- package/src/grant-env.ts +39 -7
- package/src/index.ts +26 -0
- package/src/init.ts +40 -2
- package/src/lease-helper.ts +97 -0
- package/src/lease-record.ts +15 -3
- package/src/ledger-events.ts +116 -28
- package/src/ledger-identifiers.ts +21 -0
- package/src/ledger-report.ts +40 -19
- package/src/ledger-v3-validation.ts +266 -0
- package/src/ledger.ts +75 -12
- package/src/propagation.ts +24 -1
- package/src/refusals.ts +1 -0
- package/src/resolve.ts +29 -3
- package/src/routing-authority.ts +121 -0
- package/src/run-child.ts +35 -3
- package/src/run-herdr.ts +9 -0
- package/src/skill-packages.ts +20 -13
- package/src/workflow-fact-id.ts +16 -0
- package/src/workflow-facts.ts +65 -0
- package/src/workspace-lease.ts +84 -24
- package/src/workspace.ts +179 -6
package/src/ledger-events.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The v3 runtime-event half of the ledger: workspace leases, child lifecycle and check receipts, with
|
|
3
3
|
* their builders. Split out of `./ledger.ts` only to stay under the 400-line module ceiling this
|
|
4
4
|
* project enforces mechanically; `./ledger.ts` re-exports everything here, so "the ledger module"
|
|
5
5
|
* remains one import.
|
|
@@ -8,6 +8,27 @@ import { LEDGER_VERSION, type LedgerEventBase, type GrantRecord } from "./ledger
|
|
|
8
8
|
import type { ExecutorKind } from "./executor.ts";
|
|
9
9
|
import type { CorrelationMetadata } from "./correlation.ts";
|
|
10
10
|
import type { StructuredRefusal } from "./refusals.ts";
|
|
11
|
+
import { assertExecutionId } from "./execution-id.ts";
|
|
12
|
+
import type { WorkflowFactEvent } from "./workflow-facts.ts";
|
|
13
|
+
import { assertLedgerV3Wire } from "./ledger-v3-validation.ts";
|
|
14
|
+
|
|
15
|
+
export const WORKSPACE_ACCESSES = ["read", "write"] as const;
|
|
16
|
+
export type WorkspaceAccess = typeof WORKSPACE_ACCESSES[number];
|
|
17
|
+
|
|
18
|
+
export const WORKSPACE_RECOVERY_VALUES = [false, true, "unknown"] as const;
|
|
19
|
+
export type WorkspaceRecovery = typeof WORKSPACE_RECOVERY_VALUES[number];
|
|
20
|
+
|
|
21
|
+
export const CHILD_LIFECYCLE_STATES = ["starting", "running", "completed", "failed"] as const;
|
|
22
|
+
export type ChildLifecycleState = typeof CHILD_LIFECYCLE_STATES[number];
|
|
23
|
+
|
|
24
|
+
/** The complete Node signal vocabulary accepted by a v3 child-lifecycle event. */
|
|
25
|
+
export const CHILD_PROCESS_SIGNALS = [
|
|
26
|
+
"SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD", "SIGCONT", "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGIO",
|
|
27
|
+
"SIGIOT", "SIGKILL", "SIGPIPE", "SIGPOLL", "SIGPROF", "SIGPWR", "SIGQUIT", "SIGSEGV", "SIGSTKFLT",
|
|
28
|
+
"SIGSTOP", "SIGSYS", "SIGTERM", "SIGTRAP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGUNUSED", "SIGURG",
|
|
29
|
+
"SIGUSR1", "SIGUSR2", "SIGVTALRM", "SIGWINCH", "SIGXCPU", "SIGXFSZ", "SIGBREAK", "SIGLOST", "SIGINFO",
|
|
30
|
+
] as const satisfies readonly NodeJS.Signals[];
|
|
31
|
+
export type ChildProcessSignal = typeof CHILD_PROCESS_SIGNALS[number];
|
|
11
32
|
|
|
12
33
|
/**
|
|
13
34
|
* `released` is a handover this owner performed. FOUR members were added by the 0.18.0 review pass, and
|
|
@@ -20,27 +41,24 @@ import type { StructuredRefusal } from "./refusals.ts";
|
|
|
20
41
|
* `uncontended` a read lease took no kernel lock at all, so counting it as an acquisition
|
|
21
42
|
* overstated how many exclusions the kernel actually performed (R-105).
|
|
22
43
|
*/
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
| "released-unrecorded"
|
|
29
|
-
| "lost"
|
|
30
|
-
| "retained"
|
|
31
|
-
| "timeout"
|
|
32
|
-
| "recovered";
|
|
44
|
+
export const WORKSPACE_LEASE_OUTCOMES = [
|
|
45
|
+
"acquired", "uncontended", "refused", "released", "released-unrecorded", "lost", "retained", "timeout",
|
|
46
|
+
"recovered",
|
|
47
|
+
] as const;
|
|
48
|
+
export type WorkspaceLeaseOutcome = typeof WORKSPACE_LEASE_OUTCOMES[number];
|
|
33
49
|
|
|
34
50
|
export interface WorkspaceLeaseEvent extends LedgerEventBase {
|
|
35
51
|
ledgerVersion: typeof LEDGER_VERSION;
|
|
36
52
|
event: "workspace_lease";
|
|
53
|
+
executionId: string;
|
|
54
|
+
parentExecutionId: string | null;
|
|
37
55
|
childId: string;
|
|
38
56
|
workspaceId: string;
|
|
39
57
|
root: string;
|
|
40
|
-
access:
|
|
58
|
+
access: WorkspaceAccess;
|
|
41
59
|
outcome: WorkspaceLeaseOutcome;
|
|
42
60
|
/** `"unknown"` when the prior owner's record was unreadable — not evidence of a clean handover. */
|
|
43
|
-
recovered?:
|
|
61
|
+
recovered?: WorkspaceRecovery;
|
|
44
62
|
releaseReason?: string;
|
|
45
63
|
refusal?: StructuredRefusal;
|
|
46
64
|
}
|
|
@@ -48,20 +66,29 @@ export interface WorkspaceLeaseEvent extends LedgerEventBase {
|
|
|
48
66
|
export interface ChildLifecycleEvent extends LedgerEventBase {
|
|
49
67
|
ledgerVersion: typeof LEDGER_VERSION;
|
|
50
68
|
event: "child_lifecycle";
|
|
69
|
+
executionId: string;
|
|
70
|
+
parentExecutionId: string | null;
|
|
51
71
|
childId: string;
|
|
52
|
-
state:
|
|
72
|
+
state: ChildLifecycleState;
|
|
53
73
|
executor: ExecutorKind;
|
|
74
|
+
/** Bound after which a non-terminal start is known to be incomplete. */
|
|
75
|
+
deadlineAt?: string;
|
|
76
|
+
/** Herdr runtime identity is observational and never an enforcement boundary. */
|
|
77
|
+
herdrPaneId?: string;
|
|
78
|
+
herdrAgentName?: string;
|
|
54
79
|
exitCode?: number | null;
|
|
55
|
-
signal?:
|
|
56
|
-
timedOut?:
|
|
57
|
-
aborted?:
|
|
58
|
-
truncated?:
|
|
80
|
+
signal?: ChildProcessSignal | null;
|
|
81
|
+
timedOut?: true;
|
|
82
|
+
aborted?: true;
|
|
83
|
+
truncated?: true;
|
|
59
84
|
reason?: string;
|
|
60
85
|
}
|
|
61
86
|
|
|
62
87
|
export interface CheckReceiptLedgerEvent extends LedgerEventBase {
|
|
63
88
|
ledgerVersion: typeof LEDGER_VERSION;
|
|
64
89
|
event: "check_receipt";
|
|
90
|
+
executionId: string;
|
|
91
|
+
parentExecutionId: string | null;
|
|
65
92
|
childId: string;
|
|
66
93
|
receiptId: string;
|
|
67
94
|
workspaceId: string;
|
|
@@ -69,28 +96,42 @@ export interface CheckReceiptLedgerEvent extends LedgerEventBase {
|
|
|
69
96
|
treeSha: string;
|
|
70
97
|
}
|
|
71
98
|
|
|
99
|
+
export type CapabilityDecisionEvent = GrantRecord & {
|
|
100
|
+
ledgerVersion: typeof LEDGER_VERSION;
|
|
101
|
+
event: "capability_decision";
|
|
102
|
+
executionId: string;
|
|
103
|
+
parentExecutionId: string | null;
|
|
104
|
+
taskDigest: string;
|
|
105
|
+
};
|
|
106
|
+
|
|
72
107
|
export type RuntimeLedgerEvent =
|
|
73
|
-
|
|
|
108
|
+
| CapabilityDecisionEvent
|
|
74
109
|
| WorkspaceLeaseEvent
|
|
75
110
|
| ChildLifecycleEvent
|
|
76
|
-
| CheckReceiptLedgerEvent
|
|
111
|
+
| CheckReceiptLedgerEvent
|
|
112
|
+
| WorkflowFactEvent;
|
|
77
113
|
|
|
78
114
|
export function buildWorkspaceLeaseEvent(args: {
|
|
115
|
+
executionId: string;
|
|
116
|
+
parentExecutionId: string | null;
|
|
79
117
|
childId: string;
|
|
80
118
|
workspaceId: string;
|
|
81
119
|
root: string;
|
|
82
|
-
access:
|
|
120
|
+
access: WorkspaceAccess;
|
|
83
121
|
outcome: WorkspaceLeaseOutcome;
|
|
84
|
-
recovered?:
|
|
122
|
+
recovered?: WorkspaceRecovery;
|
|
85
123
|
releaseReason?: string;
|
|
86
124
|
refusal?: StructuredRefusal;
|
|
87
125
|
correlation?: CorrelationMetadata;
|
|
88
126
|
now: Date;
|
|
89
127
|
}): WorkspaceLeaseEvent {
|
|
90
|
-
|
|
128
|
+
assertEventIdentity(args);
|
|
129
|
+
return assertLedgerV3Wire({
|
|
91
130
|
ledgerVersion: LEDGER_VERSION,
|
|
92
131
|
event: "workspace_lease",
|
|
93
132
|
ts: args.now.toISOString(),
|
|
133
|
+
executionId: args.executionId,
|
|
134
|
+
parentExecutionId: args.parentExecutionId,
|
|
94
135
|
childId: args.childId,
|
|
95
136
|
workspaceId: args.workspaceId,
|
|
96
137
|
root: args.root,
|
|
@@ -104,15 +145,50 @@ export function buildWorkspaceLeaseEvent(args: {
|
|
|
104
145
|
...(args.releaseReason ? { releaseReason: args.releaseReason } : {}),
|
|
105
146
|
...(args.refusal ? { refusal: structuredClone(args.refusal) } : {}),
|
|
106
147
|
...(args.correlation ? { correlation: structuredClone(args.correlation) } : {}),
|
|
107
|
-
};
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function buildCheckReceiptLedgerEvent(args: {
|
|
152
|
+
executionId: string;
|
|
153
|
+
parentExecutionId: string | null;
|
|
154
|
+
childId: string;
|
|
155
|
+
receiptId: string;
|
|
156
|
+
workspaceId: string;
|
|
157
|
+
checkId: string;
|
|
158
|
+
treeSha: string;
|
|
159
|
+
correlation?: CorrelationMetadata;
|
|
160
|
+
now: Date;
|
|
161
|
+
}): CheckReceiptLedgerEvent {
|
|
162
|
+
assertEventIdentity(args);
|
|
163
|
+
if (!/^[a-f0-9]{64}$/i.test(args.receiptId)) {
|
|
164
|
+
throw new TypeError("receiptId must be a SHA-256 hex digest");
|
|
165
|
+
}
|
|
166
|
+
return assertLedgerV3Wire({
|
|
167
|
+
ledgerVersion: LEDGER_VERSION,
|
|
168
|
+
event: "check_receipt",
|
|
169
|
+
ts: args.now.toISOString(),
|
|
170
|
+
executionId: args.executionId,
|
|
171
|
+
parentExecutionId: args.parentExecutionId,
|
|
172
|
+
childId: args.childId,
|
|
173
|
+
receiptId: args.receiptId,
|
|
174
|
+
workspaceId: args.workspaceId,
|
|
175
|
+
checkId: args.checkId,
|
|
176
|
+
treeSha: args.treeSha,
|
|
177
|
+
...(args.correlation ? { correlation: structuredClone(args.correlation) } : {}),
|
|
178
|
+
});
|
|
108
179
|
}
|
|
109
180
|
|
|
110
181
|
export function buildChildLifecycleEvent(args: {
|
|
182
|
+
executionId: string;
|
|
183
|
+
parentExecutionId: string | null;
|
|
111
184
|
childId: string;
|
|
112
|
-
state:
|
|
185
|
+
state: ChildLifecycleState;
|
|
113
186
|
executor: ExecutorKind;
|
|
187
|
+
deadlineAt?: string;
|
|
188
|
+
herdrPaneId?: string;
|
|
189
|
+
herdrAgentName?: string;
|
|
114
190
|
exitCode?: number | null;
|
|
115
|
-
signal?:
|
|
191
|
+
signal?: ChildProcessSignal | null;
|
|
116
192
|
timedOut?: boolean;
|
|
117
193
|
aborted?: boolean;
|
|
118
194
|
truncated?: boolean;
|
|
@@ -120,13 +196,19 @@ export function buildChildLifecycleEvent(args: {
|
|
|
120
196
|
correlation?: CorrelationMetadata;
|
|
121
197
|
now: Date;
|
|
122
198
|
}): ChildLifecycleEvent {
|
|
123
|
-
|
|
199
|
+
assertEventIdentity(args);
|
|
200
|
+
return assertLedgerV3Wire({
|
|
124
201
|
ledgerVersion: LEDGER_VERSION,
|
|
125
202
|
event: "child_lifecycle",
|
|
126
203
|
ts: args.now.toISOString(),
|
|
204
|
+
executionId: args.executionId,
|
|
205
|
+
parentExecutionId: args.parentExecutionId,
|
|
127
206
|
childId: args.childId,
|
|
128
207
|
state: args.state,
|
|
129
208
|
executor: args.executor,
|
|
209
|
+
...(args.deadlineAt ? { deadlineAt: args.deadlineAt } : {}),
|
|
210
|
+
...(args.herdrPaneId ? { herdrPaneId: args.herdrPaneId } : {}),
|
|
211
|
+
...(args.herdrAgentName ? { herdrAgentName: args.herdrAgentName } : {}),
|
|
130
212
|
...(args.exitCode !== undefined ? { exitCode: args.exitCode } : {}),
|
|
131
213
|
...(args.signal !== undefined ? { signal: args.signal } : {}),
|
|
132
214
|
...(args.timedOut ? { timedOut: true } : {}),
|
|
@@ -134,5 +216,11 @@ export function buildChildLifecycleEvent(args: {
|
|
|
134
216
|
...(args.truncated ? { truncated: true } : {}),
|
|
135
217
|
...(args.reason ? { reason: args.reason } : {}),
|
|
136
218
|
...(args.correlation ? { correlation: structuredClone(args.correlation) } : {}),
|
|
137
|
-
};
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function assertEventIdentity(args: { executionId: string; parentExecutionId: string | null }): void {
|
|
223
|
+
assertExecutionId(args.executionId);
|
|
224
|
+
if (args.parentExecutionId !== null) assertExecutionId(args.parentExecutionId, "parentExecutionId");
|
|
225
|
+
if (args.parentExecutionId === args.executionId) throw new TypeError("an execution cannot be its own parent");
|
|
138
226
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const DISPLAY_IDENTIFIER = /^[A-Za-z0-9@*][A-Za-z0-9@*._:/-]{0,511}$/;
|
|
2
|
+
const CORRELATION_IDENTIFIER = /^[A-Za-z0-9@*][A-Za-z0-9@*._:/-]{0,127}$/;
|
|
3
|
+
const CAPABILITY_TAIL = /^[A-Za-z0-9@*][A-Za-z0-9@*._/-]{0,255}$/;
|
|
4
|
+
const CAPABILITY_PREFIXES = ["tool:", "skill:", "agent:", "workspace:", "ext:"] as const;
|
|
5
|
+
|
|
6
|
+
/** Identifier text safe to copy onto the operator's terminal; prose belongs in no ledger display field. */
|
|
7
|
+
export function isLedgerDisplayIdentifier(value: unknown): value is string {
|
|
8
|
+
return typeof value === "string" && DISPLAY_IDENTIFIER.test(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** The tighter bound for model-facing correlation labels that are copied onto every event. */
|
|
12
|
+
export function isLedgerCorrelationIdentifier(value: unknown): value is string {
|
|
13
|
+
return typeof value === "string" && CORRELATION_IDENTIFIER.test(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** A namespaced capability id with an ASCII, non-prose tail. Namespace wildcards remain representable. */
|
|
17
|
+
export function isLedgerCapabilityIdentifier(value: unknown): value is string {
|
|
18
|
+
if (typeof value !== "string") return false;
|
|
19
|
+
const prefix = CAPABILITY_PREFIXES.find((candidate) => value.startsWith(candidate));
|
|
20
|
+
return Boolean(prefix && CAPABILITY_TAIL.test(value.slice(prefix.length)));
|
|
21
|
+
}
|
package/src/ledger-report.ts
CHANGED
|
@@ -18,11 +18,13 @@ import type { ApprovalSource } from "./approval.ts";
|
|
|
18
18
|
import type { GrantRecord } from "./ledger.ts";
|
|
19
19
|
import { isEscalationAttempt } from "./ledger.ts";
|
|
20
20
|
import type { WorkspaceLeaseOutcome } from "./ledger-events.ts";
|
|
21
|
+
import { isExecutionId } from "./execution-id.ts";
|
|
22
|
+
import { validateLedgerV3Event } from "./ledger-v3-validation.ts";
|
|
21
23
|
|
|
22
24
|
export interface LedgerReport {
|
|
23
25
|
/** False when the file is absent — a configuration state, not damage. */
|
|
24
26
|
exists: boolean;
|
|
25
|
-
/** Capability-decision records (legacy or
|
|
27
|
+
/** Capability-decision records (legacy, v2, or v3). */
|
|
26
28
|
records: number;
|
|
27
29
|
/** Every parsed ledger event, including lifecycle and lease events. */
|
|
28
30
|
events: number;
|
|
@@ -30,9 +32,11 @@ export interface LedgerReport {
|
|
|
30
32
|
acquired: number; uncontended: number; refused: number; released: number;
|
|
31
33
|
releasedUnrecorded: number; lost: number; retained: number; timeout: number; recovered: number;
|
|
32
34
|
};
|
|
33
|
-
lifecycle: { starting: number; completed: number; failed: number };
|
|
35
|
+
lifecycle: { starting: number; running: number; completed: number; failed: number };
|
|
36
|
+
/** Planned/observed/controller-validated facts; never counted as enforced child executions. */
|
|
37
|
+
workflowFacts: number;
|
|
34
38
|
/** Lines that did not, with 1-based line numbers so the report is actionable. */
|
|
35
|
-
corrupt: Array<{ line: number;
|
|
39
|
+
corrupt: Array<{ line: number; reason: string }>;
|
|
36
40
|
/** Records where an agent asked for more than it held — ADR-0008's designated signal. */
|
|
37
41
|
escalationAttempts: number;
|
|
38
42
|
/**
|
|
@@ -139,18 +143,20 @@ const LEASE_OUTCOME_COUNTERS: Record<WorkspaceLeaseOutcome, keyof LedgerReport["
|
|
|
139
143
|
recovered: "recovered",
|
|
140
144
|
};
|
|
141
145
|
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
function requireV2(event: Record<string, unknown>, fields: string[]): void {
|
|
147
|
-
if (!validV2Base(event) || fields.some((field) => typeof event[field] !== "string" || event[field] === "")) {
|
|
146
|
+
function requireVersioned(event: Record<string, unknown>, fields: string[]): void {
|
|
147
|
+
if ((event.ledgerVersion !== 2 && event.ledgerVersion !== 3) || typeof event.ts !== "string" ||
|
|
148
|
+
fields.some((field) => typeof event[field] !== "string" || event[field] === "")) {
|
|
148
149
|
throw new Error("invalid versioned ledger event");
|
|
149
150
|
}
|
|
151
|
+
if (event.ledgerVersion === 3 &&
|
|
152
|
+
(!isExecutionId(event.executionId) ||
|
|
153
|
+
(event.parentExecutionId !== null && !isExecutionId(event.parentExecutionId)))) {
|
|
154
|
+
throw new Error("invalid v3 execution identity");
|
|
155
|
+
}
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
function requireCapabilityDecision(event: Record<string, unknown>): void {
|
|
153
|
-
|
|
159
|
+
requireVersioned(event, ["parentId", "childId", "executor", "taskDigest"]);
|
|
154
160
|
for (const field of ["requested", "parentGrant", "effective", "denied", "clipped", "gatedBlocked"]) {
|
|
155
161
|
if (!Array.isArray(event[field]) || !(event[field] as unknown[]).every((value) => typeof value === "string")) {
|
|
156
162
|
throw new Error("invalid capability decision arrays");
|
|
@@ -172,7 +178,8 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
172
178
|
records: 0,
|
|
173
179
|
events: 0,
|
|
174
180
|
workspaceLeases: { acquired: 0, uncontended: 0, refused: 0, released: 0, releasedUnrecorded: 0, lost: 0, retained: 0, timeout: 0, recovered: 0 },
|
|
175
|
-
lifecycle: { starting: 0, completed: 0, failed: 0 },
|
|
181
|
+
lifecycle: { starting: 0, running: 0, completed: 0, failed: 0 },
|
|
182
|
+
workflowFacts: 0,
|
|
176
183
|
corrupt: [],
|
|
177
184
|
escalationAttempts: 0,
|
|
178
185
|
executors: { herdr: 0, process: 0, unknown: 0 },
|
|
@@ -190,13 +197,14 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
190
197
|
throw error;
|
|
191
198
|
}
|
|
192
199
|
|
|
193
|
-
const corrupt: Array<{ line: number;
|
|
200
|
+
const corrupt: Array<{ line: number; reason: string }> = [];
|
|
194
201
|
// Keyed by name+digest: one name with two entries is the signal that the definition changed mid-ledger.
|
|
195
202
|
const digests = new Map<string, { name: string; source: string; sha256: string; spawns: number }>();
|
|
196
203
|
let records = 0;
|
|
197
204
|
let events = 0;
|
|
198
205
|
const workspaceLeases = { acquired: 0, uncontended: 0, refused: 0, released: 0, releasedUnrecorded: 0, lost: 0, retained: 0, timeout: 0, recovered: 0 };
|
|
199
|
-
const lifecycle = { starting: 0, completed: 0, failed: 0 };
|
|
206
|
+
const lifecycle = { starting: 0, running: 0, completed: 0, failed: 0 };
|
|
207
|
+
let workflowFacts = 0;
|
|
200
208
|
let escalationAttempts = 0;
|
|
201
209
|
const executors = { herdr: 0, process: 0, unknown: 0 };
|
|
202
210
|
const bySource: Record<ApprovalSource, number> = { prompt: 0, session: 0, persisted: 0, inherited: 0 };
|
|
@@ -217,11 +225,21 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
217
225
|
if (raw.trim().length === 0) return;
|
|
218
226
|
try {
|
|
219
227
|
const event = JSON.parse(raw) as Record<string, unknown>;
|
|
220
|
-
if (event.ledgerVersion !== undefined
|
|
221
|
-
throw new Error("versioned ledger line has no event discriminator");
|
|
228
|
+
if (event.ledgerVersion !== undefined) {
|
|
229
|
+
if (event.event === undefined) throw new Error("versioned ledger line has no event discriminator");
|
|
230
|
+
if (event.ledgerVersion !== 2 && event.ledgerVersion !== 3) throw new Error("unsupported ledger version");
|
|
231
|
+
if (event.ledgerVersion === 3 && validateLedgerV3Event(event)) throw new Error("invalid ledger v3 event");
|
|
232
|
+
}
|
|
233
|
+
if (event.event === "workflow_fact") {
|
|
234
|
+
// v2 has no workflow facts; the exact v3 validator above already checked its vocabulary,
|
|
235
|
+
// correlation and provenance/state relation.
|
|
236
|
+
if (event.ledgerVersion !== 3) throw new Error("invalid workflow fact event");
|
|
237
|
+
workflowFacts += 1;
|
|
238
|
+
events += 1;
|
|
239
|
+
return;
|
|
222
240
|
}
|
|
223
241
|
if (event.event === "workspace_lease") {
|
|
224
|
-
|
|
242
|
+
requireVersioned(event, ["childId", "workspaceId", "root", "access"]);
|
|
225
243
|
const outcome = typeof event.outcome === "string" ? event.outcome : "";
|
|
226
244
|
// Explicit map, not a name match: the ledger's outcome vocabulary and these counter names are
|
|
227
245
|
// allowed to differ, and a valid event must never be counted as corruption because a counter
|
|
@@ -235,7 +253,7 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
235
253
|
return;
|
|
236
254
|
}
|
|
237
255
|
if (event.event === "child_lifecycle") {
|
|
238
|
-
|
|
256
|
+
requireVersioned(event, ["childId", "executor"]);
|
|
239
257
|
const state = typeof event.state === "string" ? event.state : "";
|
|
240
258
|
if (!Object.hasOwn(lifecycle, state)) throw new Error("invalid child lifecycle event");
|
|
241
259
|
lifecycle[state as keyof typeof lifecycle] += 1;
|
|
@@ -243,7 +261,7 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
243
261
|
return;
|
|
244
262
|
}
|
|
245
263
|
if (event.event === "check_receipt") {
|
|
246
|
-
|
|
264
|
+
requireVersioned(event, ["childId", "receiptId", "workspaceId", "checkId", "treeSha"]);
|
|
247
265
|
events += 1;
|
|
248
266
|
return;
|
|
249
267
|
}
|
|
@@ -305,7 +323,9 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
305
323
|
else digests.set(key, { name: d.name, source: d.source, sha256: d.sha256, spawns: 1 });
|
|
306
324
|
}
|
|
307
325
|
} catch {
|
|
308
|
-
|
|
326
|
+
// Content-free by contract: a torn or foreign line can contain exactly the task/output material the
|
|
327
|
+
// ledger and dashboard promise never to expose. The line number locates the evidence without copying it.
|
|
328
|
+
corrupt.push({ line: index + 1, reason: "invalid ledger line" });
|
|
309
329
|
}
|
|
310
330
|
});
|
|
311
331
|
|
|
@@ -315,6 +335,7 @@ export async function verifyLedger(path: string): Promise<LedgerReport> {
|
|
|
315
335
|
events,
|
|
316
336
|
workspaceLeases,
|
|
317
337
|
lifecycle,
|
|
338
|
+
workflowFacts,
|
|
318
339
|
corrupt,
|
|
319
340
|
escalationAttempts,
|
|
320
341
|
executors,
|