| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 11m52s
The loop was a flat queue of independent tasks routed by kind. A flat queue is a work pool, not automation: nothing could express "transform after fetch, and never publish because fetch failed". `Task::after` names the steps a task waits on, and only an item whose every dependency is `Done` is dispatched. An edge is one task id naming another in this run, resolved against the run's own journal — not an endpoint in someone else's system. That is the whole point of putting the graph here rather than in an integration fabric: the fabrics put their edges across trust boundaries they do not own, which is where their failures live, and an edge that does not cross a boundary cannot fail at one. A step whose dependency did not complete is settled `WorkState::Blocked`, naming what it waited on and why that did not happen. Blocked is deliberately not Denied: a denial is a decision about a grant and carries a sealed receipt, while a block is a missing precondition — no harness was offered the task, no grant was consulted, nothing was spent, so there is nothing to seal. The blocking pass runs to a fixed point, because settling one step is what determines why the next can never run; a single pass would have to call a long chain behind one failure a cycle, which it is not. A real cycle lands there too, so the loop still terminates on any graph a caller can submit. `Status::Retry` was taken at its word: the harness said transient, so the loop ran the task again. But transient describes why the attempt failed, not whether it left anything behind — a harness can fail after its effect has landed, and the second run then pays for and performs that effect twice. The crate already refuses that bet for `Interrupted`; it was taking it here. A retry is now honoured only for a task carrying `Task::idempotency_key`, and refused otherwise with that reason recorded. An attempt bound was never a substitute: it limits how many times an effect may be duplicated, it does not make duplicating it safe. SPEC §4.11 gains the rule. It already governed a decision recorded with no outcome; this is the neighbouring case its own reasoning implies — an outcome recorded as "run it again" — and it requires the key to be part of the durable record, so a restarted enforcement point can tell a replay-safe action from one that merely has attempts left. Both the graph edges and the replay identity are journalled with the task, so a resumed run rebuilds the graph and not a flat queue. The example is now a five-step pipeline, submitted in reverse so the ordering cannot be an artefact of the queue: the ship is denied for want of a capability and the announcement behind it is never started. jouledesk gains the matching `TagOutcome::Blocked`, which seals no efficiency receipt — there were no joules to account for. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
| .. | ||
| crates | ||
| vendor/libwebrtc | ||
| Cargo.lock | ||
| Cargo.toml | ||