Skip to content

🧭 Add durable Workspace coordination seams - #400

Merged
taras merged 1 commit into
mainfrom
agent/issue-365-5-durable-coordination
Aug 9, 2026
Merged

🧭 Add durable Workspace coordination seams#400
taras merged 1 commit into
mainfrom
agent/issue-365-5-durable-coordination

Conversation

@taras

@taras taras commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Why

Issue #365 needs a provider-neutral boundary where a later Workspace effect can coordinate live execution with durable publication, without making ordinary durable operations enlist or leaking Deno storage authority into shared APIs.

This is stack layer 5 and replaces only the durable-coordination portion of draft #387. The preceding stack layers are merged. This revision is rebased onto main at 2a0e0f2c8e870d092c4df1b16f131a29afbe039d and semantically preserves PR #394's durable persistence boundary. It does not close #365.

What changes

Before:

  • createDurableOperation() owned one fixed live execute/serialize/append path.
  • A Workspace operation had no provider-neutral, fail-closed way to request coordination.
  • WorkflowRun journal appends could not be lexically routed into an exact active caller-owned transaction.

After:

  • An explicit live coordinator controls structured operation execution and publication while the default preserves existing behavior.
  • Coordinator publication uses the ordered durable append fence: backing failures activate fail-stop state as DurablePersistenceError, retain the adapter error as cause, write no compensating Close, and fence later durable work.
  • Workspace operations explicitly select a contextual coordinator whose default refuses live work before execution or publication.
  • The Deno adapter can bind an already-filtered publication append to the exact active WorkflowRun transaction, validating lease, run, connection generation, transaction identity, and open state before delegating to transaction.journal.
  • Provider-owned ordinary and publication-local routed journal destinations are terminal { at: "min" } handlers, so a same-named enclosing loaded copy cannot suppress an append or bypass exact validation.

How it works

createDurableOperation
  → active fail-stop check before replay matching
  → replay bypasses coordination
  → active fail-stop check before live coordination
  → coordinator executes and produces the existing protocol Result
  → publication continuation constructs the existing Yield
  → appendDurableEvent applies ordered persistence and fail-stop semantics
  → protocolToEffection resolves the caller after persistence

Workspace publication
  → existing secret guard/filter
  → publication-local terminal Deno journal destination
  → exact active transaction.journal

The journal destination is bound only around publication. Mutation execution and unrelated appends do not inherit it. Unbound appends keep the standalone serialized journal path, and readAll() never routes. There is no generic durable validation hook; callers and providers validate before constructing the durable effect.

Review guide

Start with: packages/durable-streams/live-coordinator.ts and the createDurableOperation() live path in packages/durable-streams/effect.ts.

Then review:

  1. packages/durable-streams/tests/live-coordinator.test.ts for default execution, 🐛 Restore the durable eval journal boundary #394 fail-stop persistence, replay, partial replay, cancellation, and callback compatibility.
  2. packages/workflow/src/workspace/api.ts and effect.ts for explicit fail-closed Workspace selection.
  3. packages/workflow/src/deno/journal-route.ts for lexical routing, exact-authority validation, and terminal dispatch.
  4. DLC1–DLC13 and WJ26–WJ35 for conformance coverage.

Look carefully at:

  • DLC3 proves one backing append attempt raises DurablePersistenceError, retains the adapter failure as cause, persists neither Yield nor Close, and never resumes the workflow past publication.
  • DLC4 proves catching that failure cannot invoke a later coordinator or executor, cannot reach another append, and cannot replace the first active durability failure.
  • WJ34–WJ35 construct a separate same-named contextual API and prove it cannot suppress ordinary or routed appends or bypass exact-token validation.
  • WJ32 proves different-run nested routes still delegate correctly under that collision.

