@astrosheep/keiyaku 2.8.4 → 2.9.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/README.md +35 -15
- package/build/.tsbuildinfo +1 -1
- package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
- package/build/agents/harness/control-types.js +1 -0
- package/build/agents/harness/execution-handle.js +23 -3
- package/build/agents/harness/index.js +6 -607
- package/build/agents/harness/outcome.js +141 -0
- package/build/agents/harness/projection.js +310 -0
- package/build/agents/harness/router.js +201 -0
- package/build/agents/harness/runtime.js +2 -1
- package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
- package/build/agents/launch-snapshot/resolve.js +72 -0
- package/build/agents/opencode-sdk.js +24 -3
- package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
- package/build/agents/providers/claude-agent-sdk/events.js +218 -0
- package/build/agents/providers/claude-agent-sdk/session.js +158 -0
- package/build/agents/providers/codex-app-server/adapter.js +347 -0
- package/build/agents/providers/codex-app-server/events.js +352 -0
- package/build/agents/providers/codex-app-server/session.js +266 -0
- package/build/agents/providers/codex-sdk.js +23 -5
- package/build/agents/providers/opencode-sdk/adapter.js +344 -0
- package/build/agents/providers/opencode-sdk/events.js +354 -0
- package/build/agents/providers/opencode-sdk/session.js +180 -0
- package/build/agents/providers/pi/adapter.js +269 -0
- package/build/agents/providers/pi/checkpoint.js +41 -0
- package/build/agents/providers/pi/events.js +282 -0
- package/build/agents/{selector_v2.js → selector.js} +8 -6
- package/build/cli/commands/akuma/akuma/handler.js +4 -0
- package/build/cli/commands/akuma/akuma/meta.js +16 -0
- package/build/cli/commands/akuma/catalog.js +8 -0
- package/build/cli/commands/akuma/list/handler.js +15 -0
- package/build/cli/commands/akuma/list/meta-ls.js +9 -0
- package/build/cli/commands/akuma/view/handler.js +34 -0
- package/build/cli/commands/akuma/view/meta.js +8 -0
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +10 -0
- package/build/cli/commands/contract/amend/meta.js +12 -0
- package/build/cli/commands/contract/arc/handler.js +9 -0
- package/build/cli/commands/contract/arc/meta.js +26 -0
- package/build/cli/commands/contract/bind/handler.js +23 -0
- package/build/cli/commands/contract/bind/meta.js +30 -0
- package/build/cli/commands/contract/catalog.js +16 -0
- package/build/cli/commands/contract/forfeit/handler.js +13 -0
- package/build/cli/commands/contract/forfeit/meta.js +12 -0
- package/build/cli/commands/contract/log/handler.js +12 -0
- package/build/cli/commands/contract/log/meta.js +12 -0
- package/build/cli/commands/contract/petition/handler.js +26 -0
- package/build/cli/commands/contract/petition/meta.js +23 -0
- package/build/cli/commands/contract/renew/handler.js +10 -0
- package/build/cli/commands/contract/renew/meta.js +17 -0
- package/build/cli/commands/projection/call/handler.js +39 -0
- package/build/cli/commands/projection/call/meta.js +9 -0
- package/build/cli/commands/projection/catalog.js +14 -0
- package/build/cli/commands/projection/kill/handler.js +35 -0
- package/build/cli/commands/projection/kill/meta.js +11 -0
- package/build/cli/commands/projection/revive/handler.js +53 -0
- package/build/cli/commands/projection/revive/meta.js +9 -0
- package/build/cli/commands/projection/status/handler.js +23 -0
- package/build/cli/commands/projection/status/meta.js +9 -0
- package/build/cli/commands/projection/tell/handler.js +34 -0
- package/build/cli/commands/projection/tell/meta.js +9 -0
- package/build/cli/commands/projection/wait/handler.js +21 -0
- package/build/cli/commands/projection/wait/meta.js +11 -0
- package/build/cli/commands/registry.js +100 -0
- package/build/cli/commands/shared.js +71 -0
- package/build/cli/commands/skills/catalog.js +6 -0
- package/build/cli/commands/skills/install/handler.js +10 -0
- package/build/cli/commands/skills/install/meta.js +9 -0
- package/build/cli/commands/skills/skills/handler.js +4 -0
- package/build/cli/commands/skills/skills/meta.js +10 -0
- package/build/cli/commands/system/catalog.js +8 -0
- package/build/cli/commands/system/completion/handler.js +10 -0
- package/build/cli/commands/system/completion/meta.js +9 -0
- package/build/cli/commands/system/dump-env/handler.js +3 -0
- package/build/cli/commands/system/dump-env/meta.js +10 -0
- package/build/cli/commands/system/guide/handler.js +4 -0
- package/build/cli/commands/system/guide/meta.js +9 -0
- package/build/cli/commands/task/add/handler.js +21 -0
- package/build/cli/commands/task/add/meta.js +8 -0
- package/build/cli/commands/task/catalog.js +22 -0
- package/build/cli/commands/task/doctor/handler.js +4 -0
- package/build/cli/commands/task/doctor/meta.js +8 -0
- package/build/cli/commands/task/done/handler.js +17 -0
- package/build/cli/commands/task/done/meta.js +8 -0
- package/build/cli/commands/task/drop/handler.js +6 -0
- package/build/cli/commands/task/drop/meta.js +8 -0
- package/build/cli/commands/task/ls/handler.js +13 -0
- package/build/cli/commands/task/ls/meta.js +8 -0
- package/build/cli/commands/task/shared.js +131 -0
- package/build/cli/commands/task/start/handler.js +6 -0
- package/build/cli/commands/task/start/meta.js +8 -0
- package/build/cli/commands/task/stop/handler.js +17 -0
- package/build/cli/commands/task/stop/meta.js +8 -0
- package/build/cli/commands/task/task/handler.js +5 -0
- package/build/cli/commands/task/task/meta.js +11 -0
- package/build/cli/commands/task/update/handler.js +18 -0
- package/build/cli/commands/task/update/meta.js +8 -0
- package/build/cli/commands/task/view/handler.js +14 -0
- package/build/cli/commands/task/view/meta.js +8 -0
- package/build/cli/completion.js +26 -27
- package/build/cli/flags.js +79 -2
- package/build/cli/help.js +27 -49
- package/build/cli/index.js +121 -374
- package/build/cli/output-stream-error-policy.js +17 -0
- package/build/cli/parse.js +159 -72
- package/build/cli/projection-address.js +5 -0
- package/build/cli/render/arc.js +1 -1
- package/build/cli/render/errors.js +4 -3
- package/build/cli/render/format.js +14 -0
- package/build/cli/render/kanshi.js +106 -0
- package/build/cli/render/petition.js +24 -1
- package/build/cli/render/projection-activity.js +5 -1
- package/build/cli/render/shared.js +2 -2
- package/build/cli/render/status.js +79 -13
- package/build/cli/render/task.js +113 -0
- package/build/cli/render/wait.js +23 -3
- package/build/cli/types.js +1 -1
- package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
- package/build/config/env.js +9 -4
- package/build/config/settings/disease.js +26 -0
- package/build/config/settings/knobs.js +8 -0
- package/build/config/settings/loader.js +244 -0
- package/build/config/settings/schema.js +276 -0
- package/build/core/addressing.js +1 -1
- package/build/core/amend.js +3 -3
- package/build/core/arc.js +5 -4
- package/build/core/bind-workspace.js +123 -0
- package/build/core/bind.js +75 -155
- package/build/core/call/call.js +224 -0
- package/build/core/call/context.js +238 -0
- package/build/core/call/execution.js +217 -0
- package/build/core/call/prompt.js +42 -0
- package/build/core/call/reference.js +24 -0
- package/build/core/call-persist.js +1 -1
- package/build/core/claim-delivery.js +247 -0
- package/build/core/claim.js +39 -277
- package/build/core/context.js +2 -1
- package/build/core/{render.js → contract-view.js} +12 -140
- package/build/core/draft.js +107 -9
- package/build/core/entry.js +9 -1
- package/build/core/execution-coordinate.js +4 -20
- package/build/core/execution-pact.js +16 -31
- package/build/core/forfeit.js +35 -22
- package/build/core/hints.js +2 -2
- package/build/core/log.js +2 -2
- package/build/core/petition-claim-gates.js +8 -6
- package/build/core/petition-preview.js +97 -0
- package/build/core/petition-run.js +3 -2
- package/build/core/petition.js +39 -26
- package/build/core/projection/generation/database.js +306 -0
- package/build/core/projection/generation/identity.js +84 -0
- package/build/core/projection/generation/model.js +201 -0
- package/build/core/projection/generation/store.js +73 -0
- package/build/core/projection/generation/transitions.js +258 -0
- package/build/core/projection/heart.js +0 -307
- package/build/core/projection/tell/database.js +109 -0
- package/build/core/projection/tell/model.js +97 -0
- package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
- package/build/core/projection-activity.js +23 -2
- package/build/core/projection-core.js +2 -1
- package/build/core/projection-execution-observer.js +259 -0
- package/build/core/projection-generation-continuation.js +1 -1
- package/build/core/projection-generation-execution.js +90 -20
- package/build/core/projection-generation-launcher.js +1 -1
- package/build/core/projection-generation-runner.js +198 -4
- package/build/core/projection-identity.js +1 -1
- package/build/core/projection-kill.js +50 -17
- package/build/core/projection-life-observer.js +1 -1
- package/build/core/projection-life-protocol.js +10 -0
- package/build/core/projection-mint.js +1 -1
- package/build/core/projection-status.js +45 -32
- package/build/core/projection-wait.js +12 -2
- package/build/core/projection-wake.js +5 -2
- package/build/core/{queue_v2.js → queue.js} +2 -1
- package/build/core/registry.js +1 -1
- package/build/core/renew.js +7 -7
- package/build/core/response-artifact-catalog-sqlite.js +112 -0
- package/build/core/response-artifact-catalog.js +7 -0
- package/build/core/seal.js +44 -16
- package/build/core/status/board.js +286 -0
- package/build/core/status/drift.js +99 -0
- package/build/core/status/lifecycle.js +84 -0
- package/build/core/status/reconciliation.js +131 -0
- package/build/core/stored-agent-event.js +28 -4
- package/build/core/target-ref.js +10 -0
- package/build/core/task/board.js +175 -0
- package/build/core/task/commands.js +211 -0
- package/build/core/task/document.js +189 -0
- package/build/core/task/model.js +1 -0
- package/build/core/task/settlement-git.js +207 -0
- package/build/core/task/settlement-policy.js +82 -0
- package/build/core/task/source-board.js +84 -0
- package/build/core/task/source-model.js +1 -0
- package/build/core/task/validation.js +44 -0
- package/build/core/task-contract.js +224 -0
- package/build/core/task-doctor.js +14 -0
- package/build/core/task-git-actor.js +38 -0
- package/build/core/task-git-runtime.js +34 -0
- package/build/core/task-git-store.js +375 -0
- package/build/core/task-repository.js +1 -0
- package/build/core/task-store-repository.js +86 -0
- package/build/core/task-store.js +1 -0
- package/build/core/task-worktree.js +51 -0
- package/build/core/task.js +4 -0
- package/build/core/transcripts.js +138 -56
- package/build/core/validation.js +17 -0
- package/build/core/verdict.js +2 -2
- package/build/core/worktree-path.js +24 -6
- package/build/flow-error.js +3 -2
- package/build/generated/version.js +1 -1
- package/build/git/commits.js +3 -0
- package/build/git/diff/parsers.js +0 -94
- package/build/index.js +2 -0
- package/build/keiyaku-constants.js +2 -0
- package/build/keiyaku.js +4 -3
- package/package.json +3 -2
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +11 -6
- package/build/agents/harness/pump.js +0 -158
- package/build/agents/providers/codex-app-server.js +0 -864
- package/build/agents/providers/opencode-sdk.js +0 -363
- package/build/agents/providers/pi.js +0 -557
- package/build/config/settings.js +0 -533
- package/build/core/call.js +0 -686
- package/build/core/projection/generation.js +0 -412
- package/build/core/projection/identity.js +0 -81
- package/build/core/projection/mint.js +0 -174
- package/build/core/projection-generation-store.js +0 -707
- package/build/core/status.js +0 -539
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createOathGate } from "./petition-claim-gates.js";
|
|
2
|
+
import { assertPetitionArcReady, assertPetitionFresh, assertPetitionable, loadPetitionPreflightContext, } from "./petition.js";
|
|
3
|
+
import { petitionSealSource, previewSeal } from "./seal.js";
|
|
4
|
+
export const PETITION_PREVIEW_GATE_NAMES = [
|
|
5
|
+
"contract",
|
|
6
|
+
"freshness",
|
|
7
|
+
"arc",
|
|
8
|
+
"state",
|
|
9
|
+
"seal",
|
|
10
|
+
"oath",
|
|
11
|
+
"verification",
|
|
12
|
+
"review",
|
|
13
|
+
];
|
|
14
|
+
function failureDetail(error) {
|
|
15
|
+
return error instanceof Error ? error.message : String(error);
|
|
16
|
+
}
|
|
17
|
+
async function gate(name, evaluate) {
|
|
18
|
+
try {
|
|
19
|
+
await evaluate();
|
|
20
|
+
return { name, result: "pass" };
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return { name, result: "failed", detail: failureDetail(error) };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function sealPathDetail(paths) {
|
|
27
|
+
return `${paths.length} ${paths.length === 1 ? "file" : "files"} · ${paths.length > 0 ? paths.join(", ") : "(none)"}`;
|
|
28
|
+
}
|
|
29
|
+
const notEvaluated = (name) => ({
|
|
30
|
+
name,
|
|
31
|
+
result: "not_evaluated",
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Build a petition preflight without crossing any settlement or provider boundary.
|
|
35
|
+
* Loading the addressed contract is construction: failure there leaves no truthful
|
|
36
|
+
* target/source coordinate and therefore propagates as dry-run exit 2.
|
|
37
|
+
*/
|
|
38
|
+
export async function previewPetition(input) {
|
|
39
|
+
const context = await loadPetitionPreflightContext(input.cwd, input.contractId);
|
|
40
|
+
const gates = [{ name: "contract", result: "pass" }];
|
|
41
|
+
const freshness = await gate("freshness", async () => {
|
|
42
|
+
await assertPetitionFresh(input.cwd, input.contractId, context.ledger.entries, context.base);
|
|
43
|
+
});
|
|
44
|
+
gates.push(freshness);
|
|
45
|
+
const arc = freshness.result === "pass"
|
|
46
|
+
? await gate("arc", async () => {
|
|
47
|
+
await assertPetitionArcReady(context.deliveryCwd, input.contractId, context.ledger.entries);
|
|
48
|
+
})
|
|
49
|
+
: notEvaluated("arc");
|
|
50
|
+
gates.push(arc);
|
|
51
|
+
const state = await gate("state", () => {
|
|
52
|
+
assertPetitionable(input.contractId, context.ledger.entries);
|
|
53
|
+
});
|
|
54
|
+
gates.push(state);
|
|
55
|
+
let seal;
|
|
56
|
+
if (freshness.result === "pass" && arc.result === "pass" && state.result === "pass") {
|
|
57
|
+
try {
|
|
58
|
+
const sealPreview = await previewSeal(context.deliveryCwd, context.ledger.entries, "HEAD", input.waivePaths);
|
|
59
|
+
seal = { name: "seal", result: "pass", detail: sealPathDetail(sealPreview.paths) };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
seal = { name: "seal", result: "failed", detail: failureDetail(error) };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
seal = notEvaluated("seal");
|
|
67
|
+
}
|
|
68
|
+
gates.push(seal);
|
|
69
|
+
const oathOwner = createOathGate();
|
|
70
|
+
const oath = await gate("oath", async () => {
|
|
71
|
+
const result = await oathOwner.evaluate({
|
|
72
|
+
cwd: input.cwd,
|
|
73
|
+
contractId: input.contractId,
|
|
74
|
+
input: {
|
|
75
|
+
cwd: input.cwd,
|
|
76
|
+
contractId: input.contractId,
|
|
77
|
+
intent: "CLAIM",
|
|
78
|
+
title: `Petition ${input.contractId}`,
|
|
79
|
+
plea: `Settle contract ${input.contractId} through the petition pipeline.`,
|
|
80
|
+
oath: input.oath,
|
|
81
|
+
},
|
|
82
|
+
verificationCommands: [],
|
|
83
|
+
baseBranch: context.target.branch,
|
|
84
|
+
reviewNumber: 0,
|
|
85
|
+
});
|
|
86
|
+
if (!result.pass)
|
|
87
|
+
throw new Error(result.message);
|
|
88
|
+
});
|
|
89
|
+
gates.push(oath, notEvaluated("verification"), notEvaluated("review"));
|
|
90
|
+
return {
|
|
91
|
+
contract: input.contractId,
|
|
92
|
+
target: context.target.ref,
|
|
93
|
+
arc: { source: petitionSealSource(context.ledger.entries) },
|
|
94
|
+
gates,
|
|
95
|
+
verdict: gates.some((item) => item.result === "failed") ? "would_fail" : "would_succeed",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { assertSettingsKnobUsable
|
|
1
|
+
import { assertSettingsKnobUsable } from "../config/settings/disease.js";
|
|
2
|
+
import { loadKeiyakuSettings } from "../config/settings/loader.js";
|
|
2
3
|
import { FlowError } from "../flow-error.js";
|
|
3
4
|
import { readCurrentContractContext } from "./context.js";
|
|
4
5
|
import { readLedger } from "./ledger.js";
|
|
5
|
-
import { commissionTarget } from "./status.js";
|
|
6
|
+
import { commissionTarget } from "./status/drift.js";
|
|
6
7
|
import { getCurrentBranch, isGitRepo } from "../git/branches.js";
|
|
7
8
|
import { claimKeiyaku } from "./petition-claim.js";
|
|
8
9
|
import { forfeitKeiyaku } from "./petition-forfeit.js";
|
package/build/core/petition.js
CHANGED
|
@@ -2,9 +2,10 @@ import { FlowError } from "../flow-error.js";
|
|
|
2
2
|
import { createGit, errorContainsAnyPattern, MISSING_HEAD_PATTERNS, wrapGitError } from "../git/core.js";
|
|
3
3
|
import { parseCommandMarkdown } from "./command-io.js";
|
|
4
4
|
import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
|
|
5
|
-
import { allocateSettlementSeat, queueMembership, readQueueReadModel } from "./
|
|
6
|
-
import { findOpenArc, receiptsAfterFence,
|
|
7
|
-
import {
|
|
5
|
+
import { allocateSettlementSeat, queueMembership, readQueueReadModel } from "./queue.js";
|
|
6
|
+
import { findOpenArc, getMaxArc, receiptsAfterFence, sealCurrentArc } from "./seal.js";
|
|
7
|
+
import { deriveContractState } from "./status/lifecycle.js";
|
|
8
|
+
import { commissionTarget, latestBase } from "./status/drift.js";
|
|
8
9
|
import { findContractWorktreePath } from "./worktree-path.js";
|
|
9
10
|
async function resolveCommit(cwd, ref) {
|
|
10
11
|
const git = createGit(cwd);
|
|
@@ -17,7 +18,26 @@ async function resolveCommit(cwd, ref) {
|
|
|
17
18
|
throw wrapGitError(`rev-parse ${ref}`, error, cwd);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
|
-
async function
|
|
21
|
+
export async function loadPetitionPreflightContext(cwd, contractId) {
|
|
22
|
+
const ledger = await readLedger(cwd, contractId);
|
|
23
|
+
if (!ledger) {
|
|
24
|
+
throw new FlowError("INTERNAL_STATE", `contract ${contractId} not found or not active`);
|
|
25
|
+
}
|
|
26
|
+
const base = latestBase(ledger.entries);
|
|
27
|
+
if (!base)
|
|
28
|
+
throw new FlowError("INTERNAL_STATE", "ledger must contain bind entry");
|
|
29
|
+
const target = commissionTarget(ledger.entries);
|
|
30
|
+
if (!target) {
|
|
31
|
+
throw new FlowError("INTERNAL_STATE", `contract ${contractId} missing commission target`);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
ledger,
|
|
35
|
+
deliveryCwd: (await findContractWorktreePath(cwd, contractId)) ?? cwd,
|
|
36
|
+
base,
|
|
37
|
+
target,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export async function assertPetitionFresh(cwd, contractId, entries, base) {
|
|
21
41
|
const target = commissionTarget(entries);
|
|
22
42
|
if (!target) {
|
|
23
43
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} missing commission target`);
|
|
@@ -30,31 +50,28 @@ async function assertFresh(cwd, contractId, entries, base) {
|
|
|
30
50
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} must renew onto ${target.branch} before petition`, { hints: [`keiyaku @${contractId} renew — renews delivery before petition`] });
|
|
31
51
|
}
|
|
32
52
|
}
|
|
33
|
-
function
|
|
53
|
+
export async function assertPetitionArcReady(deliveryCwd, contractId, entries) {
|
|
54
|
+
if (getMaxArc(entries) <= 0 || findOpenArc(entries))
|
|
55
|
+
return;
|
|
56
|
+
const loose = await receiptsAfterFence(deliveryCwd, entries);
|
|
57
|
+
if (loose.length > 0) {
|
|
58
|
+
throw new FlowError("NO_OPEN_ARC", `${loose.length} commits after fence have no arc to receipt them`, { hints: [`keiyaku @${contractId} arc — opens a new arc to receipt them, then petition`] });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function assertPetitionable(contractId, entries) {
|
|
34
62
|
const state = deriveContractState(entries);
|
|
35
|
-
|
|
63
|
+
// bound is legal for derived a0 (sealCurrentArc appends seal 0 before petition).
|
|
64
|
+
if (state.state !== "active" && state.state !== "bound") {
|
|
36
65
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot petition from state ${state.state}`);
|
|
37
66
|
}
|
|
38
67
|
}
|
|
39
68
|
export async function petitionContract(input) {
|
|
40
69
|
const at = new Date(input.nowMs).toISOString();
|
|
41
|
-
const ledger = await
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
const deliveryCwd = (await findContractWorktreePath(input.cwd, input.contractId)) ?? input.cwd;
|
|
46
|
-
const base = latestBase(ledger.entries);
|
|
47
|
-
if (!base)
|
|
48
|
-
throw new FlowError("INTERNAL_STATE", "ledger must contain bind entry");
|
|
49
|
-
await assertFresh(input.cwd, input.contractId, ledger.entries, base);
|
|
50
|
-
if (!findOpenArc(ledger.entries)) {
|
|
51
|
-
const loose = await receiptsAfterFence(deliveryCwd, ledger.entries);
|
|
52
|
-
if (loose.length > 0) {
|
|
53
|
-
throw new FlowError("NO_OPEN_ARC", `${loose.length} commits after fence have no arc to receipt them`, { hints: [`keiyaku @${input.contractId} arc — opens a new arc to receipt them, then petition`] });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
70
|
+
const { ledger, deliveryCwd, base, target } = await loadPetitionPreflightContext(input.cwd, input.contractId);
|
|
71
|
+
await assertPetitionFresh(input.cwd, input.contractId, ledger.entries, base);
|
|
72
|
+
await assertPetitionArcReady(deliveryCwd, input.contractId, ledger.entries);
|
|
56
73
|
assertPetitionable(input.contractId, ledger.entries);
|
|
57
|
-
const sealed = await
|
|
74
|
+
const sealed = await sealCurrentArc({
|
|
58
75
|
cwd: deliveryCwd,
|
|
59
76
|
renderCwd: deliveryCwd,
|
|
60
77
|
contractId: input.contractId,
|
|
@@ -62,10 +79,6 @@ export async function petitionContract(input) {
|
|
|
62
79
|
nowMs: input.nowMs,
|
|
63
80
|
waivePaths: input.intent === "claim" ? input.waivePaths : undefined,
|
|
64
81
|
});
|
|
65
|
-
const target = commissionTarget(ledger.entries);
|
|
66
|
-
if (!target) {
|
|
67
|
-
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} missing commission target`);
|
|
68
|
-
}
|
|
69
82
|
const allocated = await allocateSettlementSeat(input.cwd, {
|
|
70
83
|
target: target.ref,
|
|
71
84
|
actor: input.actor,
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
|
+
import { configureHeartBusyTimeout } from "../heart.js";
|
|
5
|
+
import { ProjectionGenerationStoreError, parseStoredRow, validateHistory, } from "./model.js";
|
|
6
|
+
export const PROJECTION_GENERATION_STORE_FILE = "heart";
|
|
7
|
+
export const PROJECTION_GENERATION_SCHEMA_VERSION = 2;
|
|
8
|
+
const SCHEMA_TABLE_SQL = `
|
|
9
|
+
CREATE TABLE generation_schema (
|
|
10
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
11
|
+
version INTEGER NOT NULL CHECK (version = ${PROJECTION_GENERATION_SCHEMA_VERSION})
|
|
12
|
+
) STRICT
|
|
13
|
+
`;
|
|
14
|
+
const RECORD_TABLE_SQL = `
|
|
15
|
+
CREATE TABLE generation_records (
|
|
16
|
+
seq INTEGER PRIMARY KEY CHECK (seq > 0),
|
|
17
|
+
kind TEXT NOT NULL CHECK (kind IN ('launch', 'adoption', 'kill-intent', 'verdict')),
|
|
18
|
+
execution_id TEXT NOT NULL CHECK (length(trim(execution_id)) > 0),
|
|
19
|
+
facts_json TEXT NOT NULL CHECK (json_valid(facts_json))
|
|
20
|
+
) STRICT
|
|
21
|
+
`;
|
|
22
|
+
const IDENTITY_TABLE_SQL = `
|
|
23
|
+
CREATE TABLE projection_identity (
|
|
24
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
25
|
+
version INTEGER NOT NULL CHECK (version = 1),
|
|
26
|
+
pid INTEGER NOT NULL CHECK (pid >= 0),
|
|
27
|
+
akuma TEXT NOT NULL CHECK (length(trim(akuma)) > 0),
|
|
28
|
+
provider TEXT NOT NULL CHECK (length(trim(provider)) > 0),
|
|
29
|
+
authority_json TEXT NOT NULL CHECK (json_valid(authority_json)),
|
|
30
|
+
binding_json TEXT NOT NULL CHECK (json_valid(binding_json)),
|
|
31
|
+
minted_at TEXT NOT NULL CHECK (length(trim(minted_at)) > 0),
|
|
32
|
+
workspace_root TEXT NOT NULL CHECK (length(trim(workspace_root)) > 0),
|
|
33
|
+
effective_policy_json TEXT CHECK (
|
|
34
|
+
effective_policy_json IS NULL OR json_valid(effective_policy_json)
|
|
35
|
+
)
|
|
36
|
+
) STRICT
|
|
37
|
+
`;
|
|
38
|
+
const TELL_TABLE_SQL = `
|
|
39
|
+
CREATE TABLE projection_tells (
|
|
40
|
+
tell_id TEXT PRIMARY KEY CHECK (length(trim(tell_id)) > 0),
|
|
41
|
+
text TEXT NOT NULL,
|
|
42
|
+
created_at TEXT NOT NULL CHECK (length(trim(created_at)) > 0),
|
|
43
|
+
effort TEXT CHECK (effort IS NULL OR length(trim(effort)) > 0),
|
|
44
|
+
state TEXT NOT NULL CHECK (
|
|
45
|
+
state IN ('inbox', 'inflight', 'submitted', 'consumed', 'delivered')
|
|
46
|
+
),
|
|
47
|
+
execution_id TEXT CHECK (
|
|
48
|
+
execution_id IS NULL OR length(trim(execution_id)) > 0
|
|
49
|
+
),
|
|
50
|
+
fence_json TEXT CHECK (fence_json IS NULL OR json_valid(fence_json)),
|
|
51
|
+
replayed_from_json TEXT CHECK (
|
|
52
|
+
replayed_from_json IS NULL OR json_valid(replayed_from_json)
|
|
53
|
+
),
|
|
54
|
+
delivered_at TEXT CHECK (
|
|
55
|
+
delivered_at IS NULL OR length(trim(delivered_at)) > 0
|
|
56
|
+
)
|
|
57
|
+
) STRICT
|
|
58
|
+
`;
|
|
59
|
+
const closedDatabases = new WeakSet();
|
|
60
|
+
function pragmaNumber(database, pragma) {
|
|
61
|
+
const row = database.prepare(`PRAGMA ${pragma}`).get();
|
|
62
|
+
const value = row ? Object.values(row)[0] : undefined;
|
|
63
|
+
if (typeof value !== "number" && typeof value !== "bigint") {
|
|
64
|
+
throw new ProjectionGenerationStoreError(`PRAGMA ${pragma} returned an invalid value`);
|
|
65
|
+
}
|
|
66
|
+
return Number(value);
|
|
67
|
+
}
|
|
68
|
+
export function rollbackQuietly(database) {
|
|
69
|
+
try {
|
|
70
|
+
database.exec("ROLLBACK");
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Preserve the transition or schema failure that caused the rollback.
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function validateSchemaShape(database) {
|
|
77
|
+
const version = pragmaNumber(database, "user_version");
|
|
78
|
+
if (version !== PROJECTION_GENERATION_SCHEMA_VERSION) {
|
|
79
|
+
throw new ProjectionGenerationStoreError(`projection generation schema version ${version} is not supported; expected ${PROJECTION_GENERATION_SCHEMA_VERSION}`);
|
|
80
|
+
}
|
|
81
|
+
const objects = database.prepare(`
|
|
82
|
+
SELECT name, type
|
|
83
|
+
FROM sqlite_schema
|
|
84
|
+
WHERE name NOT LIKE 'sqlite_%'
|
|
85
|
+
ORDER BY name
|
|
86
|
+
`).all();
|
|
87
|
+
const signature = objects.map((object) => `${object.type}:${object.name}`).join(",");
|
|
88
|
+
if (signature !== "table:generation_records,table:generation_schema,table:projection_identity,table:projection_tells") {
|
|
89
|
+
throw new ProjectionGenerationStoreError(`projection generation schema contains unexpected objects: ${signature || "none"}`);
|
|
90
|
+
}
|
|
91
|
+
const metadata = database.prepare("SELECT singleton, version FROM generation_schema").all();
|
|
92
|
+
if (metadata.length !== 1 || Number(metadata[0].singleton) !== 1 || Number(metadata[0].version) !== PROJECTION_GENERATION_SCHEMA_VERSION) {
|
|
93
|
+
throw new ProjectionGenerationStoreError("projection generation schema metadata is malformed");
|
|
94
|
+
}
|
|
95
|
+
const recordColumns = database.prepare("PRAGMA table_info(generation_records)").all();
|
|
96
|
+
const columnSignature = recordColumns
|
|
97
|
+
.map((column) => `${column.name}:${column.type}:${Number(column.notnull)}:${Number(column.pk)}`)
|
|
98
|
+
.join(",");
|
|
99
|
+
if (columnSignature !== "seq:INTEGER:0:1,kind:TEXT:1:0,execution_id:TEXT:1:0,facts_json:TEXT:1:0") {
|
|
100
|
+
throw new ProjectionGenerationStoreError("projection generation record schema is malformed");
|
|
101
|
+
}
|
|
102
|
+
const identityColumns = database.prepare("PRAGMA table_info(projection_identity)").all();
|
|
103
|
+
const identitySignature = identityColumns
|
|
104
|
+
.map((column) => `${column.name}:${column.type}:${Number(column.notnull)}:${Number(column.pk)}`)
|
|
105
|
+
.join(",");
|
|
106
|
+
if (identitySignature !== "singleton:INTEGER:0:1,version:INTEGER:1:0,pid:INTEGER:1:0,akuma:TEXT:1:0,provider:TEXT:1:0,authority_json:TEXT:1:0,binding_json:TEXT:1:0,minted_at:TEXT:1:0,workspace_root:TEXT:1:0,effective_policy_json:TEXT:0:0") {
|
|
107
|
+
throw new ProjectionGenerationStoreError("projection identity schema is malformed");
|
|
108
|
+
}
|
|
109
|
+
const tellColumns = database.prepare("PRAGMA table_info(projection_tells)").all();
|
|
110
|
+
const tellSignature = tellColumns
|
|
111
|
+
.map((column) => `${column.name}:${column.type}:${Number(column.notnull)}:${Number(column.pk)}`)
|
|
112
|
+
.join(",");
|
|
113
|
+
if (tellSignature !== "tell_id:TEXT:1:1,text:TEXT:1:0,created_at:TEXT:1:0,effort:TEXT:0:0,state:TEXT:1:0,execution_id:TEXT:0:0,fence_json:TEXT:0:0,replayed_from_json:TEXT:0:0,delivered_at:TEXT:0:0") {
|
|
114
|
+
throw new ProjectionGenerationStoreError("projection tell schema is malformed");
|
|
115
|
+
}
|
|
116
|
+
const quickCheck = database.prepare("PRAGMA quick_check").get();
|
|
117
|
+
if (!quickCheck || Object.values(quickCheck)[0] !== "ok") {
|
|
118
|
+
throw new ProjectionGenerationStoreError("projection generation database failed quick_check");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function initializeOrValidateSchema(database) {
|
|
122
|
+
database.exec("BEGIN EXCLUSIVE");
|
|
123
|
+
try {
|
|
124
|
+
const version = pragmaNumber(database, "user_version");
|
|
125
|
+
const objects = database.prepare(`
|
|
126
|
+
SELECT name, type
|
|
127
|
+
FROM sqlite_schema
|
|
128
|
+
WHERE name NOT LIKE 'sqlite_%'
|
|
129
|
+
ORDER BY name
|
|
130
|
+
`).all();
|
|
131
|
+
if (version === 0 && objects.length === 0) {
|
|
132
|
+
database.exec(SCHEMA_TABLE_SQL);
|
|
133
|
+
database.exec(RECORD_TABLE_SQL);
|
|
134
|
+
database.exec(IDENTITY_TABLE_SQL);
|
|
135
|
+
database.exec(TELL_TABLE_SQL);
|
|
136
|
+
database.prepare("INSERT INTO generation_schema (singleton, version) VALUES (1, ?)")
|
|
137
|
+
.run(PROJECTION_GENERATION_SCHEMA_VERSION);
|
|
138
|
+
database.exec(`PRAGMA user_version = ${PROJECTION_GENERATION_SCHEMA_VERSION}`);
|
|
139
|
+
}
|
|
140
|
+
else if (version !== PROJECTION_GENERATION_SCHEMA_VERSION) {
|
|
141
|
+
throw new ProjectionGenerationStoreError(`projection generation schema version ${version} is not supported; expected ${PROJECTION_GENERATION_SCHEMA_VERSION}`);
|
|
142
|
+
}
|
|
143
|
+
validateSchemaShape(database);
|
|
144
|
+
database.exec("COMMIT");
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
rollbackQuietly(database);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export function openMutableDatabase(projectionDirectory) {
|
|
152
|
+
const stat = fs.statSync(projectionDirectory);
|
|
153
|
+
if (!stat.isDirectory())
|
|
154
|
+
throw new ProjectionGenerationStoreError("projection generation store parent must be a directory");
|
|
155
|
+
const databasePath = path.join(projectionDirectory, PROJECTION_GENERATION_STORE_FILE);
|
|
156
|
+
let database;
|
|
157
|
+
try {
|
|
158
|
+
database = new DatabaseSync(databasePath, {
|
|
159
|
+
enableForeignKeyConstraints: true,
|
|
160
|
+
enableDoubleQuotedStringLiterals: false,
|
|
161
|
+
allowExtension: false,
|
|
162
|
+
});
|
|
163
|
+
configureHeartBusyTimeout(database);
|
|
164
|
+
// Rollback journal keeps observers genuinely read-only. A read-only WAL
|
|
165
|
+
// connection creates/updates -wal and -shm coordination files, while
|
|
166
|
+
// immutable WAL reads can miss concurrently committed facts.
|
|
167
|
+
database.exec("PRAGMA journal_mode = DELETE");
|
|
168
|
+
database.exec("PRAGMA synchronous = FULL");
|
|
169
|
+
database.exec("PRAGMA foreign_keys = ON");
|
|
170
|
+
database.exec("PRAGMA trusted_schema = OFF");
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
try {
|
|
174
|
+
database?.close();
|
|
175
|
+
}
|
|
176
|
+
catch { /* preserve the open/configuration failure */ }
|
|
177
|
+
throw new ProjectionGenerationStoreError(`cannot open projection generation store at ${databasePath}`, { cause: error });
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
initializeOrValidateSchema(database);
|
|
181
|
+
readValidatedHistory(database);
|
|
182
|
+
return { databasePath, database };
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
database.close();
|
|
186
|
+
if (error instanceof ProjectionGenerationStoreError)
|
|
187
|
+
throw error;
|
|
188
|
+
throw new ProjectionGenerationStoreError(`invalid projection generation store at ${databasePath}`, { cause: error });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
export function openReadOnlyDatabase(projectionDirectory) {
|
|
192
|
+
const stat = fs.statSync(projectionDirectory);
|
|
193
|
+
if (!stat.isDirectory())
|
|
194
|
+
throw new ProjectionGenerationStoreError("projection generation store parent must be a directory");
|
|
195
|
+
const databasePath = path.join(projectionDirectory, PROJECTION_GENERATION_STORE_FILE);
|
|
196
|
+
try {
|
|
197
|
+
if (!fs.lstatSync(databasePath).isFile()) {
|
|
198
|
+
throw new ProjectionGenerationStoreError("projection generation store must be a regular file");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (error instanceof ProjectionGenerationStoreError)
|
|
203
|
+
throw error;
|
|
204
|
+
throw new ProjectionGenerationStoreError(`projection generation store does not exist at ${databasePath}`, { cause: error });
|
|
205
|
+
}
|
|
206
|
+
let database;
|
|
207
|
+
try {
|
|
208
|
+
database = new DatabaseSync(databasePath, {
|
|
209
|
+
readOnly: true,
|
|
210
|
+
enableDoubleQuotedStringLiterals: false,
|
|
211
|
+
allowExtension: false,
|
|
212
|
+
});
|
|
213
|
+
configureHeartBusyTimeout(database);
|
|
214
|
+
validateSchemaShape(database);
|
|
215
|
+
readValidatedHistory(database);
|
|
216
|
+
return { databasePath, database };
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
try {
|
|
220
|
+
database?.close();
|
|
221
|
+
}
|
|
222
|
+
catch { /* preserve the read/open failure */ }
|
|
223
|
+
if (error instanceof ProjectionGenerationStoreError)
|
|
224
|
+
throw error;
|
|
225
|
+
throw new ProjectionGenerationStoreError(`cannot read projection generation store at ${databasePath}`, { cause: error });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
export function assertDatabaseOpen(database) {
|
|
229
|
+
if (closedDatabases.has(database))
|
|
230
|
+
throw new ProjectionGenerationStoreError("projection generation store is closed");
|
|
231
|
+
}
|
|
232
|
+
export function readValidatedHistory(database) {
|
|
233
|
+
const rows = database.prepare(`
|
|
234
|
+
SELECT seq, kind, execution_id, facts_json
|
|
235
|
+
FROM generation_records
|
|
236
|
+
ORDER BY seq
|
|
237
|
+
`).all();
|
|
238
|
+
const records = rows.map(parseStoredRow);
|
|
239
|
+
return { records, current: validateHistory(records) };
|
|
240
|
+
}
|
|
241
|
+
export function appendRecord(database, kind, executionId, facts, seq) {
|
|
242
|
+
const encoded = JSON.stringify(facts);
|
|
243
|
+
database.prepare(`
|
|
244
|
+
INSERT INTO generation_records (seq, kind, execution_id, facts_json)
|
|
245
|
+
VALUES (?, ?, ?, ?)
|
|
246
|
+
`).run(seq, kind, executionId, encoded);
|
|
247
|
+
return { seq, kind, executionId, facts: JSON.parse(encoded) };
|
|
248
|
+
}
|
|
249
|
+
export function writeTransition(database, readOnly, run) {
|
|
250
|
+
assertDatabaseOpen(database);
|
|
251
|
+
if (readOnly) {
|
|
252
|
+
throw new ProjectionGenerationStoreError("projection generation store is read-only");
|
|
253
|
+
}
|
|
254
|
+
database.exec("BEGIN IMMEDIATE");
|
|
255
|
+
try {
|
|
256
|
+
const result = run();
|
|
257
|
+
database.exec("COMMIT");
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
rollbackQuietly(database);
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
export function closeDatabase(database) {
|
|
266
|
+
if (closedDatabases.has(database))
|
|
267
|
+
return;
|
|
268
|
+
closedDatabases.add(database);
|
|
269
|
+
database.close();
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Discovery-only predicate: a readable regular heart whose PRAGMA user_version
|
|
273
|
+
* is exactly 1 is recognized historical residue. Never opens through the store
|
|
274
|
+
* class, never mutates, and any observation failure returns false so callers
|
|
275
|
+
* proceed into the strict current-schema reader.
|
|
276
|
+
*/
|
|
277
|
+
export function isProjectionGenerationSchemaV1Residue(projectionDirectory) {
|
|
278
|
+
const databasePath = path.join(projectionDirectory, PROJECTION_GENERATION_STORE_FILE);
|
|
279
|
+
let database;
|
|
280
|
+
let residue = false;
|
|
281
|
+
try {
|
|
282
|
+
if (!fs.lstatSync(databasePath).isFile())
|
|
283
|
+
return false;
|
|
284
|
+
database = new DatabaseSync(databasePath, {
|
|
285
|
+
readOnly: true,
|
|
286
|
+
enableDoubleQuotedStringLiterals: false,
|
|
287
|
+
allowExtension: false,
|
|
288
|
+
});
|
|
289
|
+
configureHeartBusyTimeout(database);
|
|
290
|
+
residue = pragmaNumber(database, "user_version") === 1;
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
if (database) {
|
|
297
|
+
try {
|
|
298
|
+
database.close();
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
residue = false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return residue;
|
|
306
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { parseExecutionPact, } from "../../execution-pact.js";
|
|
2
|
+
import { assertDatabaseOpen, rollbackQuietly, } from "./database.js";
|
|
3
|
+
import { ProjectionGenerationStoreError } from "./model.js";
|
|
4
|
+
export function initializeIdentity(database, databasePath, readOnly, identity) {
|
|
5
|
+
assertDatabaseOpen(database);
|
|
6
|
+
if (readOnly) {
|
|
7
|
+
throw new ProjectionGenerationStoreError("projection identity store is read-only");
|
|
8
|
+
}
|
|
9
|
+
const validated = parseExecutionPact(identity, `${databasePath}#projection_identity`);
|
|
10
|
+
database.exec("BEGIN IMMEDIATE");
|
|
11
|
+
try {
|
|
12
|
+
const existing = database.prepare("SELECT COUNT(*) AS count FROM projection_identity").get();
|
|
13
|
+
if (Number(existing?.count ?? 0) !== 0) {
|
|
14
|
+
throw new ProjectionGenerationStoreError("projection identity is already initialized");
|
|
15
|
+
}
|
|
16
|
+
database.prepare(`
|
|
17
|
+
INSERT INTO projection_identity (
|
|
18
|
+
singleton,
|
|
19
|
+
version,
|
|
20
|
+
pid,
|
|
21
|
+
akuma,
|
|
22
|
+
provider,
|
|
23
|
+
authority_json,
|
|
24
|
+
binding_json,
|
|
25
|
+
minted_at,
|
|
26
|
+
workspace_root,
|
|
27
|
+
effective_policy_json
|
|
28
|
+
) VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
29
|
+
`).run(validated.version, validated.pid, validated.akuma, validated.provider, JSON.stringify(validated.authority), JSON.stringify(validated.binding), validated.mintedAt, validated.workspaceRoot, validated.effectivePolicy === undefined
|
|
30
|
+
? null
|
|
31
|
+
: JSON.stringify(validated.effectivePolicy));
|
|
32
|
+
database.exec("COMMIT");
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
rollbackQuietly(database);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function readIdentity(database, databasePath) {
|
|
40
|
+
assertDatabaseOpen(database);
|
|
41
|
+
const rows = database.prepare(`
|
|
42
|
+
SELECT
|
|
43
|
+
version,
|
|
44
|
+
pid,
|
|
45
|
+
akuma,
|
|
46
|
+
provider,
|
|
47
|
+
authority_json,
|
|
48
|
+
binding_json,
|
|
49
|
+
minted_at,
|
|
50
|
+
workspace_root,
|
|
51
|
+
effective_policy_json
|
|
52
|
+
FROM projection_identity
|
|
53
|
+
`).all();
|
|
54
|
+
if (rows.length !== 1) {
|
|
55
|
+
throw new ProjectionGenerationStoreError(`projection identity row count must be 1, found ${rows.length}`);
|
|
56
|
+
}
|
|
57
|
+
const row = rows[0];
|
|
58
|
+
let authority;
|
|
59
|
+
let binding;
|
|
60
|
+
let effectivePolicy;
|
|
61
|
+
try {
|
|
62
|
+
authority = JSON.parse(row.authority_json);
|
|
63
|
+
binding = JSON.parse(row.binding_json);
|
|
64
|
+
effectivePolicy = row.effective_policy_json === null
|
|
65
|
+
? undefined
|
|
66
|
+
: JSON.parse(row.effective_policy_json);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
throw new ProjectionGenerationStoreError("projection identity contains malformed JSON", {
|
|
70
|
+
cause: error,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return parseExecutionPact({
|
|
74
|
+
version: Number(row.version),
|
|
75
|
+
pid: Number(row.pid),
|
|
76
|
+
akuma: row.akuma,
|
|
77
|
+
provider: row.provider,
|
|
78
|
+
authority,
|
|
79
|
+
binding,
|
|
80
|
+
mintedAt: row.minted_at,
|
|
81
|
+
workspaceRoot: row.workspace_root,
|
|
82
|
+
...(effectivePolicy === undefined ? {} : { effectivePolicy }),
|
|
83
|
+
}, `${databasePath}#projection_identity`);
|
|
84
|
+
}
|