Skip to content

release: breakwater 0.13.0, flowsafe 0.19.0, fleet-control 0.3.4 - #100

Merged
gcharang merged 16 commits into
mainfrom
dev
Aug 22, 2026
Merged

release: breakwater 0.13.0, flowsafe 0.19.0, fleet-control 0.3.4#100
gcharang merged 16 commits into
mainfrom
dev

Conversation

@gcharang

Copy link
Copy Markdown
Contributor

Promotes the versioned dev state to main. Version Packages PR #99 is merged, the full verify job passed on dev commit c07693d, and no pending changesets remain. The non-blocking Mastra 1.61.0 canary was investigated: it reaches the compatibility tests and flags new upstream prototype members; the supported release peer remains exact 1.53.0.

gcharang and others added 16 commits August 20, 2026 11:19
A receiving agent's input processor is not a complete signal boundary: Mastra
can drain queued signals after the initiating processor has run. Breakwater now
exposes createContentPolicyGate(), the same ordered, fail-closed evaluator loop
PolicyEngine uses, for host code outside the processor chain; FlowSafe's thread
signal routes accept a structural contentPolicy callback and apply it at the one
Durable Object boundary every lane converges on, over Mastra's canonical escaped
XML, before delivery, persistence, wake, or run start.

Denial is terminal and evaluator failure stays recoverable, per lane: direct
routes answer 422 and 503; a schedule settles a discard receipt or leaves its
lease for a later tick; a notification is discarded or deferred with backoff.
Neither outcome exposes policy names, reasons, content, or causes.

Notification ingress is authoritative rather than a preview — core delivers an
urgent notification, and an idle-thread high or medium one, straight out of
sendNotificationSignal — so it inspects both renderings core can choose between.

Two pre-existing defects surfaced by that rendering are fixed with it. Signal
attributes whose keys are not XML names are dropped at ingest, and a schedule
whose stored target cannot be rendered settles terminally, instead of throwing
inside the agent turn or handing the same broken target to every later tick.

