@uchibeke/gallivant 0.0.0-stage → 0.2.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/CONTRIBUTING.md +26 -0
- package/LICENSE +204 -0
- package/README.md +201 -2
- package/SECURITY.md +19 -0
- package/bin/gallivant.mjs +257 -0
- package/bin/package-plugin.mjs +16 -0
- package/bin/release-live.mjs +29 -0
- package/bin/release-package.mjs +23 -0
- package/bin/session-runtime.mjs +13 -0
- package/bin/task-delivery-state.mjs +12 -0
- package/docs/README.md +70 -0
- package/docs/agent-setup.md +214 -0
- package/docs/app.md +111 -0
- package/docs/architecture.md +265 -0
- package/docs/chains.md +102 -0
- package/docs/codex-cloud.md +284 -0
- package/docs/commands.md +620 -0
- package/docs/config.md +430 -0
- package/docs/execution.md +796 -0
- package/docs/guardrails.md +311 -0
- package/docs/install.md +338 -0
- package/docs/launch.md +42 -0
- package/docs/learning.md +369 -0
- package/docs/network-recovery.md +101 -0
- package/docs/openai-agents.md +457 -0
- package/docs/prd.md +246 -0
- package/docs/preparation.md +110 -0
- package/docs/release-qualification.md +196 -0
- package/docs/releasing.md +140 -0
- package/docs/runtime-environment.md +113 -0
- package/docs/task-delivery.md +476 -0
- package/docs/tasks.md +739 -0
- package/lib/aport.mjs +95 -0
- package/lib/attribution.mjs +95 -0
- package/lib/block.mjs +89 -0
- package/lib/capabilities.mjs +3 -0
- package/lib/chains.mjs +222 -0
- package/lib/codex_cloud.mjs +160 -0
- package/lib/codex_cloud_config.mjs +20 -0
- package/lib/codex_cloud_input.mjs +49 -0
- package/lib/codex_cloud_result.mjs +74 -0
- package/lib/commands/doctor.mjs +457 -0
- package/lib/commands/init.mjs +34 -0
- package/lib/commands/learn.mjs +54 -0
- package/lib/commands/new.mjs +47 -0
- package/lib/commands/ready.mjs +45 -0
- package/lib/commands/register.mjs +195 -0
- package/lib/commands/resume.mjs +224 -0
- package/lib/commands/serve.mjs +349 -0
- package/lib/commands/start.mjs +247 -0
- package/lib/commands/start_services.mjs +22 -0
- package/lib/commands/status.mjs +150 -0
- package/lib/commands/task.mjs +73 -0
- package/lib/commands/up.mjs +228 -0
- package/lib/commands/why.mjs +143 -0
- package/lib/config.mjs +461 -0
- package/lib/context.mjs +100 -0
- package/lib/control.mjs +202 -0
- package/lib/control_contract.mjs +16 -0
- package/lib/coordinator.mjs +19 -0
- package/lib/credential.mjs +161 -0
- package/lib/daemon.mjs +156 -0
- package/lib/deliverable.mjs +357 -0
- package/lib/events.mjs +261 -0
- package/lib/executable.mjs +31 -0
- package/lib/execution.mjs +631 -0
- package/lib/execution_contract.mjs +15 -0
- package/lib/execution_input.mjs +4 -0
- package/lib/execution_io.mjs +94 -0
- package/lib/execution_journal.mjs +69 -0
- package/lib/execution_preparation.mjs +29 -0
- package/lib/execution_result.mjs +266 -0
- package/lib/fs.mjs +133 -0
- package/lib/gh.mjs +289 -0
- package/lib/git.mjs +434 -0
- package/lib/harness.mjs +521 -0
- package/lib/harness_log.mjs +432 -0
- package/lib/hash.mjs +16 -0
- package/lib/identity.mjs +98 -0
- package/lib/learning.mjs +654 -0
- package/lib/learning_contract.mjs +2 -0
- package/lib/learning_data.mjs +135 -0
- package/lib/learning_input.mjs +111 -0
- package/lib/learning_qualification.mjs +67 -0
- package/lib/learning_signer.mjs +151 -0
- package/lib/learning_store.mjs +88 -0
- package/lib/log.mjs +53 -0
- package/lib/network_diagnostics.mjs +64 -0
- package/lib/network_recovery.mjs +42 -0
- package/lib/notify.mjs +58 -0
- package/lib/openai_agents.mjs +373 -0
- package/lib/openai_agents_config.mjs +14 -0
- package/lib/openai_agents_http.mjs +87 -0
- package/lib/openai_agents_input.mjs +15 -0
- package/lib/openai_agents_sources.mjs +112 -0
- package/lib/owner_delivery.mjs +443 -0
- package/lib/plugin_package.mjs +340 -0
- package/lib/prd.mjs +635 -0
- package/lib/preparation_agents.mjs +33 -0
- package/lib/preparation_codex.mjs +212 -0
- package/lib/probe.mjs +126 -0
- package/lib/prompt.mjs +238 -0
- package/lib/provider_health.mjs +55 -0
- package/lib/public-format.mjs +31 -0
- package/lib/public_output.mjs +49 -0
- package/lib/release_package.mjs +154 -0
- package/lib/repository_files.mjs +86 -0
- package/lib/run.mjs +385 -0
- package/lib/run_log.mjs +94 -0
- package/lib/runtime-environment.mjs +87 -0
- package/lib/runtime_dependencies.mjs +15 -0
- package/lib/runtime_node.mjs +107 -0
- package/lib/runtime_state.mjs +174 -0
- package/lib/sources/index.mjs +27 -0
- package/lib/sources/prd.mjs +50 -0
- package/lib/start_contract.mjs +37 -0
- package/lib/state.mjs +246 -0
- package/lib/task_allowance.mjs +31 -0
- package/lib/task_completion.mjs +61 -0
- package/lib/task_contract.mjs +450 -0
- package/lib/task_delivery.mjs +219 -0
- package/lib/task_delivery_cancel.mjs +34 -0
- package/lib/task_delivery_contract.mjs +61 -0
- package/lib/task_delivery_mcp.mjs +40 -0
- package/lib/task_delivery_store.mjs +43 -0
- package/lib/task_delivery_view.mjs +88 -0
- package/lib/task_environment.mjs +281 -0
- package/lib/task_prepare.mjs +224 -0
- package/lib/task_store.mjs +38 -0
- package/lib/tasks.mjs +513 -0
- package/lib/tick.mjs +1635 -0
- package/lib/time.mjs +36 -0
- package/lib/tracker/assets.mjs +43 -0
- package/lib/tracker/pages.mjs +320 -0
- package/lib/tracker/runs.mjs +102 -0
- package/lib/tracker/stream.mjs +74 -0
- package/lib/tracker_process.mjs +107 -0
- package/lib/verification_sandbox.mjs +181 -0
- package/node_modules/smol-toml/LICENSE +24 -0
- package/node_modules/smol-toml/README.md +605 -0
- package/node_modules/smol-toml/dist/date.d.ts +41 -0
- package/node_modules/smol-toml/dist/date.js +156 -0
- package/node_modules/smol-toml/dist/error.d.ts +37 -0
- package/node_modules/smol-toml/dist/error.js +67 -0
- package/node_modules/smol-toml/dist/extract.js +289 -0
- package/node_modules/smol-toml/dist/index.cjs +770 -0
- package/node_modules/smol-toml/dist/index.d.ts +44 -0
- package/node_modules/smol-toml/dist/index.js +34 -0
- package/node_modules/smol-toml/dist/parse.d.ts +73 -0
- package/node_modules/smol-toml/dist/parse.js +164 -0
- package/node_modules/smol-toml/dist/primitive.js +151 -0
- package/node_modules/smol-toml/dist/stringify.d.ts +32 -0
- package/node_modules/smol-toml/dist/stringify.js +219 -0
- package/node_modules/smol-toml/dist/struct.js +156 -0
- package/node_modules/smol-toml/dist/util.d.ts +43 -0
- package/node_modules/smol-toml/dist/util.js +57 -0
- package/node_modules/smol-toml/package.json +68 -0
- package/npm-shrinkwrap.json +1823 -0
- package/package.json +105 -4
- package/templates/claude-settings.json +18 -0
- package/templates/passport.gallivant.json +83 -0
- package/templates/plugin/bundled-runtime.json +26 -0
- package/templates/plugin/schemas/mcp.schema.json +120 -0
- package/templates/plugin/schemas/plugin.schema.json +65 -0
- package/templates/plugin/task-delivery.SKILL.md +60 -0
- package/templates/prd.md +32 -0
- package/templates/tracker/tracker.css +301 -0
- package/templates/tracker/tracker.js +721 -0
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
# Execution transport contract
|
|
2
|
+
|
|
3
|
+
Gallivant runs local CLI harnesses and a hosted Agents API through one execution
|
|
4
|
+
boundary, task service, registry, isolated checkout and PR lifecycle. The
|
|
5
|
+
coordinator still runs on your machine or a Node host you operate; choosing a
|
|
6
|
+
hosted harness does not host Gallivant's daemon for you. Repository outputs can
|
|
7
|
+
be code, documentation, research or other verifiable artifacts. Start with a
|
|
8
|
+
[natural-language task](tasks.md) or an approved [PRD](prd.md).
|
|
9
|
+
|
|
10
|
+
The execution layer reuses registry claims and the canonical PR lifecycle.
|
|
11
|
+
`assertExecutionDependency` refuses a runtime assembled without the shared intake
|
|
12
|
+
service (`EXECUTION_DEPENDENCY`); normal installations include it. Consumers must
|
|
13
|
+
use a compatible complete package instead of recreating intake or a second review
|
|
14
|
+
engine. The original approved implementation brief is
|
|
15
|
+
[the execution PRD](https://github.com/uchibeke/gallivant/blob/main/docs/prds/hosted-codex-harnesses.md).
|
|
16
|
+
|
|
17
|
+
## Availability and capabilities
|
|
18
|
+
|
|
19
|
+
`executionRegistry` in `lib/harness.mjs` is the capability source for configuration,
|
|
20
|
+
probes, the task service's `capabilities()` and `GET /api/capabilities`. Existing
|
|
21
|
+
`claude`, `codex`, `opencode`, `gemini` and `goose` public names and CLI adapters are
|
|
22
|
+
preserved. Each entry declares authentication, environments, preparation policy,
|
|
23
|
+
continuation, observability, cancellation/interrupt, and cost/hard-cap support.
|
|
24
|
+
Mandatory policy, model and environment choices are checked before dispatch;
|
|
25
|
+
unsupported choices refuse execution without falling back or changing defaults.
|
|
26
|
+
Preparation is an optional versioned capability of that same selected provider.
|
|
27
|
+
Claude's tools-off policy, Codex's isolated preparation profile and Agents API's
|
|
28
|
+
text-only `environment:none` policy are registered by their adapters; task
|
|
29
|
+
lifecycle code contains no Claude-only name gate. Gemini, OpenCode and Goose
|
|
30
|
+
currently support implementation from a ready PRD but have no enforced preparation
|
|
31
|
+
capability. A private HOME or a version/sign-in probe does not qualify one. See
|
|
32
|
+
[preparation](preparation.md) for boundaries and measured qualification.
|
|
33
|
+
|
|
34
|
+
Availability means an implemented adapter can be selected; it is not a claim
|
|
35
|
+
that every provider/model has passed a live task. The recorded qualification is:
|
|
36
|
+
|
|
37
|
+
| Harness | Continuation and controls | Qualification and limits |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| Claude Code, local Codex | Native session; cancel and interrupt | Production/local Git evidence exists. Claude alone supplies a native dollar cap; Codex reports unknown dollar cost. Their permission settings differ; see [guardrails](guardrails.md). |
|
|
40
|
+
| Gemini CLI, OpenCode, Goose | Native session; cancel and interrupt | Adapters and fixtures exist, but the recorded coding campaign did not qualify a complete start/resume or GitHub review lifecycle for these combinations. Native permissions can block headless work; Gallivant adds no OS sandbox to these three. |
|
|
41
|
+
| OpenAI Agents API | Native session; cancel, no interrupt | Hosted preparation and implementation are implemented. Preparation-only live evidence does not qualify hosted implementation/publication/review correction; the separate campaign retains those gates. |
|
|
42
|
+
| Codex Cloud | Successor task; no native cancel or interrupt | New dispatch is unavailable. Offline transport tests and owned-task recovery do not qualify environment/repository binding or live execution. |
|
|
43
|
+
|
|
44
|
+
Local adapters use the provider/model selected in the native harness settings;
|
|
45
|
+
Gallivant does not supply a generic per-task local model router. A model that is
|
|
46
|
+
listed or a stored credential is not proof of model access, credits or permission
|
|
47
|
+
for unattended work. Agents requires an explicit authorized model; Cloud refuses
|
|
48
|
+
model overrides. Unknown dollar cost stays unknown, and remote reservations limit
|
|
49
|
+
future dispatch rather than provider billing. See the
|
|
50
|
+
[dated local campaign](https://github.com/uchibeke/gallivant/blob/main/docs/audit/harness-live-validation.md)
|
|
51
|
+
and each hosted guide for the exact evidence and remaining prerequisites.
|
|
52
|
+
|
|
53
|
+
`openai-agents` has an implemented managed REST transport; see
|
|
54
|
+
[account/environment setup and verification](openai-agents.md). `codex-cloud`
|
|
55
|
+
has an implemented CLI transport but remains unavailable for new dispatch until
|
|
56
|
+
a supported interface verifies the selected environment's connected repository;
|
|
57
|
+
see [Cloud setup and recovery](codex-cloud.md). Offline fixtures
|
|
58
|
+
exercise shared lifecycle behavior; they do not certify live account/model access
|
|
59
|
+
or installed-plugin behavior. The separately opt-in Agents campaign retains unmet
|
|
60
|
+
live prerequisites explicitly. Existing intake qualification blockers remain in
|
|
61
|
+
[the intake evidence](https://github.com/uchibeke/gallivant/blob/main/docs/audit/plugin-ready/README.md).
|
|
62
|
+
|
|
63
|
+
## Exported boundary
|
|
64
|
+
|
|
65
|
+
Package subpaths `./execution` and `./execution-result` export `makeExecution`,
|
|
66
|
+
`EXECUTION_VERSION`, `PROVIDER_STATES`, `executionLive`, `executionRunner`,
|
|
67
|
+
`assertExecutionDependency` and `reconcileExecutionResult`. `makeExecution` takes
|
|
68
|
+
an owned root, task ID, provider/account, capabilities and either the existing
|
|
69
|
+
local runner or a transport. Its local facade preserves `start`, `current`,
|
|
70
|
+
`read`, `lines`, `settle`, `kill`, `waitForKill` and `dirOf`.
|
|
71
|
+
|
|
72
|
+
A transport implements the following asynchronous methods. Every method must
|
|
73
|
+
honor its `AbortSignal`, bound responses, release resources on abort, and avoid
|
|
74
|
+
creating its own scheduler or review loop. The coordinator owns progress/review
|
|
75
|
+
scheduling. Explicit task preparation mutations can reconcile one owned turn at
|
|
76
|
+
its persisted cadence; read-only clients never call a transport.
|
|
77
|
+
|
|
78
|
+
| Method | Input and acknowledgement |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| `prepare` | Preparation kind, prompt, authorized limited environment and allowance; confirmed boundary and bounded environment grant, without paid submit |
|
|
81
|
+
| `submit` | Task/provider/account, canonical run ID, operation ID, idempotency key, prompt/input head, mandatory policy, allowance; exact provider job, session and root turn IDs |
|
|
82
|
+
| `inspect` | Exact owned job/session/turn, event cursor; authoritative state, observation time, optional nullable `completedAt`, bounded event page, next cursor, explicit gap and nullable cost |
|
|
83
|
+
| `continue` | Same dispatch contract plus this provider's recorded native session; exact new owned job/root turn acknowledgement |
|
|
84
|
+
| `collect` | Exact job/session/turn/input head; finished boolean outcome, nullable cost, optional nullable `completedAt`, saved result and optional artifact manifest or verified pushed revision |
|
|
85
|
+
| `cancel` | Task/provider/account/run, exact owned job/session/root turn, durable cancellation idempotency key and AbortSignal; boolean `confirmed`, true only after authoritative remote cancellation |
|
|
86
|
+
| optional `lookup` | Persisted intent/idempotency key after lost acknowledgement; authoritative exact job observation, or unresolved null |
|
|
87
|
+
| optional `recoverResponse` | Explicit retry of the identical authorized answer and stable key; reconcile the owned pending call or saved output before replay/acceptance |
|
|
88
|
+
|
|
89
|
+
The public boundary's `inspect()` is deliberately a cached read. Its coordinator
|
|
90
|
+
`reconcile()` invokes transport inspection/lookup. Reading CLI status, task
|
|
91
|
+
inspection, UI status/history/results or SSE never probes providers, submits work,
|
|
92
|
+
or starts an independent provider loop.
|
|
93
|
+
|
|
94
|
+
Inspection and acceptance lookup cursors are bounded JSON scalars: strings,
|
|
95
|
+
finite numbers or booleans, at most 4096 bytes of serialized UTF-8 JSON, including
|
|
96
|
+
quotes and escapes. Omitted/null cursors retain the recorded token. The fixed
|
|
97
|
+
`EXECUTION_CURSOR_BYTES` limit applies before journaling, ownership/progress
|
|
98
|
+
adoption and persistence, independently of the event-page limit. Invalid tokens
|
|
99
|
+
leave prior progress/cursor and journals intact and enter scoped protocol backoff;
|
|
100
|
+
the next inspection sends only the last validated token. Long valid cursors use
|
|
101
|
+
a stable hashed gap ID when the legacy `gap-<cursor>` ID would exceed 512 characters;
|
|
102
|
+
short gap IDs and replay identity remain compatible.
|
|
103
|
+
Hashed IDs use the distinct `gap:` prefix, so a short token resembling a digest
|
|
104
|
+
cannot collide with a long token's gap ID.
|
|
105
|
+
|
|
106
|
+
Restart checks the current cursor and saved acknowledgement cursors before any
|
|
107
|
+
transport call or state rewrite. An invalid pre-upgrade checkpoint raises
|
|
108
|
+
`EXECUTION_PROTOCOL` with an explicit remedy: preserve the run files, restore the
|
|
109
|
+
exact bounded cursor from the owned provider checkpoint, then restart. Do not
|
|
110
|
+
delete the intent, reset the cursor to skip history or redispatch the task.
|
|
111
|
+
|
|
112
|
+
For intake, `makeExecution.prepare()` returns an issued `receipt` and either the
|
|
113
|
+
native `{cmd, args, options}` spec or a remote environment grant. The receipt
|
|
114
|
+
contains version 1, provider/account, authority/boundary, task ID and an input
|
|
115
|
+
fingerprint. `submit({kind: "intake", preparation: receipt, ...})` requires an
|
|
116
|
+
issued receipt matching the exact prepared input. Changing argv, prompt or grant
|
|
117
|
+
cannot reuse it. Environment credentials remain private; only their fingerprint
|
|
118
|
+
enters execution state. Native preparation uses the selected CLI/config defaults,
|
|
119
|
+
the existing small environment allowlist and enforced adapter argv. Optional
|
|
120
|
+
adapter configuration receives an AbortSignal and the transport deadline;
|
|
121
|
+
deadline or concurrent cancellation never issues late authority.
|
|
122
|
+
|
|
123
|
+
Drafting, clarification and repair all call this operation and the shared submit,
|
|
124
|
+
reconcile, collect and cancel boundary. Remote preparation returns `preparing`
|
|
125
|
+
while acceptance or results are unknown, retaining exact ownership for explicit
|
|
126
|
+
resume. It never waits in an independent polling loop. Unknown cost stays null;
|
|
127
|
+
each remote turn reserves up to one sixteenth of the original task budget, and
|
|
128
|
+
accounting retains the greater of reservation and reported usage. The existing
|
|
129
|
+
16-turn, three-repair and runtime limits, immutable owner requirements,
|
|
130
|
+
deterministic validation/readiness and explicit implementation consent remain
|
|
131
|
+
canonical. Preparation grants no implementation or GitHub-writing authority.
|
|
132
|
+
|
|
133
|
+
Example normalized observation and result (provider identities are illustrative):
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"providerJobId": "job-123", "sessionId": "session-123", "turnId": "root-2",
|
|
138
|
+
"state": "succeeded", "observedAt": 1780000000000, "cursor": "page-2",
|
|
139
|
+
"events": [{"eventId": "delta-7", "sequence": 7, "type": "output",
|
|
140
|
+
"timestamp": 1780000000000, "data": "verification finished"}],
|
|
141
|
+
"costUsd": null
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"providerJobId": "job-123", "sessionId": "session-123", "turnId": "root-2",
|
|
148
|
+
"inputHead": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
149
|
+
"outcome": {"finished": true, "ok": true, "cost": null, "denials": []},
|
|
150
|
+
"repo": "owner/repository", "branch": "work/example",
|
|
151
|
+
"files": [{"path": "src/example.txt", "beforeHash": null,
|
|
152
|
+
"afterHash": "SHA256-of-text", "text": "new content"}],
|
|
153
|
+
"pr": {"title": "Implement example", "body": "Reviewable receipt body"}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Hashes must be real SHA-256 values, and input heads real exact revisions. Result
|
|
158
|
+
collection supplies canonical version/task/run identities even if a transport
|
|
159
|
+
returns conflicting fields. Missing, oversized, mismatched or incomplete results
|
|
160
|
+
remain unresolved; provider success alone does not mean workflow readiness.
|
|
161
|
+
`observedAt` is a finite UTC epoch millisecond value between the owned run's
|
|
162
|
+
start/last accepted observation and the coordinator clock at reconciliation.
|
|
163
|
+
There is no allowance for future clock skew. Inspection and lost-reply lookup
|
|
164
|
+
reject future observations before adopting ownership, cost, events or terminal
|
|
165
|
+
state, retain the last valid checkpoint, and use scoped protocol backoff.
|
|
166
|
+
Correct the transport's clock/units and reconcile the same owned job/key; no
|
|
167
|
+
replacement dispatch is needed. Older checkpoints already containing future
|
|
168
|
+
timestamps require restoring the last authoritative observation evidence while
|
|
169
|
+
preserving task/run ownership, intents and allowance records.
|
|
170
|
+
|
|
171
|
+
Private result ownership (`taskId`, `runId`, `providerJobId`, `sessionId`, `turnId`,
|
|
172
|
+
`inputHead`, `repo`, `branch`, `pushedHead`) retains exact protocol values through
|
|
173
|
+
redaction, collection and replay, even when an opaque ID resembles a credential
|
|
174
|
+
or equals a supplied secret. Collection validates provider identities before
|
|
175
|
+
saving them; publication independently validates repository, branch and revisions.
|
|
176
|
+
Diagnostic fields remain redacted. A previously rewritten identity is not a valid
|
|
177
|
+
substitute: preserve the cache and restore exact ownership from the recorded
|
|
178
|
+
acknowledgement/provider root before continuing; never redispatch for recovery.
|
|
179
|
+
|
|
180
|
+
`completedAt` is the exact owned root's completion time in UTC epoch milliseconds,
|
|
181
|
+
not submission-client exit or collection time. An inspection may supply it only
|
|
182
|
+
for a terminal state, between the recorded start and its authoritative observation.
|
|
183
|
+
A collected result may supply it between start and collection, no later than the
|
|
184
|
+
first terminal observation; it must agree with any recorded exact completion.
|
|
185
|
+
Invalid, conflicting or foreign timestamps cannot qualify output. Missing/null
|
|
186
|
+
timestamps remain compatible: the first terminal observation provides an inferred
|
|
187
|
+
upper bound, or collection time is the conservative bound for an older result.
|
|
188
|
+
Remote `job.json` retains compatible `endedAt` plus `completionInferred`; exact
|
|
189
|
+
completion and `terminalObservedAt` survive restart in execution metadata. Local
|
|
190
|
+
process completion and identities retain their existing semantics.
|
|
191
|
+
|
|
192
|
+
Preparation retrieves terminal results before applying runtime allowance, even
|
|
193
|
+
when task resume occurs after the deadline. It compares this owned completion
|
|
194
|
+
time (or conservative bound) with the saved inclusive deadline. Timely output is
|
|
195
|
+
eligible for deterministic validation; late/unknown-late output preserves result,
|
|
196
|
+
usage and cost evidence but cannot authorize readiness or another repair. Missing
|
|
197
|
+
or invalid results stay pending without cancelling an already completed root.
|
|
198
|
+
A timeout/unsafe-boundary stop of active or unresolved work persists its intent
|
|
199
|
+
in the task attempt before control I/O. Unconfirmed, failed or unsupported stops
|
|
200
|
+
keep the intake `preparing`, with an explicit cancellation next action and no new
|
|
201
|
+
dispatch. Call `task resume` with the current revision to reconcile that owned
|
|
202
|
+
stop through the boundary's persisted cadence until cancellation or terminal
|
|
203
|
+
completion is confirmed, then the task becomes `blocked` and output is quarantined.
|
|
204
|
+
Older blocked timeouts with a pending owned stop permit this same control-only
|
|
205
|
+
resume. Other blocked refusals remain inert; inspect/list never poll providers.
|
|
206
|
+
|
|
207
|
+
## Durable state and reconciliation
|
|
208
|
+
|
|
209
|
+
`execution.json` version 1 records task/provider/account ownership, current run,
|
|
210
|
+
operations, stop fence and cumulative allowance. Each operation records the input
|
|
211
|
+
fingerprint, canonical run ID, deterministic idempotency key, intent timestamp,
|
|
212
|
+
input head and acceptance (`unknown` or `accepted`). Intent is atomically persisted
|
|
213
|
+
before submit/continue. Issued preparation receipts live in `preparations`, keyed
|
|
214
|
+
by their exact input fingerprints; intake execution metadata records its receipt
|
|
215
|
+
and `kind`. Task attempts retain receipts, reservations and cached execution
|
|
216
|
+
observations. Legacy scalar receipts remain valid only for the selected adapter's
|
|
217
|
+
declared boundary; another provider's receipt cannot authorize readiness,
|
|
218
|
+
answers, dispatch or recovery. The process-identity lock serializes mutations on the
|
|
219
|
+
operator's local filesystem; this is not a distributed multi-host lease.
|
|
220
|
+
|
|
221
|
+
Accepted execution metadata in both the registry and compatible `job.json`
|
|
222
|
+
contains transport kind, exact job/session/root-turn IDs, environment/model/policy, provider state,
|
|
223
|
+
nullable `observedAt`, `reconciledAt`, `nextAttemptAt`, failures, cursor, nullable
|
|
224
|
+
cost, collected/quarantined flags, controls and saved workflow ownership. Saved
|
|
225
|
+
workflow cursors recover a correction accepted before registry acknowledgement.
|
|
226
|
+
A repeated operation with identical input reuses its acknowledgement; changed
|
|
227
|
+
input conflicts. A trusted transport can mark a local refusal with
|
|
228
|
+
`dispatchNotSentError` only before persisting its transport operation and before
|
|
229
|
+
every provider request. The shared boundary then restores the prior root and
|
|
230
|
+
allowance, removes the unsubmitted projection, and retains the latest twenty
|
|
231
|
+
private `dispatchRefusals` (operation/run IDs, timestamp and code). Initial start
|
|
232
|
+
and review dispatch stop with `dispatch-refused`; repair the prerequisites and
|
|
233
|
+
explicitly resume. The same authorized operation can also be retried through the
|
|
234
|
+
shared service across restart. This release does not apply to provider setup
|
|
235
|
+
requests, lost replies, unmarked errors or an unproven deadline.
|
|
236
|
+
Remote start consumes its clone claim into a registered `launch-preparation` entry
|
|
237
|
+
before source delivery and read-only provider preparation. `initial_dispatch`
|
|
238
|
+
version 1 retains the original start-token operation and `unsubmitted` status.
|
|
239
|
+
`unsubmittedInitialDispatch` verifies that token, the entry's sessionless ownership
|
|
240
|
+
and an empty, unstopped execution ledger before CLI/control/tracker resume can
|
|
241
|
+
authorize the first submission. Existing private refusal proof also recovers older
|
|
242
|
+
initial refusal entries. The shared coordinator rebuilds verified current inputs
|
|
243
|
+
from the saved approved brief, changes the marker to `dispatching` before submit,
|
|
244
|
+
and clears it after acceptance or exact startup reconciliation. Proven pre-send
|
|
245
|
+
refusals restore `unsubmitted`; unknown acceptance keeps its recorded intent and
|
|
246
|
+
cannot start another session. Partial/unknown clone failures still retain their
|
|
247
|
+
original claim for inspection rather than silently deleting an owned checkout.
|
|
248
|
+
Unknown acceptance never authorizes another dispatch. Startup
|
|
249
|
+
and periodic lookup reconcile it; without authoritative lookup an operator must
|
|
250
|
+
inspect the recorded key and restore exact ownership. Never manually delete an
|
|
251
|
+
acceptance-unknown intent to force a retry. Remote submission/continuation acknowledgements and every lookup
|
|
252
|
+
or observation require nonempty string job and root-turn IDs. A job-only reply
|
|
253
|
+
keeps its reservation and unresolved intent. Incomplete older remote records
|
|
254
|
+
must recover the root through the intent lookup; job-level inspection or cached
|
|
255
|
+
results cannot fill that identity. Collection validates saved results against the
|
|
256
|
+
exact task/run/job/root turn as well as newly retrieved results. Raw job projections
|
|
257
|
+
use the recorded transport kind (or canonical registry for older records) and
|
|
258
|
+
cannot treat an unresolved remote root as terminal; CLI runs need no root-turn ID.
|
|
259
|
+
Reported remote sessions must be nonempty strings and match an already recorded
|
|
260
|
+
session. Omitted/null sessions retain that identity; the first reported session
|
|
261
|
+
may establish it when none is known. The same check protects acknowledgement,
|
|
262
|
+
lookup, inspection, fresh/cached collection and shared publication, before events
|
|
263
|
+
or usage are adopted. A foreign reply cannot authorize a native continuation.
|
|
264
|
+
|
|
265
|
+
For local adapters that do not echo a session ID, the boundary retains the session
|
|
266
|
+
minted by the existing start path. Legacy continuation uses the recorded registry
|
|
267
|
+
session for that same provider/root, or its native output identity. An active
|
|
268
|
+
legacy writer still fences dispatch; a foreign session cannot be substituted.
|
|
269
|
+
|
|
270
|
+
Provider states are `queued`, `provisioning`, `running`, `waiting-for-input`,
|
|
271
|
+
`retrieving-results`, `succeeded`, `failed`, `cancellation-requested`, `cancelled`
|
|
272
|
+
and `status-unknown`. They are separate from existing workflow/review states.
|
|
273
|
+
Stale reads, missing events, launcher exit, a cached response or silence cannot
|
|
274
|
+
complete a remote turn. Both success and failure enter retrieval until an exact
|
|
275
|
+
finished result is saved; `terminalState` retains the authoritative root outcome
|
|
276
|
+
while workflow settlement waits. Fresh and cached results must agree with that
|
|
277
|
+
outcome before persistence or settlement; the shared PR writer enforces the same
|
|
278
|
+
check before artifact or GitHub operations. A contradictory result stays
|
|
279
|
+
unresolved with `EXECUTION_RESULT`, retaining its observation, ownership and
|
|
280
|
+
allowance without authorizing another run. A later inspection cannot replace
|
|
281
|
+
the retained terminal state. Older collected records whose state contradicts
|
|
282
|
+
their retained observation re-enter retrieval; their private cache remains for
|
|
283
|
+
inspection and cannot authorize publication. Records without exact job/root
|
|
284
|
+
ownership cannot retain a qualified terminal claim; lookup must establish that
|
|
285
|
+
identity and its authoritative completion before a cache can settle it.
|
|
286
|
+
Correct the provider's exact owned
|
|
287
|
+
result before retrying collection; do not erase identities or redispatch.
|
|
288
|
+
Failure diagnostics, denials, usage and recovered
|
|
289
|
+
session identity survive collection and cached-result replay. `collectedAt` records
|
|
290
|
+
durable retrieval separately from owned completion/observation timestamps, so
|
|
291
|
+
restart does not lose cost, session or completion time. Older failure records claiming collection without a
|
|
292
|
+
result re-enter retrieval without redispatch. Failed artifacts remain private;
|
|
293
|
+
only a successful collected outcome can enter the shared publication path. A
|
|
294
|
+
stop during terminal result retrieval or after collection quarantines the result
|
|
295
|
+
without issuing a cancellation call for a root already known to have finished.
|
|
296
|
+
Foreign job/session/root-turn observations refuse reconciliation. Unavailable
|
|
297
|
+
status carries timestamps, retry time and recovery action rather than fabricated
|
|
298
|
+
liveness. Terminal collected results survive log removal.
|
|
299
|
+
|
|
300
|
+
Local settlement, collection, cached replay and session reads apply the same
|
|
301
|
+
session ownership rule before adopting an identity. A reported ID must match
|
|
302
|
+
the preassigned or previously discovered session; omitted IDs retain it. An
|
|
303
|
+
anonymous first turn may establish a nonempty string ID. Legacy runs use their
|
|
304
|
+
recorded registry session, and submission acknowledgements retain preassigned
|
|
305
|
+
identities across restart. A mismatch raises `EXECUTION_RESULT`, rejects result
|
|
306
|
+
adoption and prevents continuation into the foreign session. Restore
|
|
307
|
+
the exact owned stream/cache evidence before retrying; never transplant sessions.
|
|
308
|
+
|
|
309
|
+
## Scheduling and limits
|
|
310
|
+
|
|
311
|
+
Configuration may override the integer `execution` limits validated by
|
|
312
|
+
`lib/config.mjs`; `EXECUTION_LIMITS` is the default. Per-operation transport and
|
|
313
|
+
health deadlines are 20 seconds, progress cadence 10 seconds, maximum exponential
|
|
314
|
+
backoff 5 minutes with jitter/Retry-After, concurrency 4, event pages 100 records
|
|
315
|
+
and 64 KiB. Native standalone CLI version/sign-in probes keep their compatible
|
|
316
|
+
20-second subprocess bound; coordinator probes also honor the configured
|
|
317
|
+
abort deadline. The shared default includes native verification startup, which
|
|
318
|
+
can exceed two seconds on a healthy host. Explicit shorter deadlines still apply,
|
|
319
|
+
and timed-out submissions retain their unknown-acceptance fences. Remote standalone
|
|
320
|
+
probes use the configured `execution.deadlineMs`
|
|
321
|
+
for their entire serial access check, or 10 seconds when none is configured; an
|
|
322
|
+
earlier caller signal is retained. The configurable transport ceiling is 120
|
|
323
|
+
seconds. Snapshotting hosts may explicitly use 60 seconds when each outbound
|
|
324
|
+
request carries several seconds of authorization and persistence latency. This
|
|
325
|
+
does not increase task runtime/spend allowances or replace durable lost-reply
|
|
326
|
+
reconciliation. Health is persisted per provider **and account**. A success stops
|
|
327
|
+
authorizing dispatch at its saved `nextAttemptAt`, before the due refresh starts
|
|
328
|
+
and while it waits for a probe worker or reply. Read-only health checks enforce
|
|
329
|
+
that deadline across restart without probing or changing the saved observation.
|
|
330
|
+
Fresh scopes remain independent; failed checks retain their backoff and remedy.
|
|
331
|
+
The shared fix/resume path rechecks health after checkout, credentials, input-head
|
|
332
|
+
and remote preparation, immediately before submit/continue or local launch. A
|
|
333
|
+
failure at that boundary leaves feedback and run ownership available for retry
|
|
334
|
+
on the existing coordinator schedule, without a submission intent or paid call.
|
|
335
|
+
|
|
336
|
+
One coordinator tick has separate bounded progress and GitHub review worker
|
|
337
|
+
lanes. Provider checks run alongside them and register due scopes before the
|
|
338
|
+
tick. Dispatches waiting on health leave the review workers free. A bounded
|
|
339
|
+
dispatch lane joins only those already scheduled scoped probes, then retries
|
|
340
|
+
once after the observation is persisted. It uses the same dispatch function,
|
|
341
|
+
rechecks registry ownership and stop fences, and never starts probes itself.
|
|
342
|
+
A successful refresh can release work in that tick; failures preserve the
|
|
343
|
+
feedback cursor for the next review interval. Progress polling is independent of
|
|
344
|
+
`poll_seconds`, which still schedules entry review and chain merge/ancestry reads.
|
|
345
|
+
Each tick instance checks chains immediately on boot, then at most once per
|
|
346
|
+
review interval; failed chain checks consume retries only on that schedule.
|
|
347
|
+
GitHub authentication health has a separate bounded lane and `github-health.json`
|
|
348
|
+
scope keyed by the startup login. It refreshes on `poll_seconds` with the same
|
|
349
|
+
backoff/deadline rules, publishes `probes.gh` in daemon status and retains the
|
|
350
|
+
existing `gh not ready` notification and authentication remedy. It cannot consume
|
|
351
|
+
provider probe workers or fence unrelated execution progress. The native GitHub
|
|
352
|
+
probe receives the abort signal, including a credential lookup that finishes
|
|
353
|
+
after its deadline. Status/UI reads only persisted observations and never probe.
|
|
354
|
+
Startup forces reconciliation
|
|
355
|
+
once, then saved retry times govern subsequent inspection. Provider failures do
|
|
356
|
+
not globally suppress ticks. UI polling reads these persisted results.
|
|
357
|
+
|
|
358
|
+
## Journal, projections and retention
|
|
359
|
+
|
|
360
|
+
Each new run retains compatible `job.json`/`job.log` plus:
|
|
361
|
+
|
|
362
|
+
| File | Contract |
|
|
363
|
+
| --- | --- |
|
|
364
|
+
| `events.jsonl` | Version 1 redacted normalized records: task/run/provider, event ID, ingestion sequence, provider sequence, provenance and timestamp |
|
|
365
|
+
| `journal.json`, `event-keys/` | Durable append checkpoint and hashed exact provider/job/turn/event replay keys; interrupted append becomes an explicit gap |
|
|
366
|
+
| `job.idx`, `log-meta.json` | Fixed-width 8-byte offsets, version 2 offset-plus-one encoding, stable sequence numbers and retained first sequence; zero entries denote gaps |
|
|
367
|
+
| `local-output.json` | Raw local ingestion byte cursor, bounded page, pending marker and persistent `discarding` state |
|
|
368
|
+
| `local-output-queue.json` (task run root) | Version 1 ordered local run IDs awaiting projection or private-file cleanup; persisted before replacing `latest-run` |
|
|
369
|
+
| `result.json` | Mode 0600 private collected result, exact ownership fields and artifact manifest/payloads, redacted diagnostics and `artifacts` summary; independent of retained logs |
|
|
370
|
+
| `result-application.json`, `verification.json` | Artifact application/publication checkpoint and actual approved verification observations |
|
|
371
|
+
|
|
372
|
+
Provider-order numbers survive out-of-order arrival; ingestion order remains
|
|
373
|
+
monotonic. Replay keys survive restart and projection retention. Rotation,
|
|
374
|
+
truncation, missing indexes, oversized records and unrecoverable interrupted
|
|
375
|
+
history produce explicit gaps rather than renumbering replay IDs or inventing
|
|
376
|
+
output. Redaction occurs before journals, public projections and saved evidence,
|
|
377
|
+
using recognized credentials and supplied resolved secret values.
|
|
378
|
+
Overlapping supplied values are replaced longest first without changing the
|
|
379
|
+
caller's secret list, so environment order cannot expose a credential suffix.
|
|
380
|
+
Verification merges coordinator environment and execution/run secrets in one
|
|
381
|
+
redaction pass via `sanitize(value, runId, extraSecrets = [])`; existing callers
|
|
382
|
+
can omit the extra list.
|
|
383
|
+
Artifact paths, hashes and text retain the provider's exact bytes in the private
|
|
384
|
+
result. Diagnostic redaction never rewrites publication input. The coordinator still checks original
|
|
385
|
+
hashes and ownership before application. Modified/truncated content cannot publish.
|
|
386
|
+
The additive version 1 `artifacts` field is a redacted path/hash summary generated
|
|
387
|
+
by collection, overriding any provider-supplied summary. Tracker result responses
|
|
388
|
+
use this summary for artifacts and application paths, and never include file text.
|
|
389
|
+
The result route redacts its complete response through the execution's supplied
|
|
390
|
+
and retained run secrets, including ownership fields and publication checkpoints;
|
|
391
|
+
standalone run readers use recognized-credential redaction. These read-only views
|
|
392
|
+
never replace private routing identities or call a provider.
|
|
393
|
+
Legacy results without the summary retain their already-redacted projection.
|
|
394
|
+
Verification output also uses the execution boundary's supplied-secret redaction.
|
|
395
|
+
Previously modified cached artifacts remain invalid; restore exact artifacts for
|
|
396
|
+
the recorded provider job/root turn before publication, without redispatching.
|
|
397
|
+
|
|
398
|
+
Journal append recovery reads at most 65,537 bytes at the saved pending offset.
|
|
399
|
+
An invalid or partial pending record is removed by truncating to that offset
|
|
400
|
+
before a complete gap record replaces it. Previously acknowledged bytes remain
|
|
401
|
+
intact. A complete pending record with a missing newline receives its delimiter
|
|
402
|
+
before another event can append. Recovery and subsequent replay preserve the
|
|
403
|
+
original sequence/event ID and do not append a second replacement gap. If an
|
|
404
|
+
existing journal is shorter than the acknowledged offset, recovery refuses and
|
|
405
|
+
preserves it: restore its matching backup before replay instead of extending
|
|
406
|
+
the file with zero bytes or claiming a damaged prefix was repaired.
|
|
407
|
+
|
|
408
|
+
Completed local output may outlive its current-run pointer. Before a successor
|
|
409
|
+
can save an execution intent or start, the runner preserves the old run in
|
|
410
|
+
`local-output-queue.json` while output is pending or either private diagnostic
|
|
411
|
+
file remains, including drained and empty logs. Coordinator reconciliation drains
|
|
412
|
+
one queued run page and one current-run page, each at most 100 records and 262,144
|
|
413
|
+
raw bytes (200 records and 524,288 bytes per observation; maximum single buffer
|
|
414
|
+
262,144 bytes). Runs awaiting projection or cleanup rotate through the queue;
|
|
415
|
+
drained runs check expiry without reading diagnostic bytes or rewriting journals.
|
|
416
|
+
Journal byte-position identities and atomic checkpoints make restart/replay
|
|
417
|
+
duplicate-free. The queue is serviced even when legacy execution metadata has
|
|
418
|
+
no current record. Public status, tail and history reads do not ingest diagnostics
|
|
419
|
+
or mutate this queue.
|
|
420
|
+
Results settle independently of this backlog, so a large old log cannot postpone
|
|
421
|
+
unrelated execution or GitHub review. Unsupported queue versions, invalid cursors
|
|
422
|
+
and queue persistence errors preserve diagnostics and refuse a new paid intent;
|
|
423
|
+
restore the matching compatible package/checkpoint before dispatch or replay.
|
|
424
|
+
|
|
425
|
+
An oversized raw local record emits one stable gap at its starting byte ID.
|
|
426
|
+
`discarding: true` then consumes bounded pages through that record's newline;
|
|
427
|
+
no suffix can enter normalized history or the public projection. At an active
|
|
428
|
+
EOF the flag remains pending until a delimiter or confirmed local exit. A final
|
|
429
|
+
unterminated oversized record is discarded through EOF. Restart, queue rotation
|
|
430
|
+
and cursor acknowledgement replay retain this state. Older mid-record cursors
|
|
431
|
+
are recognized with a one-byte lookbehind inside the same per-page read budget
|
|
432
|
+
and discard the remaining continuation. Invalid discard state refuses dispatch
|
|
433
|
+
or replay with the checkpoint/backup remedy.
|
|
434
|
+
|
|
435
|
+
Private local diagnostics use `provider.log` and `sensitive-redactions.json`
|
|
436
|
+
(mode 0600 in the private run tree). They are excluded from routes/projections.
|
|
437
|
+
The redaction metadata records a 24-hour expiry; coordinator observation removes
|
|
438
|
+
expired diagnostics once a durable result exists, retaining the queue item until
|
|
439
|
+
both private files have been removed. Removal failures preserve the item for a
|
|
440
|
+
later coordinator retry. If redaction metadata is missing, the owned job's start
|
|
441
|
+
time supplies the 24-hour expiry; missing metadata never authorizes raw projection.
|
|
442
|
+
If queued bytes expire before projection, or diagnostics/redaction metadata are
|
|
443
|
+
missing or truncated, the coordinator appends a stable explicit gap and retains
|
|
444
|
+
any remaining private files for expiry cleanup. Results, job outcomes, session
|
|
445
|
+
identity and public history
|
|
446
|
+
survive this cleanup, and read-only routes cannot trigger it. The version 1 queue
|
|
447
|
+
format remains compatible. Runs already omitted from the queue by an older
|
|
448
|
+
package require explicit retention maintenance: after checking expiry and a
|
|
449
|
+
durable `result.json`, remove only `provider.log` and `sensitive-redactions.json`.
|
|
450
|
+
Never remove result/application evidence or change `latest-run` for cleanup.
|
|
451
|
+
Legacy raw local files keep their existing runner semantics.
|
|
452
|
+
|
|
453
|
+
Public tail/history reads are capped at 400 lines, 256 KiB data plus at most
|
|
454
|
+
3,208 index bytes, 64 KiB per encoded line. JSON escaping is included in response
|
|
455
|
+
budgets. Large legacy logs without indexes use a bounded suffix and explicit
|
|
456
|
+
byte-position replay IDs; small legacy logs preserve numeric line IDs. New logs
|
|
457
|
+
always have stable numeric journal sequence IDs. An absent index with existing
|
|
458
|
+
metadata is an explicit recovery gap, not a legacy renumbering fallback.
|
|
459
|
+
|
|
460
|
+
Existing `/api/run/output`, `/api/run/log`, `/api/run/history` and
|
|
461
|
+
`/api/run/status` routes remain compatible, including mount prefixes and foreign
|
|
462
|
+
configured run trees. `Last-Event-ID` resumes replay; history's `before` cursor
|
|
463
|
+
paginates older windows. SSE has a 20-second heartbeat, a 320 KiB pending-buffer
|
|
464
|
+
cap, pauses file reads on backpressure, and removes watchers/timers/listeners on
|
|
465
|
+
disconnect. The browser caps live and history DOM at 2,000 lines each and pending
|
|
466
|
+
lines at 400. Buffered events retain their SSE replay IDs. Display drops coalesce
|
|
467
|
+
into a bounded pair of recovery cursors, separate from the oldest history cursor;
|
|
468
|
+
the existing history button retrieves the missing windows without a `skipped`
|
|
469
|
+
frame. Each rendered row keeps its event replay ID and stable position within
|
|
470
|
+
that event. History restores missing row positions even when a sibling remains,
|
|
471
|
+
merges by event ID and row position, avoids duplicates with painted/pending rows
|
|
472
|
+
and preserves older pagination through bursts and reconnects, including legacy
|
|
473
|
+
byte IDs. DOM eviction also exposes recoverable history. A failed history read
|
|
474
|
+
retains its cursor; page exit aborts the read and discards pending/late frames.
|
|
475
|
+
`/api/run/result` exposes saved outcomes, artifact hashes and
|
|
476
|
+
verification evidence after log retention, without exposing raw diagnostics.
|
|
477
|
+
|
|
478
|
+
## Controls, costs and publication
|
|
479
|
+
|
|
480
|
+
`cancel` queues a protected operator control and immediately fences dispatch.
|
|
481
|
+
|
|
482
|
+
The final publication step and cancellation queueing share an entry-scoped
|
|
483
|
+
`publication.lock` using the existing process-identity lock helper. Publication
|
|
484
|
+
takes this lock before `execution.lock`, rechecks registry and private stop/root
|
|
485
|
+
ownership, and holds both through branch push, PR write and the published
|
|
486
|
+
checkpoint. An accepted cancellation precedes and prevents these writes. Once
|
|
487
|
+
publication has started, cancellation returns `EXECUTION_PUBLICATION_BUSY` with
|
|
488
|
+
a retry message and saves no request/fence; retry after publication completes.
|
|
489
|
+
Direct cancellation/continuation also cannot enter its execution lock. Provider
|
|
490
|
+
inspection holds only `execution.lock`, so operator cancellation can still queue
|
|
491
|
+
while progress I/O runs. Other entries remain independent. Both locks release
|
|
492
|
+
after success, failed I/O/checkpoint writes or contention; dead process owners
|
|
493
|
+
use existing identity-checked recovery, never elapsed-time expiry of a live lock.
|
|
494
|
+
|
|
495
|
+
The coordinator records cancellation requested before calling a supported transport,
|
|
496
|
+
then distinguishes authoritative confirmation from unsupported/unconfirmed
|
|
497
|
+
cancellation. Native local cancellation retains verified process-tree cleanup;
|
|
498
|
+
active runs carried across an upgrade are adopted with their exact local run and
|
|
499
|
+
session identity before cancellation. This stop-only record has `legacy: true`,
|
|
500
|
+
`operationId: null`, unknown cost and no invented submission intent. Cancellation
|
|
501
|
+
remains requested while owned descendants survive or inspection is unavailable;
|
|
502
|
+
restart reconciliation confirms only the same observed run and quarantines its
|
|
503
|
+
late output. A kill request alone never confirms cessation.
|
|
504
|
+
Coordinator reconciliation also resumes the runner's persisted `killAfter`
|
|
505
|
+
fallback when its original timer owner exited. The existing process-identity
|
|
506
|
+
checks still refuse reused PIDs or unavailable inspection, and the same owned
|
|
507
|
+
run remains cancellation-requested until its descendants are confirmed stopped.
|
|
508
|
+
If a launch reply was lost, reconciliation first records exact local acceptance
|
|
509
|
+
and then initiates any already-requested supported stop, even when no kill was
|
|
510
|
+
previously started. Unsupported stops and mismatched jobs remain fenced; failed
|
|
511
|
+
process inspection remains pending for later coordinator reconciliation.
|
|
512
|
+
Read-only status/history access never signals a process.
|
|
513
|
+
Cancelling after a local run has been collected preserves its success/failure,
|
|
514
|
+
exit, end time, result, usage and session; only future dispatch is fenced. No
|
|
515
|
+
process stop is requested for that completed run, including when cancellation
|
|
516
|
+
capability is unavailable. Restart reconciliation preserves the same historical
|
|
517
|
+
outcome. Completed pre-boundary local jobs also retain their original files and
|
|
518
|
+
identity without an invented stop/adoption record. Active local stops still
|
|
519
|
+
require exact process-tree confirmation and quarantine their late results.
|
|
520
|
+
If an owned local job has already exited before collection, cancellation saves
|
|
521
|
+
its exact exit/end-time snapshot and the future-dispatch fence, then uses the
|
|
522
|
+
same local settlement helper to retain its outcome, usage and session. A failed
|
|
523
|
+
cache write remains in `retrieving-results`; restart reconciliation or a repeated
|
|
524
|
+
cancel completes that saved snapshot. This requires the matching job, an actual
|
|
525
|
+
recorded exit and no prior active stop. Uncertain exits and output arriving after
|
|
526
|
+
an active stop retain the existing cancellation/quarantine path.
|
|
527
|
+
Remote cancellation never equates stopping a submission client with stopping its
|
|
528
|
+
job. The additive `execution.cancellation` record stores status (`pending`,
|
|
529
|
+
`acknowledged`, `confirmed`, `unsupported` or `terminal`), request reason/time,
|
|
530
|
+
idempotency key, attempt/failure counts and retry times. A stop requested during
|
|
531
|
+
unknown submission acceptance remains pending. Authoritative lookup first saves
|
|
532
|
+
exact owned job/root identity, then the existing coordinator sends the stop.
|
|
533
|
+
Lost stop replies retry the same key under bounded backoff; transports must make
|
|
534
|
+
that cancellation key idempotent. An acknowledged unconfirmed stop is inspected
|
|
535
|
+
until cancellation is authoritative, without resending every tick. Unsupported
|
|
536
|
+
stops never call the transport. Natural completion still quarantines the output
|
|
537
|
+
and records `terminal`, without claiming cancellation. Applied control receipts
|
|
538
|
+
are updated when the matching run's later reconciliation confirms cancellation
|
|
539
|
+
or observes natural completion. `cancel()` returns `{confirmed: false,
|
|
540
|
+
terminal: true}` for an already ended remote root, distinguishing it from an
|
|
541
|
+
unconfirmed live stop. The operator task is stopped with reason `cancelled` and
|
|
542
|
+
a receipt stating that provider execution had already completed; its historical
|
|
543
|
+
provider success/failure, exit, completion time and collected result remain
|
|
544
|
+
unchanged. Existing pending receipts are repaired only for their matching run.
|
|
545
|
+
No read-only client drives this recovery. Interrupted continuity requires native
|
|
546
|
+
capability and exact session ownership.
|
|
547
|
+
Cancelled/timed-out work cannot overlap a replacement; late results are
|
|
548
|
+
quarantined. A requested deadline abort leaves unknown acceptance unresolved.
|
|
549
|
+
|
|
550
|
+
A local implementation `timeout` fences dispatch while its owned process tree
|
|
551
|
+
is stopping. Cancellation or restart reconciliation releases only this timeout
|
|
552
|
+
fence after the exact matching local run is confirmed non-live; missing/different
|
|
553
|
+
runs, surviving descendants and unreadable process state keep it fenced. The
|
|
554
|
+
timed-out run remains collected and quarantined, so late success or a saved
|
|
555
|
+
result cannot rewrite settlement or qualify publication. The canonical timeout
|
|
556
|
+
stop and stranded-work diagnostics remain on the entry; explicit `resume` can
|
|
557
|
+
then continue the same session in its existing branch/worktree. This also repairs
|
|
558
|
+
older local timeout fences on reconciliation. Operator cancellation, preparation
|
|
559
|
+
allowance stops and remote timeout fences remain in force. A later timeout retry
|
|
560
|
+
cannot replace an operator or preparation stop with a recoverable timeout.
|
|
561
|
+
|
|
562
|
+
Remote dispatch requires a positive reservation and positive finite remaining
|
|
563
|
+
allowance. Reservations accumulate durably, including unknown usage; they are not
|
|
564
|
+
released on missing cost. Accounting charges the greater of each reservation and
|
|
565
|
+
its reported usage, preserves higher prior usage and deduplicates repeated reads.
|
|
566
|
+
Execution metadata and settlement outcomes retain the maximum finite nonnegative
|
|
567
|
+
cost reported for the exact run. Missing, invalid or lower observations and
|
|
568
|
+
collected estimates cannot erase known spend. Private results preserve the
|
|
569
|
+
provider's reported cost; `outcome(runId)` and the tracker result projection
|
|
570
|
+
combine it with that run's durable operation cost, including after restart or
|
|
571
|
+
when a subsequent turn is active. These reads never poll a provider.
|
|
572
|
+
Older regressed projections recover known cost from their owned operation.
|
|
573
|
+
Unknown cost remains null and is never reported as zero.
|
|
574
|
+
An exhausted allowance refuses further dispatch. Future providers must enforce
|
|
575
|
+
any mandatory hard cap in their declared capability; this boundary does not
|
|
576
|
+
advertise billing enforcement a transport cannot provide.
|
|
577
|
+
|
|
578
|
+
Shared result publication validates task/run/root-turn/input-head ownership,
|
|
579
|
+
repository origin, task branch/base, paths/symlinks and artifact content/base
|
|
580
|
+
hashes before mutation. Every artifact target is canonicalized with the shared
|
|
581
|
+
repository containment/symlink validator before any content is read. Equivalent
|
|
582
|
+
spellings (`a.txt`, `./a.txt`, repeated separators) cannot name duplicate targets.
|
|
583
|
+
The manifest also rejects paths that collide after NFC normalization and Unicode
|
|
584
|
+
upper/lower folding, including file or parent-directory case aliases. This is a
|
|
585
|
+
conservative portable manifest rule on every filesystem, including case-sensitive
|
|
586
|
+
checkouts: distinct files with ambiguous case/Unicode spellings require separate
|
|
587
|
+
results. A single accepted path keeps its casing and original artifact bytes;
|
|
588
|
+
application, commit paths and lost-acknowledgement reconciliation use the same
|
|
589
|
+
canonical Git-relative paths. The private provider manifest remains unchanged.
|
|
590
|
+
Each target component is also compared with tracked HEAD and index paths before
|
|
591
|
+
content reads or mutation. A single artifact cannot introduce a case/Unicode
|
|
592
|
+
alias of an existing file or parent directory, including a directory with a
|
|
593
|
+
different child filename or a file/directory collision. Exact tracked spelling
|
|
594
|
+
remains valid for edits and deletions. The same check runs before publication
|
|
595
|
+
recovery; pushed results validate their complete tracked tree. Published receipt
|
|
596
|
+
replay remains read-only. Missing or incomplete metadata blocks publication.
|
|
597
|
+
Git path reads use NUL separators, preserving spaces and newlines, with a
|
|
598
|
+
2-second deadline and 1 MiB output cap per HEAD/index query. Ownership checks on
|
|
599
|
+
staged and changed paths reuse that bounded reader without trimming filenames.
|
|
600
|
+
Text-only manifests preserve each target's input Git mode (`100644` or `100755`);
|
|
601
|
+
new files use `100644`. Before reading payloads or applying changes, the shared
|
|
602
|
+
Git helper compares input, current HEAD and index modes with the actual regular
|
|
603
|
+
file's owner executable bit. Uncommitted, staged and already-committed mode
|
|
604
|
+
changes cannot be adopted into a text result, even when its content hash matches.
|
|
605
|
+
Missing, malformed or incomplete mode metadata refuses publication; tree/index
|
|
606
|
+
records reuse the NUL reader's 2-second and 1 MiB limits. The same guard covers
|
|
607
|
+
lost commit replies and verified-result replay. Exact-mode edits/deletions and
|
|
608
|
+
regular creations remain recoverable; pushed revisions describe their own modes.
|
|
609
|
+
Applied content and input ancestry reconcile lost commit
|
|
610
|
+
acknowledgements. Only existing Git/GitHub helpers commit, push and reconcile one
|
|
611
|
+
regular PR. Approved immutable PRD Verify commands run in the owned checkout
|
|
612
|
+
with real exit/output/timestamp/revision evidence (120-second, 256 KiB command
|
|
613
|
+
bounds). They use a fixed non-login POSIX shell (`/bin/sh -c`), preserving the
|
|
614
|
+
approved command text without selecting the operator's `SHELL` or sourcing login
|
|
615
|
+
startup files. Verify commands must use POSIX shell syntax and explicitly invoke
|
|
616
|
+
any other interpreter they need. Provider assertions are not verification
|
|
617
|
+
evidence. Verification receives an explicit allowlist of PATH, locale, timezone,
|
|
618
|
+
terminal/color and CI settings. Coordinator tokens, provider credentials,
|
|
619
|
+
proxies, SSH agents, shell startup and Node injection variables are excluded.
|
|
620
|
+
An empty private HOME/XDG/temp profile exists for the command list and is removed
|
|
621
|
+
on success, failure, dirty-tree rejection or cancellation. Existing Git/tooling
|
|
622
|
+
environment helpers disable system/global credential stores, interactive auth
|
|
623
|
+
and user npm configuration; repository credential helpers are reset too.
|
|
624
|
+
Verification also requires an OS filesystem/network sandbox. macOS uses
|
|
625
|
+
`/usr/bin/sandbox-exec` with the installed `dyld-support.sb` loader rules and a
|
|
626
|
+
deny-default profile. Linux uses `/usr/bin/bwrap` with isolated user, PID, IPC and
|
|
627
|
+
network namespaces and a private mount tree. Only the checkout and private
|
|
628
|
+
verification profile are writable; fixed system tools/libraries, the running
|
|
629
|
+
Node binary and its npm package are readable. Git metadata is hidden or denied.
|
|
630
|
+
PATH is limited to that Node installation, `/usr/bin` and `/bin`; arbitrary
|
|
631
|
+
operator PATH entries and configuration directories are not granted. Commands
|
|
632
|
+
needing other tools must use an isolated supported runtime installation rather
|
|
633
|
+
than broadening access to an operator home. Network-dependent Verify commands
|
|
634
|
+
fail: fetch dependencies in the approved execution environment or use installed
|
|
635
|
+
checkout dependencies for offline verification.
|
|
636
|
+
Before repository code runs, a bounded trusted probe checks private writes,
|
|
637
|
+
denied outside reads/writes and host TCP isolation. No missing executable,
|
|
638
|
+
namespace restriction or failed probe can fall back to an ordinary host shell.
|
|
639
|
+
It records `verification-sandbox-unavailable`, preserves the applied revision
|
|
640
|
+
and saved results, and requires explicit operator recovery after host repair.
|
|
641
|
+
Success/failure evidence records the sandbox driver and enforcement probe.
|
|
642
|
+
Recovered `verified` checkpoints lacking this provenance block before push;
|
|
643
|
+
completed commands are never silently replayed. Empty Verify lists still record
|
|
644
|
+
no test claim. The profile and probe files are removed on every exit.
|
|
645
|
+
Git checks use an immutable temporary `GIT_DIR` containing only the exact current
|
|
646
|
+
commit/tree/blob objects and a reconstructed index; the real Git directory or
|
|
647
|
+
linked-worktree pointer stays hidden. Config, hooks, remotes, reflogs, alternate
|
|
648
|
+
stores and ancestor history are not copied. The shared process helper preserves
|
|
649
|
+
binary Git object bytes, and the same native read-only policy protects the view
|
|
650
|
+
on macOS and Linux. macOS Git additionally requires its fixed installed Command
|
|
651
|
+
Line Tools runtime. The view has bounded object count, bytes and preparation time
|
|
652
|
+
and is removed on success, refusal, command failure and stop.
|
|
653
|
+
Remote readiness also exercises this enforcement in disposable directories with
|
|
654
|
+
the same empty verification environment and a trusted empty Git commit; actual
|
|
655
|
+
Git reads and denied index writes prove that the runtime and read-only metadata
|
|
656
|
+
boundary work before cloning. Doctor and initial start check before
|
|
657
|
+
API access or cloning; manual resume and review dispatch check before checkout
|
|
658
|
+
recreation or base merging, and the managed transport checks before new provider
|
|
659
|
+
dispatch. Failed/unproven/aborted probes refuse with
|
|
660
|
+
`EXECUTION_VERIFICATION_SANDBOX` and the existing OS/runtime remedy. No repository
|
|
661
|
+
code runs, and temporary profiles are removed on every path. Preparation and
|
|
662
|
+
provider-health records retain the successful probe evidence. Read-only progress,
|
|
663
|
+
artifact collection and cancellation remain available after host refusal. The
|
|
664
|
+
publication-time probe still verifies the actual applied checkout and descendants.
|
|
665
|
+
Manual resume uses full native/API readiness before recreation, merging,
|
|
666
|
+
resnapshot acceptance or reopening state. API refusal preserves the existing
|
|
667
|
+
brief/source snapshots and session/PR along with the checkout.
|
|
668
|
+
Hosted resume additionally refuses ordinary unfinished repository files before
|
|
669
|
+
merge or reopening; commit those intended edits on the owned branch and resume
|
|
670
|
+
the same session. Source preparation repeats this check for all dispatch paths,
|
|
671
|
+
allowing only approved brief/carried-source overlays with verified saved bytes.
|
|
672
|
+
An unanswered operator request uses the same durable signature/key on explicit retry: the
|
|
673
|
+
shared boundary calls optional `recoverResponse`, leaving transports without a
|
|
674
|
+
safe recovery method ambiguous. The managed adapter verifies the current owned
|
|
675
|
+
pending `ask_operator` call before replay, or confirms matching successful saved
|
|
676
|
+
output across bounded pages; an absent action alone never proves acceptance.
|
|
677
|
+
The canonical tick continues to own readiness, trusted feedback,
|
|
678
|
+
freshness, receipts, conflicts, rounds and human merge boundaries. No automatic
|
|
679
|
+
merge is added.
|
|
680
|
+
|
|
681
|
+
Permanent publication validation failures also persist a `blocked` checkpoint
|
|
682
|
+
with reason `result-validation`, retaining any previous fingerprint, applied head
|
|
683
|
+
and evidence. Invalid repository/branch ownership, paths, modes, hashes or public
|
|
684
|
+
text cannot be applied or retried on each poll. The publication boundary rejects
|
|
685
|
+
NUL bytes in raw PR titles and bodies before normalization or artifact application,
|
|
686
|
+
including pushed and previously verified results. Shared GitHub writers and
|
|
687
|
+
recovery-only metadata migration use the same NUL validation without rewriting
|
|
688
|
+
payloads or exposing rejected text in errors. The canonical needs-human lane
|
|
689
|
+
settles the provider's actual exit, cost and session, and an explicit same-session
|
|
690
|
+
resume starts correction without clearing the rejected result. Missing collection
|
|
691
|
+
results, unavailable Git metadata and ordinary I/O failures remain unresolved and
|
|
692
|
+
retryable. A failed checkpoint write cannot claim durable blocking or settlement.
|
|
693
|
+
|
|
694
|
+
Transports distinguish deterministic validation of a downloaded completed-turn
|
|
695
|
+
artifact with `collectionValidationError` from unavailable delivery or I/O.
|
|
696
|
+
The shared collection boundary persists an owned `blocked` checkpoint with reason
|
|
697
|
+
`result-collection-validation` before settling liveness. `resultRejected: true`
|
|
698
|
+
retains the authoritative root status and actual exit while reporting unsuccessful
|
|
699
|
+
delivery; no valid `result.json` is invented. The checkpoint restores settlement
|
|
700
|
+
after a crash between its write and execution/job projection writes, using exact
|
|
701
|
+
task/run/job/session/turn/input-head ownership. The coordinator refreshes that
|
|
702
|
+
run's state before entering the same `needs-human` corrective lane. Repeated polls
|
|
703
|
+
and rechecks cannot recollect rejected input; explicit same-session continuation
|
|
704
|
+
keeps the old rejection evidence and starts a new owned turn.
|
|
705
|
+
|
|
706
|
+
Verification requires the recorded applied commit and a clean Git index/worktree,
|
|
707
|
+
including untracked files. The existing strict Git status helper checks both
|
|
708
|
+
before commands, after each successful command and before PR publication; a
|
|
709
|
+
status failure blocks publication. Ignored build outputs remain subject to the
|
|
710
|
+
repository's own ignore rules. No verification-created edits are silently
|
|
711
|
+
committed, discarded or represented as part of the verified revision.
|
|
712
|
+
|
|
713
|
+
The application checkpoint advances through `applying`, `verifying`, `verified`
|
|
714
|
+
and `published`. A failed command, changed revision, dirty checkout or unavailable
|
|
715
|
+
status/evidence becomes `blocked`, with its reason and `blockedAt` timestamp.
|
|
716
|
+
Each completed command persists real evidence, including a failing exit or an
|
|
717
|
+
unknown exit on a transport error. A restart that finds `verifying` records
|
|
718
|
+
`verification-interrupted`: commands may have run and cannot be replayed safely.
|
|
719
|
+
The coordinator settles the provider run separately and enters `needs-human`
|
|
720
|
+
with reason `result-verification`; provider success and unknown cost stay truthful.
|
|
721
|
+
Polling, read-only projections and PR recheck cannot retry blocked verification.
|
|
722
|
+
Inspect the private checkpoint, evidence and retained checkout, then explicitly
|
|
723
|
+
resume the same session (or send a correction) to authorize a new corrective run.
|
|
724
|
+
The old run's blocked evidence remains intact. A push/PR acknowledgement failure
|
|
725
|
+
after `verified` retries only publication, requiring the same clean revision and
|
|
726
|
+
complete successful evidence for the approved command list. A published replay
|
|
727
|
+
returns the saved PR without executing commands again.
|
|
728
|
+
|
|
729
|
+
## Upgrade and rollback
|
|
730
|
+
|
|
731
|
+
1. Stop the coordinator and preserve its private home, registry, queued chain
|
|
732
|
+
snapshots, run trees and immutable PRD/source snapshots. Do not interrupt local
|
|
733
|
+
children merely to upgrade; their recorded identity survives launcher exit.
|
|
734
|
+
2. Install the compatible package and restart one coordinator. Legacy version 1
|
|
735
|
+
registry entries/local runs stay readable without changing task/PR/session IDs.
|
|
736
|
+
Startup reconciles recorded runs before paid dispatch. Review the status and
|
|
737
|
+
recovery action for every unresolved acceptance. A pre-upgrade `verifying`
|
|
738
|
+
checkpoint stops as interrupted; inspect its preserved evidence and explicitly
|
|
739
|
+
resume for correction instead of deleting it to rerun verification.
|
|
740
|
+
3. Back up the entire matching state before rollback. Older packages can retain
|
|
741
|
+
legacy local registry/job files, but must not operate active remote metadata or
|
|
742
|
+
new private-output runs they do not understand. Restore the matching package
|
|
743
|
+
and state backup together; do not clear run pointers, transplant sessions or
|
|
744
|
+
erase intents to make an old coordinator proceed.
|
|
745
|
+
4. An unsupported registry, execution, health, local output queue or journal version fails with an
|
|
746
|
+
actionable compatible-package/backup remedy. Preserve the original files and
|
|
747
|
+
resolve that version error before restarting; redispatch is not a migration.
|
|
748
|
+
|
|
749
|
+
Run `npm run test:execution-backends` for focused G3/G3a/G6 fixture coverage and the
|
|
750
|
+
full Verify set for regressions. [The foundation evidence](https://github.com/uchibeke/gallivant/blob/main/docs/audit/plugin-ready/execution-foundation.json)
|
|
751
|
+
is an offline G8 receipt, with live-provider status explicitly unqualified.
|
|
752
|
+
The [shared preparation follow-up](https://github.com/uchibeke/gallivant/blob/main/docs/audit/plugin-ready/execution-preparation.json)
|
|
753
|
+
records the owner correction, final verification and source/output review.
|
|
754
|
+
|
|
755
|
+
## Integration boundary and recorded milestone handoff
|
|
756
|
+
|
|
757
|
+
M3/M4 and APort must consume these shared preparation/submit/inspection/result/
|
|
758
|
+
control operations and the existing task service, without copying a runner or
|
|
759
|
+
adding a review engine. An implemented provider registers preparation version 1,
|
|
760
|
+
its concrete `boundary`, limited `authority` and remote `environment`; a CLI
|
|
761
|
+
adapter additionally supplies its enforced `render`, optional abortable
|
|
762
|
+
`configure` and required native minimum version. The context's `capabilitiesFor`
|
|
763
|
+
and `executionFor` must use that same registry. Mark provider availability only
|
|
764
|
+
after its implemented transport and required live evidence exist.
|
|
765
|
+
|
|
766
|
+
The restricted Codex preparation adapter introduced in
|
|
767
|
+
[`uchibeke/gallivant#10`](https://github.com/uchibeke/gallivant/pull/10) is registered
|
|
768
|
+
alongside the shared execution foundation and Agents API transport. Consume its
|
|
769
|
+
registry capability rather than copying its adapter or restoring a provider-name
|
|
770
|
+
gate. Drafting, questions and repairs already use the selected
|
|
771
|
+
provider through this shared execution contract. Validation/readiness remains
|
|
772
|
+
deterministic, and implementation still requires explicit authorization.
|
|
773
|
+
|
|
774
|
+
The [preparation qualification](preparation.md) records native Codex 0.160.0 checks
|
|
775
|
+
against a loopback provider, including inherited notifier and effective-policy
|
|
776
|
+
regressions. That evidence tests installed CLI/configuration
|
|
777
|
+
enforcement; it does not establish paid model access, managed preparation or
|
|
778
|
+
installed-plugin behavior. Preserve the operator's model/provider defaults,
|
|
779
|
+
limited preparation authority, bounded attempts and execution consent. Carry
|
|
780
|
+
unmet live qualification evidence forward rather than substituting fixtures.
|
|
781
|
+
|
|
782
|
+
The original M5/M6 handoff identified the following connected execution successor.
|
|
783
|
+
This is a recorded integration plan, not evidence that the external deployment
|
|
784
|
+
is live or its gates have passed. Check the linked PR and the consumer's current
|
|
785
|
+
release evidence before an installation:
|
|
786
|
+
|
|
787
|
+
The connected execution successor is
|
|
788
|
+
[`aporthq/agent-passport#417`](https://github.com/aporthq/agent-passport/pull/417),
|
|
789
|
+
with canonical PRD `docs/prds/aport-task-delivery-workflow-integration.md` and job
|
|
790
|
+
identity `aporthq/agent-passport/aport-task-delivery-workflow-integration`. It
|
|
791
|
+
preserves the original T0–T9 requirements; the recorded plan requires the actual
|
|
792
|
+
M5 portable artifact before its integration gate can pass. M6 must reuse it, pin the artifact's version, commit,
|
|
793
|
+
integrity and actual exports, connect existing APort authentication, regional
|
|
794
|
+
storage and shared UI to this task service and single coordinator, and qualify the
|
|
795
|
+
full workflow. No second runner, duplicate foundation job or other-repository
|
|
796
|
+
implementation is part of this API milestone.
|