* test(wac): pin the failure record with one corpus both SDKs read
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(wac): add the behaviour matrix that verified the failure record
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(wac): record how to exercise an unreleased SDK change
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): guard the whole extra pair, not just its value
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): never rehash an untrusted extra key
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): walk only a real __dict__ when collecting extra
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(wac): name the divergence the corpus cannot pin
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(wac): state the extra-encoding constraints in four lines
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): hand a caught task and step failure the same shape in every round
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(wac): decide the failure record once, server-side
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): leave a legacy SDK's failure marker untouched, and ship wacError to jsr
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): carry a step's custom error fields, and bound the stack in bytes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): keep a step's extra fields serializable and bounded
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): record a non-Error throw the way a task records it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): guard the last unguarded throw site in the step marker
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): make failure reporting non-throwing on both clients
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): take the step traceback the way the executor takes it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): contain the reads that happen before a failure is checkpointed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): fall back to the checkpointed marker, not the live one
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): keep non-finite fields and hostile proxies out of the checkpoint path
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): keep the snapshot that passed the serialization probe
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(wac): keep the failure-record module's surface to what is used
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): return the checkpointed value from step(), not the live object
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(wac): regenerate system prompts and narrow the round-trip claim
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* style(wac): condense the round-trip comments and fix the fallback note
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(sdk): type step() as the JSON round trip of its body's result
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(sdk): apply the JSON round trip to task() and the standalone paths
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): encode bigint, keep unknown as unknown, align dropped-key results
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): null out results whose key JSON.stringify would drop
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): normalize only the top-level result, keeping nested keys as they were
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): normalize a child task's result so a deployed job cannot fail to parse
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(sdk): pin non-finite number behavior in Jsonified and its tests
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): admit undefined for keys whose value JSON.stringify may omit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): make a key JSON.stringify may omit optional, not just nullable
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): treat a class-valued property as dropped, like any other function
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): report a task failure the child round's body catches
* chore(wac): state the child-round failure invariant once
* test(wac): pin the catch-then-continue re-raise in the child round
* fix(wac): checkpoint step errors so a caught exception does not hang replay
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(wac): honour a step suspend the workflow body caught and swallowed
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(wac): park every suspend, not only those from a failing step
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore(wac): keep the generated bun wrapper comment-free
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(wac): park the child task-completion suspend and align error identity
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(wac): pin the TaskError identity of replayed step and task failures
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* feat: bind WAC approval urls to a named wait_for_approval step
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: reject duplicate WAC approval step keys instead of renaming them
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: reject WAC approval links minted for a step that is not awaiting approval
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: bind WAC approval links to the awaiting step and stop step key aliasing
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: reject empty approval keys and scope minted-key writes to the workspace
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: enforce WAC approval binding at consumption and reject colliding keys
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: make WAC approval binding and collision checks atomic, harden TS step keys
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: decrement WAC suspend atomically instead of from a pre-lock snapshot
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore: add sqlx cache entry for the atomic WAC suspend decrement
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: omit empty approver param from python get_approval_urls
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: pin the suspend-snapshot decrement and the colliding-mint race
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: drop the suspend-snapshot interleave test, it cannot both be stable and discriminate
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: reject step keys that cannot be minted as a URL path segment
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* feat(pipelines): ingestion (EL) templates + docs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(pipelines): review nits — draft collision guard, template-mode selection reset, invariant test
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(pipelines): lead the insert menu with ingestion templates
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(pipelines): ingestion story as docs-only — drop editor template UI
The insert-menu template section mixed two selection grammars in one popover and confused more than it helped. The three E2E-verified example pipelines now live verbatim in docs/pipeline-ingestion.md; the Python bare-string S3 key fix in pipelineTemplates.ts stays.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(sdk): bare string S3 keys in py/ts clients + asset parsers
A plain string passed where an S3Object is expected is now a bare key in the default storage — previously the py client silently degraded it to s3="" (auto-generated key) and both asset parsers canonicalized it without the leading slash, splitting lineage. parseS3Object moves to s3Types.ts so it is unit-testable without the generated services. The pipeline template fix from the earlier commit is superseded (bare strings are the supported spelling again); docs examples flipped to bare keys.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(sdk): enforce s3:// URIs for string S3Object params
Bare strings now raise/throw with a hint pointing at the s3:///<key> spelling instead of being treated as keys (previous commit) or silently degrading to an empty key (original behavior). One string spelling everywhere: SDK calls, // on annotations, and DuckDB SQL all use s3:///<key>. TS regains the s3://-template-literal type; the asset parsers record no asset for a bare string (the call can only error); templates emit the URI form.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(pipelines): move ingestion (EL) guide to windmilldocs, keep design constraints
User-facing how-to (engine choice, cursor recipes, schema drift, worked examples) moves to windmilldocs core_concepts/63_pipelines (windmilldocs#1462); the repo keeps only the design constraints future feature work must not break, as a section of ducklake-materialization.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: regenerate system prompts after parse_s3_object docstring change
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(sdk): reject empty-key s3 URIs; align asset parsers with the runtime rule
Addresses CI review: s3:/// and s3://bucket/ now raise (an empty key would fall back to the auto-generated-key path the strict contract exists to prevent); the asset parsers' string branch applies the same valid-URI-with-non-empty-key rule so no R/W edge is recorded for a call that can only error (the generic URI-literal scan still records ambiguous access-None assets, by design); comments rephrased as current constraints per AGENTS.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>