fix(workflows): close review gaps — pull round-trip, dup-names, reclaim budget
Adversarial review of the v1.2 Workflows track surfaced two HIGH footguns and several correctness/hardening gaps. Fixes: HIGH - pull round-trip: `pic pull` dropped `[[workflows]]`, so a later `apply --prune` silently deleted them. The list endpoint now returns the full `definition`; pull rebuilds the manifest block (inverse of workflow_to_wire). - case-colliding names: two workflows differing only by case collided in the reconcile diff (keyed by lower(name)), silently dropping one. Rejected up front in validate_bundle_for. MEDIUM - reclaim retry budget: a crashed attempt (no outcome) consumed the retry budget. reclaim_stale_steps now decrements `attempt` (floored) and clears `next_attempt_at`, so a crash no longer counts as a failed try. - on_error/backoff: typed the manifest fields against the shared enums so a bad value fails at TOML parse with a clear message, not an opaque 500. - dedupe depends_on: a repeated dependency inflated the Kahn in-degree past the single decrement, reporting a spurious cycle for a valid DAG. Count distinct. - canceled child: a canceled sub-workflow resolved the parent step with a message naming the cause instead of a generic "failed"; documented that a run-level cancel op is not yet supported. LOW - list_run_steps is now app-scoped at the query (JOIN workflow_runs) rather than relying on caller pre-verification. - partial failure is surfaced: a run that succeeds with on_error=continue failures records them in the run's `error` field. - admin-started runs log the root_execution_id against the principal. - documented the deliberate when(missing→false) vs template(missing→fail) asymmetry; corrected the claim's atomicity comment. Tests: unit (dedupe-deps), DB-gated reclaim-budget assertion, and two new CLI journeys (duplicate-name rejection, pull→plan clean round-trip). fmt + clippy -D warnings clean; 450 lib + 14 orchestrator DB + 5 workflow journeys pass; schema snapshot unchanged (no migration). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,15 @@
|
||||
//! (`== != < > <= >=`), primary (`( … )`, `exists <ref>`, literal, `<ref>`).
|
||||
//! Literals: numbers, `'…'`/`"…"` strings, `true`, `false`, `null`.
|
||||
//! A bare reference is truthy per [`is_truthy`]; a reference that doesn't
|
||||
//! resolve is `null` (falsy) at run time — apply-time [`validate`] guards typos.
|
||||
//! resolve is `null` (falsy) at run time. This is a DELIBERATE asymmetry with
|
||||
//! [`workflow_template`], which HARD-FAILS a missing ref: a `when` is a
|
||||
//! predicate (an absent value is "condition not met"), whereas an input
|
||||
//! template must not silently substitute null. Apply-time [`validate`] guards
|
||||
//! the *shape* of a ref (the root `input`/`steps.<name>.output` prefix and that
|
||||
//! `<name>` is a declared step), but it cannot check a deeper JSON path against
|
||||
//! a runtime value — so a typo *past* the step name (e.g. `steps.a.output.typ`
|
||||
//! for `…typo`) is not caught at apply and silently makes the step skip. Prefer
|
||||
//! `exists <ref>` to make "the value may be absent" explicit.
|
||||
//!
|
||||
//! [`workflow_template`]: crate::workflow_template
|
||||
|
||||
|
||||
Reference in New Issue
Block a user