Provider deliveries now separate a terminal refusal from one the deployment
could not decide. An undecided webhook answers 5xx so the sender redelivers,
under a dedupe key derived from the signed bytes and the subscription, rather
than dropping an authentic event during a policy outage; a provider bug stays
contained and non-retryable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The O2 "scheduled agent principal" check was flaky because an earlier
probe left a `* * * * *` schedule active and `/sched/agent`'s tick claimed
every due row, so a minute boundary produced `due:2, fired:2`. Every
`/sched/*` probe now pauses prior probe schedules at its entry (one call
site; the barrier's inline loop is gone), the route set is decided before
the store is constructed, and the workflow-start seam throws as a tripwire.
O2 asserts `due === 1`, exactly one trigger row, the seam and D1 run ids
agree, and the outcome is `succeeded`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119A2ucLjbpmXKEe5GLXxTB
Webhook and poll deliveries that a thread Durable Object refuses were
logged as `*-delivery-error` without saying whether redelivery could change
the outcome. Every such event now carries `terminal`, computed by one
shared predicate next to the delivery classifiers: `denied` and `failed`
cannot change on redelivery, `deferred` can. The two by-construction
`failed` lanes carry the literal; the rejected lanes use the predicate
instead of an inline comparison. Tests assert the flag per lane on the
exact logged event.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119A2ucLjbpmXKEe5GLXxTB
Every @mastra/core release from 1.54.0 through 1.61.0-alpha.1 ships literal
`import("execa")` / `import("@ast-grep/napi")` specifiers (mastra-ai/mastra
#20638) that break the flowsafe workerd bundle and the showcase build, so
the supported peer moves to exactly 1.53.0 in all six manifests; the D1
adapter stays at 1.1.1. Flowsafe's breakwater peer floor rises to
`>=0.13.0 <1.0.0`, three stale age-gate exclusions are dropped, and the
packed-manifest tripwires now derive their expectations from the source
manifests and assert the packed core peer is an exact version.

1.53.0 added recovery entries to DurableAgent and made `resume()` rehydrate
a run from snapshot storage below `executeWorkflow`, outside RunnerRuntime
and the approval-decision path. FlowsafeDurableAgent now refuses nineteen
inherited entry points from a single reason table (`BLOCKED_RUN_ENTRIES`,
kept off the public subpath), and a prototype-surface tripwire partitions
every DurableAgent and Agent member so the next core bump surfaces new
members mechanically. Breakwater's inventory loses a member 1.53.0 removed
and gains a self-expiring allowlist for the newest-core canary. The
`mastra-compat` job bundles the spike Worker against newest core and
reports the outcome on the run summary.

Docs record the residual this work surfaced: on an idle thread the queue,
state and notification routes — and Mastra's completion drains — start
runs under Mastra-minted ids FlowSafe does not own. That behaviour is
byte-identical at 1.50.0 and is left for its own change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119A2ucLjbpmXKEe5GLXxTB
Text-only follow-up to the @mastra/core 1.53.0 closeout; no behavior change.

- docs/durable-agents.md: the wake-path sentence now partitions the five
  thread channels (message/signal wake through Flowsafe's seam; queue/state/
  notification do not) and names schedule and notification-dispatch as routes
  outside the channel table; blocked-entry ground 4 reads "mints a run id
  below the caller" to match BLOCKED_RUN_ENTRIES.
- durable-agent-runner.ts: section rules say "unless another chunk or file is
  named" (the Corroboration paragraph cites repo-file offsets); the
  five-senders block scopes its offset rule to the paragraph, uses one form per
  file name, and is re-flowed to the file's comment width.
- durable-agent-surface.test.ts: gloss names the RunnerRuntime boundary and the
  unreachable model by its helper name.
- agent.test.ts: the allowlist comment points below to the comparison it
  governs and no longer hard-codes the live-name count.
- host-do.test.ts: the it.each column is `scenario` (not the reserved `case`)
  and the provider id is one hoisted const.
- packages/breakwater/src/agent/CLAUDE.md: route maintainers to the
  forwardClassified allowlist before any @mastra/core bump.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RA71awFou9Yr5VNpETGhjr
…n routes

Closes the pre-existing (Track C) residual where three thread-DO signal
routes let @mastra/core mint a run id and start a run outside RunnerRuntime,
and where core's completion drains replayed leftover signals under fresh ids
with the previous run's trusted context.

Runner (durable-agent-runner.ts):
- A run the host seam (streamUntilPersisted) did not register is failed
  terminally inside executeWorkflow: its input is persisted best-effort
  (bounded, skipped for read-only or missing threads, and for deliveries
  marked as non-owner), a terminal ERROR is published through core's own
  channel so core's completion watcher heals the thread (maps, lease,
  renewal timer), registries are cleaned in finally, and RunnerRuntime.start
  is never reached. Direct stream() resolves to a failed output; direct
  generate() rejects.
- One live-id guard (#assertRunIdNotLive) refuses stream/generate/prepare
  and a second host start for any id still live in the requester map, the
  persistence waiters, core's TTL run registry or the runner's internal
  registry; the host's own first start carries a single-shot private ticket.
  streamUntilPersisted refuses untilIdle.
- Terminal-error publication is one-attempt/never-throws; the terminal path
  retries once and throws after cleanup, the resume path publishes
  best-effort before cleanup and keeps its original semantics.

Routes (thread-do-routes.ts):
- /signal/queue persists in both thread states (sendMessage with
  ifActive/ifIdle persist); the active-thread auto-drain is gone.
- /signal/state gains the owner gates /signal/queue has, persists on idle,
  and awaits the write.
- /signal/notification stays the provider lane: no owner refusals; owners
  persist on idle; non-owners are record-only through
  resolveNotificationsStorage with deliverAt now and are delivered by the
  host's notification dispatch tick; 409 without the storage seam.
- Every deliverActive fall-through persists only when memory is available
  and the principal may persist; a non-owner's requested ifActive persist is
  degraded; signals sent under a non-owner principal carry a non-rendered
  metadata marker the terminal persist honours.
- memory-unavailable is answered only where a memory write would otherwise
  be silently dropped, after the content gate; wake-start, active delivery
  and the notification inbox record need no memory. The schedule route
  settles a canonical discard receipt in that case.
- Unbranded agents degrade to persist-only with a typed `degraded` marker.

Tests: a real guarded durable agent driven through the real routes proves
the DENY direction, the completion-drain heal (maps, lease, no run row), the
direct-sender matrix, the suspended-run collision window and the non-owner
record-only path; unit rows cover every gate and order.

Docs and the flowsafe minor changeset call out every contract that moved,
the memory prerequisite the shipped starter host does not yet satisfy
(follow-up: wire agent memory), and the two declared residuals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RA71awFou9Yr5VNpETGhjr
…-check

Four hardening follow-ups the 1.53.0 closeout recorded:

- scripts/github-yaml-check.mjs (+ test, `github:check` / `github:check:test`,
  a lint-staged entry for .github/**/*.{yml,yaml}, and two `verify` steps
  before Lint) parses every .github YAML file with yaml@2.9.0's
  parseDocument, fails closed on parse errors, unresolved aliases,
  multi-document files, empty or non-mapping documents, zero files,
  forbidden characters (C0/C1 controls, DEL, U+FFFE/U+FFFF), invalid
  UTF-8, symlinked entries or a symlinked root, and a missing or
  non-directory .github. A plain-scalar `": "` error in ci.yml was
  previously invisible to every local gate, and sibling workflows and
  issue templates are never trigger-checked on a PR. yaml@2.9.0 is pinned
  exactly as a root devDependency; it was already resolved at that version.
- scripts/publish-ordered.mjs checks each prerequisite's peer floor against
  the version being published, as a required first hook of publishRelease
  (release time only: between a floor raise and the Version Packages PR the
  source tree legitimately fails it); publish-invocation-check.mjs asserts
  the floor grammar on every PR and names the manifest that owns each
  violation. The two packed-consumer tests assert that breakwater and
  flowsafe pin the same @mastra/core peer.
- docs-check gains checkMastraCoreAgreement: every packages/*/package.json
  @mastra/core declaration must carry one value, and each library's
  devDependency must equal its peer.
- pnpm override js-yaml@4 -> 4.3.1 (CVE-2026-59870 on the changesets
  transitive), mirroring the existing js-yaml@3 override.

The CONTRIBUTING and maintainer-guide gate lists now mirror the verify job
in order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: ba9217b9-818b-4144-9baa-1336c3de16da
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
anchorage-showcase-single-tenant c07693d Aug 22 2026, 01:29 PM

@gcharang
gcharang merged commit bc48a98 into main Aug 22, 2026
4 of 6 checks passed
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.

1 participant