What must stay true

  • Existing durable protocol Result is the only live success/failure representation — DLC1–DLC9.
  • 🐛 Restore the durable eval journal boundary #394's ordered append fence, fail-stop state, persistence-error cause, policy distinction, and persist-before-resume behavior remain intact — DLC3–DLC4 plus the fail-stop, terminal-boundary, durable-run, and guard-stream suites.
  • Callback-based createDurableEffect() behavior stays unchanged — DLC9.
  • Workspace coordination is explicit and fail-closed — DLC10–DLC12.
  • Shared production signatures expose no Deno, SQLite, DOFS, savepoint, generation, or transaction-token types — DLC13.
  • Secret filtering remains outside routing, while insertion uses the existing transaction journal — WJ26–WJ27.
  • Missing, foreign, fabricated, completed, closed, cross-run, and stale authority reaches no SQL — WJ28–WJ30.
  • Unrelated appends and reads never enlist — WJ31–WJ33.
  • Same-named contextual handlers cannot intercept ahead of provider-owned terminal routing — WJ32, WJ34, and WJ35.

How to verify it

  • deno task setup — passed; tracked files unchanged.
  • deno task lint — passed with 0 errors.
  • deno task check — passed.
  • deno task check:jsrSuccess Dry run complete.
  • deno task test --related=packages/durable-streams/effect.ts — 299 tests, 2,215 steps, all passed.
  • Explicit durable/workflow boundary suite from the review prompt — 16 tests, 105 steps, all passed.
  • git diff --check origin/main...HEAD — passed.

CI owns the exhaustive Deno/Node/Bun matrix for this runtime-adapter and shared durable boundary.

Scope

Included

  • Provider-neutral live durable-operation coordinator and default behavior.
  • Shared explicit, fail-closed Workspace coordination API and durable wrapper.
  • Adapter-private publication-local WorkflowRun journal routing.
  • DLC and WJ conformance inventory plus architecture, storage-specification, and durable-stream README updates.

Intentionally unchanged

  • Filesystem mutation, operation-savepoint orchestration, root capture, and current-root changes.
  • Atomic mutation/root/result publication and known-failure commit behavior.
  • Secret policy and filtering behavior.
  • Public workflow start/resume, <File>, history/fork, Worker Shell, Git/Repository effects, FUSE, workerd, subprocess bridges, GC, schema, migration, and vendored Cloudflare source.

New abstractions

  • LiveDurableOperationCoordinator separates live execution/result construction from the existing Yield publication continuation; the default and explicit Workspace coordinator are its concrete uses.
  • WorkspaceCoordination is the shared contextual capability that makes live Workspace work fail closed when no owning provider is installed.
  • The adapter-private journal destination/router lexically connects one already-filtered publication to exact active transaction authority.
  • Each new abstraction has multiple concrete uses or a clear justification.
  • No speculative functionality is included.

Risks and limitations

  • This PR provides seams only. It does not coordinate a filesystem mutation, root publication, and journal append atomically; the next layer consumes these contracts.
  • The atomic Workspace-effect layer must preserve the mutation-scope teardown ordering and exact private authority established by the earlier stack layers.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified (none).
  • The description matches the final diff and test results.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

PR #400: 🧭 Add durable Workspace coordination seams

16 files, +1357 / -28

Scope

🔴 PR has 1385 lines changed. Split into focused PRs.

🟡 1385 lines changed. PRs under 400 receive more thorough review.

Structural

Oxlint structural signals:

  • no-unused-vars ×2: packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts
  • no-empty-function ×2: packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts
  • no-unnecessary-type-assertion ×1: packages/durable-streams/effect.ts

Slop

✅ Slop indicators look low.

Static Analysis

Oxlint: 260 diagnostics across 7 files (32 rules)
Density: 0.192 violations/added-line

