toolroll 0.9.51 → 0.9.53
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 +20 -0
- package/README.md +55 -80
- package/dist/agentconfig.d.ts +11 -36
- package/dist/agentconfig.js +3 -62
- package/dist/approval-policy.d.ts +1 -1
- package/dist/approval-policy.js +1 -1
- package/dist/backup.d.ts +8 -0
- package/dist/backup.js +10 -1
- package/dist/board.d.ts +3 -19
- package/dist/board.js +4 -42
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +18 -18
- package/dist/browser-workspace.d.ts +3 -1
- package/dist/builder.d.ts +9 -40
- package/dist/builder.js +50 -257
- package/dist/chat-actions.js +3 -14
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-decide.js +1 -3
- package/dist/chat-delivery.d.ts +0 -2
- package/dist/chat-delivery.js +0 -1
- package/dist/chat-quiet.js +2 -2
- package/dist/chat-task-actions.d.ts +1 -1
- package/dist/chat-task-actions.js +0 -2
- package/dist/claim.d.ts +79 -244
- package/dist/claim.js +688 -1023
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +10 -2
- package/dist/contracts/cli.d.ts +0 -13
- package/dist/contracts/cli.js +0 -2
- package/dist/contracts/console-api.d.ts +5 -10
- package/dist/contracts/console-api.js +4 -10
- package/dist/contracts/flow.d.ts +50 -0
- package/dist/contracts/flow.js +26 -1
- package/dist/contracts/lead-tools.d.ts +0 -13
- package/dist/contracts/lead-tools.js +3 -3
- package/dist/contracts/store-json.d.ts +1 -25
- package/dist/contracts/store-json.js +3 -13
- package/dist/converse.d.ts +1 -11
- package/dist/converse.js +6 -38
- package/dist/coordinator.d.ts +0 -1
- package/dist/coordinator.js +3 -5
- package/dist/database-reclaim.d.ts +4 -0
- package/dist/database-reclaim.js +13 -0
- package/dist/demo.d.ts +1 -1
- package/dist/demo.js +17 -27
- package/dist/desktop-update-gate.js +0 -1
- package/dist/desktop-update.d.ts +1 -1
- package/dist/desktop-update.js +1 -3
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/dispose.d.ts +2 -3
- package/dist/dispose.js +17 -92
- package/dist/envelope.js +0 -3
- package/dist/exec.d.ts +0 -64
- package/dist/exec.js +3 -356
- package/dist/exhaustion.d.ts +22 -76
- package/dist/exhaustion.js +14 -140
- package/dist/export.js +4 -4
- package/dist/flow-engine.js +1 -1
- package/dist/flow-schedule.d.ts +154 -0
- package/dist/flow-schedule.js +321 -0
- package/dist/flow-share.js +1 -1
- package/dist/flow-triggers.d.ts +6 -1
- package/dist/flow-triggers.js +65 -10
- package/dist/flows-cli.js +8 -4
- package/dist/flows-ui.js +2 -0
- package/dist/flows.js +1 -1
- package/dist/guides.js +9 -29
- package/dist/invoke.d.ts +1 -24
- package/dist/invoke.js +17 -259
- package/dist/lead-status.js +2 -4
- package/dist/lead-voice.js +1 -1
- package/dist/live-bus.d.ts +3 -3
- package/dist/live-bus.js +3 -3
- package/dist/mate-doors.d.ts +1 -2
- package/dist/mate-doors.js +12 -25
- package/dist/mate-tools.d.ts +2 -2
- package/dist/mate-tools.js +10 -22
- package/dist/modes.d.ts +6 -7
- package/dist/modes.js +7 -13
- package/dist/monitoring.js +32 -8
- package/dist/notification-delivery.d.ts +19 -0
- package/dist/notification-delivery.js +37 -0
- package/dist/operate-remote-arguments.js +2 -6
- package/dist/operate-remote.js +6 -7
- package/dist/operate.d.ts +0 -6
- package/dist/operate.js +283 -2378
- package/dist/phase-routing.d.ts +13 -23
- package/dist/phase-routing.js +13 -35
- package/dist/plan-auto.js +2 -2
- package/dist/planner-source.js +2 -1
- package/dist/policy.d.ts +1 -4
- package/dist/policy.js +0 -8
- package/dist/process-recovery-eligibility.js +2 -3
- package/dist/process-recovery-settlement.js +1 -0
- package/dist/project-delete.js +3 -15
- package/dist/proposal.d.ts +4 -24
- package/dist/proposal.js +3 -88
- package/dist/provider-auth.d.ts +3 -3
- package/dist/provider-auth.js +4 -6
- package/dist/provider.d.ts +11 -25
- package/dist/provider.js +4 -36
- package/dist/push.js +1 -1
- package/dist/recipe-ui.js +6 -6
- package/dist/recipes.d.ts +3 -3
- package/dist/recipes.js +27 -23
- package/dist/retention.js +6 -5
- package/dist/run-closeout.d.ts +1 -1
- package/dist/run-closeout.js +1 -4
- package/dist/scope.d.ts +11 -65
- package/dist/scope.js +17 -82
- package/dist/serve.js +16 -25
- package/dist/server/chat.js +7 -30
- package/dist/server/flows.js +11 -10
- package/dist/server/guards.js +0 -1
- package/dist/server/pages-assets.js +1 -1
- package/dist/server/pages.js +0 -2
- package/dist/server/people-tokens.js +0 -4
- package/dist/server/route-table.d.ts +1 -1
- package/dist/server/route-table.js +2 -17
- package/dist/server/settings.js +4 -9
- package/dist/server/shared.d.ts +29 -212
- package/dist/server/shared.js +73 -780
- package/dist/server/task-views.js +9 -76
- package/dist/server/tasks.d.ts +1 -50
- package/dist/server/tasks.js +36 -946
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-chat.d.ts +0 -2
- package/dist/slack-chat.js +0 -1
- package/dist/store.d.ts +142 -1382
- package/dist/store.js +900 -4083
- package/dist/surface.js +10 -25
- package/dist/task-composer.d.ts +1 -1
- package/dist/task-composer.js +1 -1
- package/dist/task-control.d.ts +3 -10
- package/dist/task-control.js +2 -7
- package/dist/teammate-desk.js +1 -1
- package/dist/teammates-ui.js +1 -1
- package/dist/telegram-mate.d.ts +0 -3
- package/dist/telegram-mate.js +0 -1
- package/dist/templates.d.ts +11 -7
- package/dist/templates.js +12 -9
- package/dist/toolroll-update.d.ts +24 -3
- package/dist/toolroll-update.js +159 -16
- package/dist/webhooks.d.ts +10 -22
- package/dist/webhooks.js +43 -81
- package/dist/work-index.js +3 -7
- package/dist/workspace-revision.d.ts +28 -1
- package/dist/workspace-revision.js +276 -49
- package/dist/workspace-ui.js +1 -1
- package/package.json +1 -3
- package/scripts/recovery-canary.mjs +3 -3
- package/dist/contest.d.ts +0 -318
- package/dist/contest.js +0 -753
- package/dist/held.d.ts +0 -150
- package/dist/held.js +0 -799
- package/dist/liveness.d.ts +0 -30
- package/dist/liveness.js +0 -42
- package/dist/pricing.d.ts +0 -45
- package/dist/pricing.js +0 -77
- package/dist/routine.d.ts +0 -228
- package/dist/routine.js +0 -764
- package/dist/supervisor.mjs +0 -297
package/dist/chat-actions.js
CHANGED
|
@@ -23,7 +23,7 @@ import { addCardToFlow, advanceFlows, cancelFlowCard, crossProjectProblem, decid
|
|
|
23
23
|
import { chooseFlowCard, flowPersonOf } from "./flow-send.js";
|
|
24
24
|
import { assignFlowCard, commentOnFlowCard, flowPeople, mentionsIn, watchFlowCard } from "./flow-people.js";
|
|
25
25
|
import { addFlowTriggerTo, describeTrigger, readLinearKey, removeFlowTrigger, scheduleFromWords, takesDeliveries, triggerConfigOf, validateTriggerConfig } from "./flow-triggers.js";
|
|
26
|
-
import { describeSchedule, parseSchedule } from "./
|
|
26
|
+
import { describeSchedule, parseSchedule } from "./flow-schedule.js";
|
|
27
27
|
import { dirname } from "node:path";
|
|
28
28
|
import { handleOf, parseSoul, SOUL_CHARS, TEAMMATE_TEMPLATES, teammateLabel } from "./teammates.js";
|
|
29
29
|
import { createTeammateFrom, labelOf, nameOf, renamedSoul, saveSoul, setTeammateState } from "./teammate-admin.js";
|
|
@@ -825,8 +825,6 @@ export function prepareSharedAction(store, who, operation, input, root, now = ne
|
|
|
825
825
|
const ref = store.lookupRef(task), row = store.getTask(task), family = store.taskFamilyOf(task, who.repos, false);
|
|
826
826
|
if (!row || !family || family.problem || family.current.id !== task)
|
|
827
827
|
throw Error("Choose the current task.");
|
|
828
|
-
if (store.openContestFor(ref.id) !== null)
|
|
829
|
-
throw Error("Wait for the agent comparison to finish.");
|
|
830
828
|
const scope = store.getScope(task);
|
|
831
829
|
state = {
|
|
832
830
|
task,
|
|
@@ -847,19 +845,13 @@ export function prepareSharedAction(store, who, operation, input, root, now = ne
|
|
|
847
845
|
if (!authority.ok)
|
|
848
846
|
throw Error(authority.problem);
|
|
849
847
|
state["authMode"] = authority.authMode;
|
|
850
|
-
const race = store.activeTournamentTerms(ref.id);
|
|
851
|
-
state["race"] = race;
|
|
852
848
|
terms.push(...describeScope(scope)
|
|
853
849
|
.filter((line) => !/^\s*(reference|approved)\s/.test(line))
|
|
854
850
|
.map((line) => line
|
|
855
851
|
.trimStart()
|
|
856
852
|
.replace(/^goal\s+/, "Work: ")
|
|
857
853
|
.replace(/^not this\s+/, "Excluded: ")
|
|
858
|
-
.replace(/^touches\s+/, "Allowed files: ")),
|
|
859
|
-
{ profile: authority.profile, authMode: authority.authMode },
|
|
860
|
-
]).map((entry, index) => `${index === 0 ? "Agent permissions and limits" : "Fallback " + index}\n${runtimeTerms(entry.profile)}\n${entry.authMode === "api-key" ? "Uses your API key; spend is charged to that account." : entry.authMode === "subscription" ? "Uses your subscription login." : ""}`));
|
|
861
|
-
if (race)
|
|
862
|
-
terms.push(`Agent comparison terms:\n${JSON.stringify(race, null, 2)}`);
|
|
854
|
+
.replace(/^touches\s+/, "Allowed files: ")), `Agent permissions and limits\n${runtimeTerms(authority.profile)}\n${authority.authMode === "api-key" ? "Uses your API key; spend is charged to that account." : authority.authMode === "subscription" ? "Uses your subscription login." : ""}`);
|
|
863
855
|
const plan = store.latestPlanArtifact(ref.id), revision = ref.revisionBriefArtifact === null
|
|
864
856
|
? null
|
|
865
857
|
: store.getArtifact(ref.revisionBriefArtifact);
|
|
@@ -1111,7 +1103,7 @@ export function executeSharedAction(store, who, id, payload, now, options) {
|
|
|
1111
1103
|
: { restore: Number(req["restore"]) }),
|
|
1112
1104
|
}, now);
|
|
1113
1105
|
else if (payload.operation === "scope_approve") {
|
|
1114
|
-
const scope = store.getScope(task)
|
|
1106
|
+
const scope = store.getScope(task);
|
|
1115
1107
|
const result = approve(store, task, actor, now, scope.digest, options.review.password);
|
|
1116
1108
|
if (!result.ok) {
|
|
1117
1109
|
// v102: the project's approval rules speak for themselves.
|
|
@@ -1123,9 +1115,6 @@ export function executeSharedAction(store, who, id, payload, now, options) {
|
|
|
1123
1115
|
throw Error(result.message);
|
|
1124
1116
|
throw Error(`Approval refused: ${result.reason}.`);
|
|
1125
1117
|
}
|
|
1126
|
-
if (race &&
|
|
1127
|
-
!store.approveTournamentTerms(race.id, actor, race.raceDigest, now))
|
|
1128
|
-
throw Error("The comparison terms changed. Nothing was approved.");
|
|
1129
1118
|
}
|
|
1130
1119
|
else if (payload.operation === "result_accept") {
|
|
1131
1120
|
// Accept and finish, as on the result page: whether a check only the person makes is accepted
|
package/dist/chat-controls.d.ts
CHANGED
|
@@ -42,10 +42,6 @@ export declare const CHAT_CONTROLS: {
|
|
|
42
42
|
readonly label: "Open coding workspace";
|
|
43
43
|
readonly href: "/code";
|
|
44
44
|
};
|
|
45
|
-
readonly routines: {
|
|
46
|
-
readonly label: "Manage routines";
|
|
47
|
-
readonly href: "/routines";
|
|
48
|
-
};
|
|
49
45
|
readonly flows: {
|
|
50
46
|
readonly label: "Open flows";
|
|
51
47
|
readonly href: "/flows";
|
package/dist/chat-controls.js
CHANGED
|
@@ -12,7 +12,6 @@ export const CHAT_CONTROLS = {
|
|
|
12
12
|
publish: { label: "Review publication", target: "task" },
|
|
13
13
|
projects: { label: "Manage projects", href: "/projects" },
|
|
14
14
|
code: { label: "Open coding workspace", href: "/code" },
|
|
15
|
-
routines: { label: "Manage routines", href: "/routines" },
|
|
16
15
|
flows: { label: "Open flows", href: "/flows" },
|
|
17
16
|
recipes: { label: "Browse workflows", href: "/recipes" },
|
|
18
17
|
workers: { label: "Manage workers", href: "/fleet" },
|
package/dist/chat-decide.js
CHANGED
|
@@ -104,11 +104,9 @@ export function planInChat(store, taskId, approver, now, root) {
|
|
|
104
104
|
const family = store.taskFamilyOf(taskId, [ref.repo], false);
|
|
105
105
|
if (family === null || family.problem !== null || family.current.id !== taskId)
|
|
106
106
|
return { ok: false, why: "A newer version of this task is current." };
|
|
107
|
-
// What the mode's seal refuses anyway, said first: model- or coordinator-written terms,
|
|
107
|
+
// What the mode's seal refuses anyway, said first: model- or coordinator-written terms, an unreadable route.
|
|
108
108
|
if (ref.coordinatorCid !== null || (scope.proposedVia ?? null) !== null)
|
|
109
109
|
return { ok: false, why: "This plan was written for you, so you approve it in Toolroll." };
|
|
110
|
-
if (store.activeTournamentTerms(ref.id) !== null)
|
|
111
|
-
return { ok: false, why: "Agents compete on this task, so you approve it in Toolroll." };
|
|
112
110
|
if (scope.profileState === "unresolved" || scope.routeEra == null || (scope.termsProblem ?? null) !== null)
|
|
113
111
|
return { ok: false, why: "This plan can't say exactly which agents run, so you approve it in Toolroll." };
|
|
114
112
|
const yours = mode.source === "setting" ? "your chat approval setting" : "your mode";
|
package/dist/chat-delivery.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type WarmHooks } from "./chat-warmth.js";
|
|
2
|
-
import { type DoorOptions } from "./mate-doors.js";
|
|
3
2
|
import { ChatState, type ChatBinding, type ChatEvent, type ChatIdentity } from "./chat-delivery-state.js";
|
|
4
3
|
import { type Store } from "./store.js";
|
|
5
4
|
import type { SubscriptionMateRunner } from "./subscription-chat.js";
|
|
@@ -16,7 +15,6 @@ export type ChatDeliveryOptions = {
|
|
|
16
15
|
current: () => boolean;
|
|
17
16
|
origin: () => string | null;
|
|
18
17
|
subscriptionRunner?: SubscriptionMateRunner;
|
|
19
|
-
held?: DoorOptions["held"];
|
|
20
18
|
canNotify?: () => boolean;
|
|
21
19
|
clock?: () => Date;
|
|
22
20
|
partSize?: number;
|
package/dist/chat-delivery.js
CHANGED
|
@@ -547,7 +547,6 @@ export function applyChatAction(options, event, binding, repos) {
|
|
|
547
547
|
via: options.state.channel,
|
|
548
548
|
evidenceRoot: options.evidenceRoot,
|
|
549
549
|
confirm: phase === "yes",
|
|
550
|
-
...(options.held ? { held: options.held } : {}),
|
|
551
550
|
deferSignal: (signal) => signals.push(signal),
|
|
552
551
|
});
|
|
553
552
|
if (!outcome.ok && outcome.reason === "needs-confirm") {
|
package/dist/chat-quiet.js
CHANGED
|
@@ -36,9 +36,9 @@ export function needsPerson(row) {
|
|
|
36
36
|
export function isTaskFact(row) {
|
|
37
37
|
return row.taskRef !== null && row.taskId !== null && row.project !== null;
|
|
38
38
|
}
|
|
39
|
-
/** The attempt a task's card follows: its newest builder attempt
|
|
39
|
+
/** The attempt a task's card follows: its newest builder attempt. */
|
|
40
40
|
function cardRun(store, taskRef) {
|
|
41
|
-
return store.runsFor(taskRef).find(run => run.role === "builder"
|
|
41
|
+
return store.runsFor(taskRef).find(run => run.role === "builder") ?? null;
|
|
42
42
|
}
|
|
43
43
|
/** Before any attempt starts, the card says where the task stands in the words of its last lifecycle fact. */
|
|
44
44
|
const before = (headline) => ({ icon: headlineEmoji(headline), status: headline });
|
|
@@ -44,7 +44,7 @@ export declare function isChatTaskAction(value: unknown): value is keyof typeof
|
|
|
44
44
|
export declare function chatTaskStamp(store: Store, who: VerifiedApprover, task: string): string | null;
|
|
45
45
|
/** Only current, eligible controls can become cards; retain the exact run the reader saw. */
|
|
46
46
|
export declare function chatTaskRun(store: Store, task: string, operation: "stop" | "resume", now: Date): number | null;
|
|
47
|
-
export declare function applyChatTaskAction(store: Store, who: VerifiedApprover, payload: Record<string, unknown>, now: Date, web: boolean, controls?: Pick<StopRequest, "
|
|
47
|
+
export declare function applyChatTaskAction(store: Store, who: VerifiedApprover, payload: Record<string, unknown>, now: Date, web: boolean, controls?: Pick<StopRequest, "deferSignal"> & {
|
|
48
48
|
via?: StopRequest["via"];
|
|
49
49
|
evidenceRoot?: string;
|
|
50
50
|
}): {
|
|
@@ -46,8 +46,6 @@ export function applyChatTaskAction(store, who, payload, now, web, controls = {}
|
|
|
46
46
|
if (stamp === null || stamp !== payload["stamp"])
|
|
47
47
|
return { ok: false, message: "This task changed. Review it again before confirming." };
|
|
48
48
|
const ref = store.lookupRef(task);
|
|
49
|
-
if (store.openContestFor(ref.id) !== null)
|
|
50
|
-
return { ok: false, message: "Wait for the agent comparison to finish." };
|
|
51
49
|
if (operation === "stop" || operation === "resume") {
|
|
52
50
|
if (store.isDemo())
|
|
53
51
|
return { ok: false, message: "The demo authorizes nothing." };
|
package/dist/claim.d.ts
CHANGED
|
@@ -63,21 +63,6 @@ export type AcquireResult = {
|
|
|
63
63
|
reason: "external";
|
|
64
64
|
detail: "stale-mirror" | "external-closed" | "dispatch-revoked" | "plane-blocked";
|
|
65
65
|
}
|
|
66
|
-
/** An attended authorization holds this task for its named runner (v25).
|
|
67
|
-
* Its OWN reason token — never the `reserved` tag, whose reservedFor field
|
|
68
|
-
* is a documented public contract meaning task_ref.assigned_runner. */
|
|
69
|
-
| {
|
|
70
|
-
ok: false;
|
|
71
|
-
reason: "attended-held";
|
|
72
|
-
runner: string;
|
|
73
|
-
}
|
|
74
|
-
/** The task's only authority is an attended authorization, and the
|
|
75
|
-
* operator is not watching (or the one attempt is spent). Expiry never
|
|
76
|
-
* converts attended work into unattended work. */
|
|
77
|
-
| {
|
|
78
|
-
ok: false;
|
|
79
|
-
reason: "attended-only";
|
|
80
|
-
}
|
|
81
66
|
/** A mode-sealed approval whose signature no longer stands (v29): the
|
|
82
67
|
* approval falls back to a person; nothing dispatches on a dead mode. */
|
|
83
68
|
| {
|
|
@@ -209,26 +194,6 @@ export declare function acquireIfReady(store: Store, taskRef: number, runner: st
|
|
|
209
194
|
* caller's survey is not trusted (Codex planning review, finding 2). */
|
|
210
195
|
dispatchRole?: "builder" | "planner" | "scout";
|
|
211
196
|
}): AcquireResult | NotReady;
|
|
212
|
-
/**
|
|
213
|
-
* The FALLBACK-ADMISSION claim (E3d, review finding 4): the one gate a
|
|
214
|
-
* pending-admission chain cycle dispatches through. It enforces everything
|
|
215
|
-
* `acquireIfReady` enforces — task state, holds, blockers, the approved
|
|
216
|
-
* scope + live-mode belt, capability, capacity, and quota — with EXACTLY
|
|
217
|
-
* ONE deliberate difference: a BACKOFF hold does not gate, because the
|
|
218
|
-
* pending admission IS the system's answer to the predecessor's failure
|
|
219
|
-
* (waiting out the exhausted entry's backoff to run a different credential
|
|
220
|
-
* would be waiting for nothing). Quota is keyed by the PINNED entry's
|
|
221
|
-
* provider, model, and auth mode — the credential that would actually
|
|
222
|
-
* spend — so an exhausted fallback credential refuses here, before any
|
|
223
|
-
* claim exists.
|
|
224
|
-
*/
|
|
225
|
-
export declare function acquireFallback(store: Store, taskRef: number, runner: string, options: AcquireOptions & {
|
|
226
|
-
repo?: string;
|
|
227
|
-
provider: string;
|
|
228
|
-
model: string;
|
|
229
|
-
authMode: "subscription" | "api-key";
|
|
230
|
-
maxOpenDecisions?: number;
|
|
231
|
-
}): AcquireResult | NotReady;
|
|
232
197
|
/**
|
|
233
198
|
* "I am still here." Extends the lease, and tells a superseded runner that it
|
|
234
199
|
* has been superseded — which is the cheapest moment for it to find out, well
|
|
@@ -246,73 +211,67 @@ export declare function heartbeat(store: Store, leaseId: string, now: Date, ttlM
|
|
|
246
211
|
*/
|
|
247
212
|
export declare function release(store: Store, leaseId: string, now: Date): FenceResult;
|
|
248
213
|
/**
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
* Release-then-mark is a window: between the two, the freed task is back in
|
|
252
|
-
* the ready set, and another pass can claim it before the terminal state
|
|
253
|
-
* lands — two builders for one task, the second dispatched by our own
|
|
254
|
-
* bookkeeping. Here the state is written inside the same transaction as the
|
|
255
|
-
* fenced release, so a task is never simultaneously free and unfinished.
|
|
256
|
-
*
|
|
257
|
-
* A fenced or unknown lease writes nothing: a runner the world moved past
|
|
258
|
-
* does not get to say how the task ended. A duplicate release reports
|
|
259
|
-
* `duplicate` and also writes nothing — the first completion already said,
|
|
260
|
-
* and a retry changing the answer would make "done" negotiable.
|
|
261
|
-
*/
|
|
262
|
-
export declare function completeFenced(store: Store, leaseId: string, state: Extract<TaskState, "done" | "failed">, now: Date, mutation?: Mutation): CompleteResult;
|
|
263
|
-
/**
|
|
264
|
-
* Seal a park, fenced at the write (§7).
|
|
265
|
-
*
|
|
266
|
-
* The builder proved its lease after the agent ran; this transaction proves
|
|
267
|
-
* it again *in the same statement that releases it*, because everything a
|
|
268
|
-
* park creates — the decision, its hold, the outbox row — is only true if
|
|
269
|
-
* this lease still spoke for the task at the moment of sealing. A superseded
|
|
270
|
-
* lease creates none of it: no decision, no hold, no notification, and the
|
|
271
|
-
* run is finalized as the fenced refusal it was. A crash anywhere inside
|
|
272
|
-
* rolls all of it back together; there is no instant at which a decision
|
|
273
|
-
* exists without its hold.
|
|
274
|
-
*
|
|
275
|
-
* `released_by = 'parked'` so a late retry from this lease is answered with
|
|
276
|
-
* the fence, not "duplicate": a park hands the task to a person, and nothing
|
|
277
|
-
* the runner says afterwards is that person's answer.
|
|
278
|
-
*/
|
|
279
|
-
/**
|
|
280
|
-
* Continuation admission (Phase 2E, A4 / v3 R7): the AUTHORIZATION is the
|
|
281
|
-
* claimable unit — the finished parent task is never re-queued, its state,
|
|
282
|
-
* strikes, holds, and dependents untouched. Every shared gate still runs
|
|
283
|
-
* (acquireLocked: reservation, external mirror, the attended gates, the
|
|
284
|
-
* lease CAS); the queued-state readiness gate alone is replaced by
|
|
285
|
-
* construction. Liveness, the named runner, and the unspent attempt are
|
|
286
|
-
* re-proved HERE at claim time and again at the final dispatch proof.
|
|
214
|
+
* How an attempt ended, one kind per ending, each with the facts its seal needs. `finalize` seals every one.
|
|
287
215
|
*/
|
|
288
|
-
export
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
216
|
+
export type Outcome =
|
|
217
|
+
/** The task's terminal state, written with the release (no run: the lease's own completion). */
|
|
218
|
+
({
|
|
219
|
+
kind: "complete";
|
|
220
|
+
} & CompleteSeal) | ({
|
|
221
|
+
kind: "park";
|
|
222
|
+
} & ParkSeal) | ({
|
|
223
|
+
kind: "malformed";
|
|
224
|
+
} & MalformedSeal) | ({
|
|
225
|
+
kind: "interrupted";
|
|
226
|
+
} & InterruptedSeal) | ({
|
|
227
|
+
kind: "hand-back";
|
|
228
|
+
} & HandBackSeal) | ({
|
|
229
|
+
kind: "failure";
|
|
230
|
+
} & FailureSeal) | ({
|
|
231
|
+
kind: "plan";
|
|
232
|
+
} & PlanSeal) | ({
|
|
233
|
+
kind: "revision";
|
|
234
|
+
} & RevisionSeal) | ({
|
|
235
|
+
kind: "plan-failure";
|
|
236
|
+
} & PlanFailureSeal) | ({
|
|
237
|
+
kind: "scout";
|
|
238
|
+
} & ScoutSeal) | ({
|
|
239
|
+
kind: "scout-failure";
|
|
240
|
+
} & ScoutFailureSeal);
|
|
241
|
+
/** What sealing each kind answers. */
|
|
242
|
+
export type Finalized = {
|
|
243
|
+
complete: CompleteResult;
|
|
244
|
+
park: ParkFinalize;
|
|
245
|
+
malformed: MalformedFinalize;
|
|
246
|
+
interrupted: InterruptSeal;
|
|
247
|
+
"hand-back": HandBackFinalize;
|
|
248
|
+
failure: FailureDisposition;
|
|
249
|
+
plan: PlanFinalize;
|
|
250
|
+
revision: RevisionFinalize;
|
|
251
|
+
"plan-failure": PlanFailureDisposition;
|
|
252
|
+
scout: ScoutFinalize;
|
|
253
|
+
"scout-failure": ScoutFailureDisposition;
|
|
292
254
|
};
|
|
293
255
|
/**
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
256
|
+
* THE ONE WAY AN ATTEMPT ENDS: seal `outcome` for `leaseId` in one fenced transaction.
|
|
257
|
+
*
|
|
258
|
+
* Every ending passes the same fence, in the same order: the run is this lease's open attempt of the right role (a
|
|
259
|
+
* caller defect otherwise, thrown); a stop that applies to it wins — the attempt is sealed as interrupted instead
|
|
260
|
+
* (except the endings that ARE a stop or a service hand-back); then the claim is released by a compare-and-swap only the
|
|
261
|
+
* live, unsuperseded lease wins. A lease the world moved past writes nothing but its own run's fenced refusal (the
|
|
262
|
+
* stop and hand-back endings still end their run, touching no task state), and a retry of an ending the same lease
|
|
263
|
+
* already made answers as a duplicate where that ending allows it. Only then does the ending's own effect run —
|
|
264
|
+
* decision and hold, incident, strike and backoff, scope, report, revision, task state, the disowned mirror — inside
|
|
265
|
+
* the same transaction, so nothing of it exists without the release, and a crash rolls all of it back together.
|
|
299
266
|
*/
|
|
300
|
-
export declare function
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
artifactIds: readonly number[];
|
|
305
|
-
sessionTurn: number;
|
|
267
|
+
export declare function finalize<O extends Outcome>(store: Store, leaseId: string, outcome: O): Finalized[O["kind"]];
|
|
268
|
+
/** The task's terminal state, written with the release (no run: the lease's own completion). */
|
|
269
|
+
export type CompleteSeal = {
|
|
270
|
+
state: Extract<TaskState, "done" | "failed">;
|
|
306
271
|
now: Date;
|
|
307
|
-
|
|
308
|
-
ok: true;
|
|
309
|
-
decisionId: number;
|
|
310
|
-
} | {
|
|
311
|
-
ok: false;
|
|
312
|
-
reason: "decision-open" | "not-held";
|
|
272
|
+
mutation?: Mutation;
|
|
313
273
|
};
|
|
314
|
-
export
|
|
315
|
-
leaseId: string;
|
|
274
|
+
export type ParkSeal = {
|
|
316
275
|
runId: number;
|
|
317
276
|
taskId: string;
|
|
318
277
|
decision: ParsedDecision;
|
|
@@ -321,28 +280,21 @@ export declare function finalizeParkFenced(store: Store, args: {
|
|
|
321
280
|
* settled in this same fence, never earlier. */
|
|
322
281
|
repairRunId?: number | null;
|
|
323
282
|
now: Date;
|
|
324
|
-
}
|
|
283
|
+
};
|
|
284
|
+
export type ParkFinalize = {
|
|
325
285
|
ok: true;
|
|
326
286
|
decisionId: number;
|
|
327
287
|
} | {
|
|
328
288
|
ok: false;
|
|
329
289
|
reason: "fenced" | "unknown" | "stopped";
|
|
330
290
|
};
|
|
331
|
-
|
|
332
|
-
* Seal a park whose payload never became a decision (§6's bounded repair ran
|
|
333
|
-
* out). Same fence, same atomicity, different record: an incident that stays
|
|
334
|
-
* in every brief until a person resolves it, holding the task so the next
|
|
335
|
-
* pass does not spend the same tokens hitting the same wall nightly. The
|
|
336
|
-
* malformed payload is preserved as evidence — a person may still be able to
|
|
337
|
-
* read what the agent meant.
|
|
338
|
-
*/
|
|
339
|
-
export declare function finalizeMalformedFenced(store: Store, args: {
|
|
340
|
-
leaseId: string;
|
|
291
|
+
export type MalformedSeal = {
|
|
341
292
|
runId: number;
|
|
342
293
|
taskId: string;
|
|
343
294
|
problems: readonly Problem[];
|
|
344
295
|
now: Date;
|
|
345
|
-
}
|
|
296
|
+
};
|
|
297
|
+
export type MalformedFinalize = {
|
|
346
298
|
ok: true;
|
|
347
299
|
incidentId: number;
|
|
348
300
|
} | {
|
|
@@ -387,48 +339,21 @@ export type InterruptSeal = {
|
|
|
387
339
|
requeued: false;
|
|
388
340
|
fenced: true;
|
|
389
341
|
};
|
|
390
|
-
|
|
391
|
-
* Seal an operator-stopped attempt (v52): ONE fenced transaction for the
|
|
392
|
-
* claim's release as `interrupted`, the run's ending as `failed` /
|
|
393
|
-
* `interrupted` (the same words dead-runner recovery writes, so the
|
|
394
|
-
* recovered-draft road inherits the preserved work exactly as after a
|
|
395
|
-
* crash), every open run the attempt owns, the task's return to the
|
|
396
|
-
* queue under the stop's own hold, and the stop's settlement. Nothing
|
|
397
|
-
* here is a failure: no strike, no backoff, no incident, no automatic
|
|
398
|
-
* repair task, no notification page. A commit the attempt already made
|
|
399
|
-
* is kept as a reviewable artifact — `committed` records that it exists.
|
|
400
|
-
*
|
|
401
|
-
* A lease the world moved past (reaped, recovered, superseded) still
|
|
402
|
-
* ends the run as interrupted — that IS the honest ending — but touches
|
|
403
|
-
* no task state: the task belongs to whoever holds it now.
|
|
404
|
-
*/
|
|
405
|
-
export declare function finalizeInterruptedFenced(store: Store, args: {
|
|
406
|
-
leaseId: string;
|
|
342
|
+
export type InterruptedSeal = {
|
|
407
343
|
runId: number;
|
|
408
344
|
taskId: string;
|
|
409
345
|
stopRun: number;
|
|
410
346
|
message?: string;
|
|
411
347
|
committed?: boolean;
|
|
412
348
|
now: Date;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
* Hand an attempt back because the SERVICE stopped (its builder is
|
|
416
|
-
* stopping or restarting), not because anyone stopped the task: one fenced
|
|
417
|
-
* transaction releases the claim as `interrupted`, ends the run (and every
|
|
418
|
-
* open run it owns) as `failed` / `interrupted` — the words dead-runner
|
|
419
|
-
* recovery writes, so the next attempt inherits the preserved work in the
|
|
420
|
-
* same checkout exactly as after a crash — and returns the task to the
|
|
421
|
-
* queue with no strike, no backoff and no hold, so the next builder pass
|
|
422
|
-
* resumes it. A lease the world moved past still ends the run, touching no
|
|
423
|
-
* task state.
|
|
424
|
-
*/
|
|
425
|
-
export declare function finalizeHandBackFenced(store: Store, args: {
|
|
426
|
-
leaseId: string;
|
|
349
|
+
};
|
|
350
|
+
export type HandBackSeal = {
|
|
427
351
|
runId: number;
|
|
428
352
|
taskId: string;
|
|
429
353
|
message: string;
|
|
430
354
|
now: Date;
|
|
431
|
-
}
|
|
355
|
+
};
|
|
356
|
+
export type HandBackFinalize = {
|
|
432
357
|
ok: true;
|
|
433
358
|
requeued: boolean;
|
|
434
359
|
fenced: boolean;
|
|
@@ -449,30 +374,14 @@ export declare function interruptIfStopped(store: Store, args: {
|
|
|
449
374
|
committed?: boolean;
|
|
450
375
|
now: Date;
|
|
451
376
|
}): InterruptSeal | null;
|
|
452
|
-
|
|
453
|
-
* Seal a failed attempt: one fenced transaction for the release, the run,
|
|
454
|
-
* the strike, the hold, and the page (§6, gnhf adopted rather than
|
|
455
|
-
* reinvented).
|
|
456
|
-
*
|
|
457
|
-
* Strikes count only top-level builder attempts; built, no-change, and
|
|
458
|
-
* parked reset them elsewhere; refusals, fenced attempts, and repair
|
|
459
|
-
* children never reach this function. Under three strikes the task
|
|
460
|
-
* requeues behind a doubling backoff hold the failure owns; at three it
|
|
461
|
-
* stalls — an 'attempts-exhausted' incident, the task marked failed, held,
|
|
462
|
-
* and paged once — because a fourth identical attempt at 3am is a token
|
|
463
|
-
* bonfire, not persistence. A commit-stage failure takes neither road: the
|
|
464
|
-
* worktree holds unpreserved work, ordinary re-pooling would refuse it as
|
|
465
|
-
* dirty forever, so it is an immediate incident naming the checkout.
|
|
466
|
-
*/
|
|
467
|
-
export declare function finalizeFailureFenced(store: Store, args: {
|
|
468
|
-
leaseId: string;
|
|
377
|
+
export type FailureSeal = {
|
|
469
378
|
runId: number;
|
|
470
379
|
taskId: string;
|
|
471
380
|
failureClass: FailureClass;
|
|
472
381
|
message: string;
|
|
473
382
|
worktree: string;
|
|
474
383
|
now: Date;
|
|
475
|
-
}
|
|
384
|
+
};
|
|
476
385
|
/** The live claim on a task, if there is one. */
|
|
477
386
|
export declare const MAX_PLAN_STRIKES = 3;
|
|
478
387
|
export type PlanFinalize = {
|
|
@@ -492,16 +401,7 @@ export type PlanFinalize = {
|
|
|
492
401
|
reason: "stale-source" | "source-invalid";
|
|
493
402
|
detail: string;
|
|
494
403
|
};
|
|
495
|
-
|
|
496
|
-
* Seal a successful planning run: the proposed scope, the plan document
|
|
497
|
-
* artifact, the drafted state, the run outcome, and the page to the
|
|
498
|
-
* operator exist together or — if the lease was superseded — not at all.
|
|
499
|
-
* The scope proposal is authority-bearing (it is what the approve card
|
|
500
|
-
* will restate), which is why this is the park discipline, not the DONE
|
|
501
|
-
* one (Codex planning review, question 2).
|
|
502
|
-
*/
|
|
503
|
-
export declare function finalizePlanFenced(store: Store, args: {
|
|
504
|
-
leaseId: string;
|
|
404
|
+
export type PlanSeal = {
|
|
505
405
|
runId: number;
|
|
506
406
|
taskId: string;
|
|
507
407
|
plan: ParsedPlan;
|
|
@@ -529,7 +429,7 @@ export declare function finalizePlanFenced(store: Store, args: {
|
|
|
529
429
|
/** Where the plan-contract ingestion record is written. */
|
|
530
430
|
evidenceRoot?: string;
|
|
531
431
|
now: Date;
|
|
532
|
-
}
|
|
432
|
+
};
|
|
533
433
|
export type RevisionFinalize = {
|
|
534
434
|
ok: true;
|
|
535
435
|
revisionId: number;
|
|
@@ -538,42 +438,7 @@ export type RevisionFinalize = {
|
|
|
538
438
|
ok: false;
|
|
539
439
|
reason: "fenced" | "unknown" | "stopped";
|
|
540
440
|
};
|
|
541
|
-
|
|
542
|
-
* Seal a running build's plan-revision proposal (adaptive execution plans).
|
|
543
|
-
*
|
|
544
|
-
* A builder that finds repository evidence invalidating a named dependency,
|
|
545
|
-
* risk, or assumption in the plan it was given files ONE proposal and stops
|
|
546
|
-
* without committing — the park discipline, applied to the road rather than
|
|
547
|
-
* to a question. The ledger row, the hold when one is owed, the run's
|
|
548
|
-
* outcome, and the page exist together or, if the lease was superseded,
|
|
549
|
-
* not at all. Structurally `finalizePlanFenced`'s twin: the same
|
|
550
|
-
* open-attempt assertion, the same fenced release, the same all-or-nothing
|
|
551
|
-
* transaction.
|
|
552
|
-
*
|
|
553
|
-
* Two dispositions, decided by the caller's classification and recorded
|
|
554
|
-
* here:
|
|
555
|
-
*
|
|
556
|
-
* plan-only the signed scope and publication authority are
|
|
557
|
-
* byte-identical to what this build started under, so
|
|
558
|
-
* nothing authority-bearing moved and the revision is
|
|
559
|
-
* APPLIED. The claim releases plainly, the task returns
|
|
560
|
-
* to the ready set, and the next attempt reads the new
|
|
561
|
-
* plan — that is the "resume" the subject line promises.
|
|
562
|
-
*
|
|
563
|
-
* authority-change something else moved the signed scope or the
|
|
564
|
-
* publication authority WHILE this build ran. Whatever
|
|
565
|
-
* the revision proposes, it is never auto-applied: the
|
|
566
|
-
* row lands 'blocked', a `revision` hold keeps the task
|
|
567
|
-
* out of every ready set until a person accepts or
|
|
568
|
-
* rejects it, and the page names exactly which fields
|
|
569
|
-
* changed.
|
|
570
|
-
*
|
|
571
|
-
* The lease is released either way — the attempt is over — and the run is
|
|
572
|
-
* finished as `refused`, reusing the existing outcome vocabulary rather
|
|
573
|
-
* than growing it: no work was committed, and nothing failed.
|
|
574
|
-
*/
|
|
575
|
-
export declare function finalizeRevisionFenced(store: Store, args: {
|
|
576
|
-
leaseId: string;
|
|
441
|
+
export type RevisionSeal = {
|
|
577
442
|
runId: number;
|
|
578
443
|
taskId: string;
|
|
579
444
|
taskRef: number;
|
|
@@ -594,7 +459,7 @@ export declare function finalizeRevisionFenced(store: Store, args: {
|
|
|
594
459
|
changedFields: readonly AuthorityChangeField[];
|
|
595
460
|
};
|
|
596
461
|
now: Date;
|
|
597
|
-
}
|
|
462
|
+
};
|
|
598
463
|
export type PlanFailureDisposition = {
|
|
599
464
|
ok: true;
|
|
600
465
|
disposition: "malformed-incident";
|
|
@@ -616,44 +481,22 @@ export type PlanFailureDisposition = {
|
|
|
616
481
|
ok: false;
|
|
617
482
|
reason: "fenced" | "unknown" | "stopped";
|
|
618
483
|
};
|
|
619
|
-
|
|
620
|
-
* The planner's own fenced failure finalizer (Codex planning review,
|
|
621
|
-
* finding 6): releases exactly the planner claim, finishes the run,
|
|
622
|
-
* counts a SEPARATE planning strike — a planner that cannot finish must
|
|
623
|
-
* never spend the builder's three attempts — and eventually leaves a
|
|
624
|
-
* durable incident + hold + page. It never marks the task done, never
|
|
625
|
-
* touches builder strikes, never commits, never publishes.
|
|
626
|
-
*
|
|
627
|
-
* A malformed payload goes straight to its incident with no strike: the
|
|
628
|
-
* protocol failed, not the weather, and retrying the same session buys
|
|
629
|
-
* nothing without the repair machinery (deliberately not wired for
|
|
630
|
-
* planners in v1).
|
|
631
|
-
*/
|
|
632
|
-
export declare function finalizePlanFailureFenced(store: Store, args: {
|
|
633
|
-
leaseId: string;
|
|
484
|
+
export type PlanFailureSeal = {
|
|
634
485
|
runId: number;
|
|
635
486
|
taskId: string;
|
|
636
|
-
|
|
487
|
+
failure: "malformed" | "failure";
|
|
637
488
|
/** Which payload was malformed (v4 review, finding 12): the mailbox is a `malformed-decision`. */
|
|
638
489
|
malformed?: "decision" | "plan";
|
|
639
490
|
message: string;
|
|
640
491
|
now: Date;
|
|
641
|
-
}
|
|
492
|
+
};
|
|
642
493
|
export type ScoutFinalize = {
|
|
643
494
|
ok: true;
|
|
644
495
|
} | {
|
|
645
496
|
ok: false;
|
|
646
497
|
reason: "fenced" | "unknown" | "stopped";
|
|
647
498
|
};
|
|
648
|
-
|
|
649
|
-
* Seal a successful scouting run (mate arc §10): the report artifact, the
|
|
650
|
-
* run outcome, the task's terminal state, and the page to the operator
|
|
651
|
-
* exist together or — if the lease was superseded — not at all. Nothing
|
|
652
|
-
* here touches a branch, a publication, or a scope: the deliverable is
|
|
653
|
-
* the artifact, and the task is done the moment it verifies.
|
|
654
|
-
*/
|
|
655
|
-
export declare function finalizeScoutFenced(store: Store, args: {
|
|
656
|
-
leaseId: string;
|
|
499
|
+
export type ScoutSeal = {
|
|
657
500
|
runId: number;
|
|
658
501
|
taskId: string;
|
|
659
502
|
report: ParsedReport;
|
|
@@ -670,7 +513,7 @@ export declare function finalizeScoutFenced(store: Store, args: {
|
|
|
670
513
|
redacted: boolean;
|
|
671
514
|
};
|
|
672
515
|
now: Date;
|
|
673
|
-
}
|
|
516
|
+
};
|
|
674
517
|
export type ScoutFailureDisposition = {
|
|
675
518
|
ok: true;
|
|
676
519
|
disposition: "malformed-incident";
|
|
@@ -692,25 +535,17 @@ export type ScoutFailureDisposition = {
|
|
|
692
535
|
ok: false;
|
|
693
536
|
reason: "fenced" | "unknown" | "stopped";
|
|
694
537
|
};
|
|
695
|
-
|
|
696
|
-
* The scout's fenced failure finalizer: the BUILDER's discipline, not the
|
|
697
|
-
* planner's — a scout task has no builder attempts, so its strikes are the
|
|
698
|
-
* task's own (three stall it, `task requeue` clears them), and a malformed
|
|
699
|
-
* report is a straight incident with no strike. Never a branch, never a
|
|
700
|
-
* repair session, never a commit.
|
|
701
|
-
*/
|
|
702
|
-
export declare function finalizeScoutFailureFenced(store: Store, args: {
|
|
703
|
-
leaseId: string;
|
|
538
|
+
export type ScoutFailureSeal = {
|
|
704
539
|
runId: number;
|
|
705
540
|
taskId: string;
|
|
706
|
-
|
|
541
|
+
failure: "malformed" | "failure";
|
|
707
542
|
/** Which payload was malformed (v4 review, finding 12): the park
|
|
708
543
|
* mailbox is a `malformed-decision` incident, the handoff a
|
|
709
544
|
* `malformed-report` one — the taxonomy says what actually broke. */
|
|
710
545
|
malformed?: "decision" | "report";
|
|
711
546
|
message: string;
|
|
712
547
|
now: Date;
|
|
713
|
-
}
|
|
548
|
+
};
|
|
714
549
|
export declare function currentClaim(store: Store, taskRef: number, now: Date): Claim | null;
|
|
715
550
|
/**
|
|
716
551
|
* Release every lease that has run out.
|