new-cap (36): packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
capitalized-comments (34): packages/workflow/src/deno/journal-route.ts, packages/workflow/src/workspace/api.ts, packages/workflow/src/deno/provider.ts (+2)
no-unsafe-call (29): packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
no-unsafe-member-access (27): packages/workflow/src/deno/database.ts, packages/workflow/src/deno/provider.ts
id-length (22): packages/workflow/src/workspace/effect.ts, packages/durable-streams/live-coordinator.ts, packages/workflow/src/deno/journal-route.ts (+4)
func-names (11): packages/workflow/src/deno/journal-route.ts, packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts (+1)
max-statements (11): packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts, packages/workflow/src/deno/database.ts
no-unsafe-assignment (10): packages/workflow/src/deno/database.ts, packages/workflow/src/deno/provider.ts
init-declarations (9): packages/durable-streams/live-coordinator.ts, packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
no-confusing-void-expression (9): packages/durable-streams/effect.ts
max-lines-per-function (8): packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts, packages/workflow/src/deno/database.ts
no-ternary (6): packages/durable-streams/live-coordinator.ts, packages/durable-streams/effect.ts, packages/workflow/src/deno/database.ts
max-params (5): packages/workflow/src/deno/journal-route.ts, packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts
no-unsafe-argument (5): packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
method-signature-style (4): packages/durable-streams/live-coordinator.ts, packages/workflow/src/deno/journal-route.ts, packages/workflow/src/deno/database.ts
no-nodejs-modules (4): packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
catch-error-name (4): packages/durable-streams/effect.ts
max-lines (3): packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts, packages/workflow/src/deno/database.ts
no-labels (3): packages/durable-streams/effect.ts
no-unsafe-return (3): packages/workflow/src/deno/database.ts
max-dependencies (2): packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
no-unused-vars (2): packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts
no-empty-function (2): packages/workflow/src/deno/provider.ts, packages/durable-streams/effect.ts
prefer-const (2): packages/workflow/src/deno/database.ts
no-floating-promises (2): packages/durable-streams/effect.ts
no-inline-comments (1): packages/durable-streams/effect.ts
consistent-function-scoping (1): packages/durable-streams/effect.ts
prefer-destructuring (1): packages/workflow/src/deno/database.ts
no-array-callback-reference (1): packages/workflow/src/deno/database.ts
no-useless-return (1): packages/workflow/src/deno/database.ts
no-unnecessary-type-assertion (1): packages/durable-streams/effect.ts
strict-boolean-expressions (1): packages/workflow/src/deno/provider.ts

Correctness

FILE: packages/workflow/src/deno/provider.ts, packages/workflow/src/deno/database.ts
PATTERN: SIGNAL CLUSTERS
CONCERN: Files with multiple Oxlint violations (e.g., new-cap, no-unsafe-call, no-unsafe-member-access) suggest unreviewed or low-quality code.
QUESTION: Are these violations due to legitimate code patterns or unreviewed generated code?

FILE: packages/workflow/src/deno/journal-route.ts
PATTERN: WRAPPER INDIRECTION
CONCERN: routeWorkflowRunJournal and withEnlistedJournalRoute may be excessive wrappers that don't add clear value.
QUESTION: Could these be simplified to reduce indirection while maintaining functionality?

FILE: packages/workflow/src/deno/journal-route.ts
PATTERN: DEAD CONSTRUCTS
CONCERN: CollidingJournalDestination is defined but not clearly used in the provided code.
QUESTION: Is this code necessary, or is it leftover from previous implementations?

FILE: packages/durable-streams/effect.ts
PATTERN: OBJECT LITERAL ASSERTIONS
CONCERN: {} as Type patterns may hide missing properties.
QUESTION: Are there explicit type assertions that could be replaced with proper typing?

@taras
taras force-pushed the agent/issue-365-5-durable-coordination branch from ec823f2 to 0b4fdb4 Compare August 9, 2026 02:29
@taras
taras marked this pull request as ready for review August 9, 2026 02:43
@taras
taras merged commit 5a68556 into main Aug 9, 2026
11 checks passed
@taras
taras deleted the agent/issue-365-5-durable-coordination branch August 9, 2026 02:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Commit Workspace mutations and journal results atomically

1 participant