Skip to content

persist: write SessionSnapshot on transcriptPointer - #868

Merged
btipling merged 14 commits into
mainfrom
plan/f5-readable-blob
Aug 28, 2026
Merged

persist: write SessionSnapshot on transcriptPointer#868
btipling merged 14 commits into
mainfrom
plan/f5-readable-blob

Conversation

@btipling

Copy link
Copy Markdown
Owner

Summary

Readable worker blob (plan #864, parent #862).

persistStep was JSON.stringify({ deltas }), so parseCloudSessionSnapshot returned null and F5 after a finished durable turn could not LWW-adopt the worker transcript.

This PR writes a SessionSnapshot shape (id, messages, extra deltas key) from the bounded checkpoint. The persist seam stamps updatedAt with the B8 overlay clock once (same number as the envelope upsert). persistStep never calls Date.now(). Checkpoint tool maps to session tool_run so tool rows are not dropped. Empty-envelope B7 pointer mint uses updatedAt: 0 so that overlay clock is strictly newer (append-only blob cannot be rewritten after B7).

Locks

  • persistStep stringifies { id, messages, deltas } only — no updatedAt, no Date.now().
  • Missing/blank scope.sessionId{ ok: false, code: 'invalid_scope' } before seam.persist.
  • Seam: OverlayClock once → stamp JSON → B7 → B8 with the same number.
  • 'tool''tool_run'; other unknown checkpoint roles dropped.
  • Parser unchanged: { deltas }-only still null. No second schema. No blob backfill.
  • Helper is runtime-pure (no sessionRepository import).

Tests

  • checkpointToSnapshotMessages: +4 (happy, tooltool_run, drop unknown, empty).
  • persist seam: +1 (blob updatedAt === envelope clock; clock invoked once).
  • persistStep: +1 (missing sessionId fail-closed).
  • persist-parse int: dropped it.fails; both rows green.
  • Remaining it.fails: TURN2_USER, LIVE_ASSISTANT (phase 4), quota (phase 3).
  • F5 attach / C15 rows stay green (phase 1).

Gates: npm run typecheck green. vitest run --changed 36 files / 377 passed. vitest run --project int 11 passed. npm run build N/A (no Wasm change).

Expected default-suite delta: +6 tests vs main (4 helper + 1 clock + 1 invalid_scope).

Docs

  • docs/session-model.md Reload/restore: transcriptPointer body is a session snapshot JSON; legacy { deltas }-only fails parse (timeless).

Fixes #864
Refs #862
Refs #859

Worker persist was stringify({ deltas }), so boot parse-fail left F5 on
stale local. persistStep now writes { id, messages, deltas }; the seam
stamps the B8 overlay clock once onto that JSON. Checkpoint `tool` maps
to `tool_run`. Drop persist-parse it.fails.
@btipling btipling self-assigned this Aug 28, 2026
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
invincible Ignored Ignored Aug 28, 2026 9:47pm

Request Review

Copy link
Copy Markdown
Owner Author

Opened from plan #864 (not merged).

  • typecheck green
  • vitest run --changed: 36 files / 377 passed
  • vitest run --project int: 11 passed (persist-parse no longer it.fails)
  • +6 unit tests; remaining int it.fails: TURN2_USER / LIVE_ASSISTANT / quota

Next: adversarial-review on this PR, then an explicit merge request.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: BLOCK
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer schema
Lenses run: L1, L6, L8 (skip: L2 no secret/runner/client-bundle surface; L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L5 one persist stringify, not a poll/alloc storm; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Blocker L1 persistStep writes this-run fold.checkpoint as the Blob SessionSnapshot (lib/workflows/persistStep.ts · checkpointToSnapshotMessages; lib/workflows/turnLoop.ts · derivePersistFold / messages = [{ role:'user', content: input.userMessage }]). The seam then stamps the B8 overlay clock (max(now, stored+1)) onto that body (lib/agent/turnPersistSeam.ts). shouldAdoptServer adopts any strictly-newer server whole-array (lib/sessionRepository.ts). Complete durable turn 1, then turn 2. Worker persist 2 body is [user2, assistant2] only, updatedAt strictly newer than the host envelope/local. F5 → bootCloudSnapshot parses (this PR’s DoD) → action: 'ok'shouldAdoptServer true → canvas drops turn 1. Same-device F5 after a finished second turn, or any empty other-device local, hydrates the suffix as the full session. Main today fail-closes parse ({ deltas }) and keeps local; this PR turns that clobber into a successful LWW replace. Plan #864 / parent #862 want a parseable pointer and to “hydrate that checkpoint, not turn-1-only local.” That is the missing turn 2 content, not a license to delete turn 1. Empty-checkpoint “keeps local via shouldAdoptServer” is false: newer updatedAt wins before the empty-dialogue clause. TURN2_USER remaining it.fails is phase 4 cadence, not a merge of prior blob messages. persist-parse only exercises persistTurn1 (2 rows). Defender “local clock is usually newer” fails the PR’s own lock: overlay clock is designed to beat stored/local completed. high
Major L6 No test that a second persistStep / seam persist retains turn-1 messages (or suffix-merges a host-shaped prior). New rows prove parse, 'tool''tool_run', one-clock stamp, missing sessionId. Merge this PR. vitest run --changed and int/persist-parse stay green while F5 after two completed durable turns wipes history. CI cannot catch the Blocker. “Phase 4 int rows cover turn 2” — those rows are still it.fails and do not assert LWW of a completed two-turn blob. DI/cost is clean (memory stores). high
Minor L8 docs/session-model.md Reload/restore now says the pointer body is “the same shape a full-record GET returns.” After this PR it is this-run checkpoint + deltas, not the accumulated host transcript. Operator/agent reads living docs, treats worker blob as full GET, ships F5 against it, loses earlier turns. Extra-keys sentence is accurate. The “full-record GET” claim is not. high

Residual risk

Even with a prior-blob merge, a first persist over a leftover { deltas } object still starts from this run only (no backfill — accepted). B7/B8 remain two envelope upserts; a concurrent host LWW on the B8 overlay still leaves the pointer advanced (pre-existing partial-commit). Oversize merged JSON can still write_failed at the 8 MiB object ceiling.

Merge guidance

  • BLOCK: do not merge until the Blocker is fixed in createTurnPersistSeam (read current transcriptPointer body; suffix-merge this-run messages onto a parseable prior; never LWW-publish a this-run-only array under a newer overlay clock when a readable prior exists). Add a two-persist / host-prior unit that still parses and keeps the turn-1 user line. Living-docs sentence must match the accumulated body.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob, real F5 against Production Redis, Wasm hydrate paint, host putEnvelopeOnce race on a live session.

This-run checkpoint plus a newer overlay clock LWW-replaced turn-1
history on F5. The persist seam reads the current transcriptPointer,
suffix-merges this-run messages onto a parseable prior, then stamps
the same B8 clock. Leftover { deltas } objects are not merged.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial BLOCK: suffix-merge is in c043e9b.

  • createTurnPersistSeam reads the current bound transcriptPointer, suffix-merges this-run messages onto a parseable prior (role+text overlap), then stamps the same B8 overlay clock.
  • Leftover { deltas } / foreign pointer still starts from this run only (no backfill).
  • Tests: two-persist keeps turn-1 user; host-shaped prior is not duplicated; unreadable prior stays this-run; int persist-parse second persist asserts the four-row body.

--request-changes is not available on an own-PR; the review body above still stands as BLOCK until this commit is considered.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

c043e9b closed the previous BLOCK (this-run-only array under a newer overlay clock wiping turn 1 on the two-persist happy path). Remaining findings are on the merge predicate and the bound-pointer miss path.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 mergeCheckpointOntoPrior (lib/agent/messageCheckpoint.ts) overlaps only on exact role+text. Host tool_run rows are encodeToolRun payloads (lib/harnessChat.ts livePaintToolRun); worker checkpoint tooltool_run rows are raw result strings (turnLoop.ts checkpointRow). Those texts never match, so overlap collapses to 0 and this-run is appended. Durable tool turn. Host persistTurn / onSessionPatch wins the pointer (turn-end PUT or mid-turn change_dir / usage after appendMessage bumps updatedAt). Worker persist reads that host snapshot, suffix-merges [user, raw_tool, assistant] onto […, user, encoded_tool, …], publishes the duplicate under the B8 overlay clock. F5 LWW-adopts doubled user + mixed tool cards. Same hole for a trailing partial assistant whose text ≠ the final checkpoint. Tests only cover exact role+text (turn-2 user/assistant, host prior that already equals this turn). Text-only turns with identical assistant strings still overlap. Plan #864 did not mention merge; c043e9b added it to stop clobber, not to survive the host encoder. Host PUT often 409s against the running envelope clock — not on the turn-end path once local updatedAt is Date.now(). high
Major L1 Bound transcriptPointer + blobStore.readnull is treated like leftover { deltas }: priorMessages = null → this-run-only body → overlay clock LWW-clobbers history (createTurnPersistSeam prior-read try/catch). VercelBlobTranscriptStore.read maps fetch/timeout/non-2xx to null (does not throw). Complete turn 1 (readable snapshot at a bound pointer). Turn 2 persist: signed GET of that pointer fails transiently → raw === null → merge skipped → B7 writes [user2, assistant2] as a new object and B8 stamps a newer clock. F5 adopts turn 2 only. Distinct from leftover { deltas } (that path still has a JSON body). Unbound seed pointers (t_old_ptr_0000) already skip the read. Missing blob vs timeout is indistinguishable in the Vercel store — fail-closed persist (leave the pointer) is still better than a successful LWW replace. { deltas } remains this-run-only because snapshotMessagesFromUnknown rejects it after a successful read. high
Minor L6 No unit/seam row for (a) host-encoded tool_run prior, (b) bound pointer + read() === null must {ok:false} and not advance. Two-persist / host-prior rows stay green while both Majors ship. Merge this PR. vitest run --changed and persist-parse int remain green. Helper overlap tests exist for equal text. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. Assistant text that is a proper prefix of the final checkpoint (mid-stream host PUT) can still duplicate if overlap requires exact assistant text — accepted unless a later phase persists mid-turn (phase 4). Envelope reserved meta is overlaid on boot (overlayEnvelopeMeta); dropping meta from the worker blob is not a carrier wipe.

Merge guidance

  • CONCERNS: do not merge until both Majors are fixed. mergeCheckpointOntoPrior must treat tool_run as role-equal (ignore payload text) so a host-encoded prior does not duplicate; a bound pointer whose read() is null (or whose JSON throws) must {ok:false, code:'write_failed'} and must not stamp a this-run-only snapshot. Add those two tests. Leftover { deltas } JSON must stay this-run-only.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint, host putEnvelopeOnce vs B8 overlay on a live session.

Host encodeToolRun payloads never equal checkpoint result text, so
suffix-merge appended a duplicate this-run. tool_run now matches by
role. A bound pointer whose object is missing or not JSON fails
persist instead of LWW-publishing this-run-only.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (b0bf473):

  • mergeCheckpointOntoPrior treats tool_run as role-equal (host encodeToolRun payload vs worker raw result) so a host-shaped prior does not duplicate this-run.
  • Bound transcriptPointer whose object is missing or not JSON → {ok:false, code:'write_failed'}, pointer unchanged. Leftover { deltas } JSON still starts from this run only.
  • Prior-read gate runs before B6 so a miss does not orphan a checkpoint blob.
  • Tests: encoded tool_run host prior; bound missing blob; bound non-JSON body.

npm run typecheck green. vitest run --changed: 33 files / 374 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

b0bf473 closed the previous CONCERNS pair (role-equal tool_run; bound pointer miss/non-JSON fail-closed). Remaining finding is the overlap shape: 1:1 row alignment still cannot absorb the host this-run window.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 mergeCheckpointOntoPrior (lib/agent/messageCheckpoint.ts) still aligns equal-length prefixes. tool_run is role-equal 1:1. Host livePaintToolRun (lib/harnessChat.ts) grows one session row for a consecutive tool streak (updateLastMessage / same openToolRunId); worker checkpointRow (lib/workflows/turnLoop.ts) emits one row per tool. Host also inserts skill_attached (pushSkillRow) — and can insert system/error — inside that window. Any extra incoming tool_run or host-only role zeros overlap. Durable turn with ≥2 tools. Host persistTurn / envelope carrier wins transcriptPointer first (terminal persist after stream; putEnvelopeOnce writes {id,updatedAt,messages}). Prior = […, user2, ONE encodeToolRun card, assistant2]. Incoming = [user2, raw_t1, raw_t2, assistant2]. k=4 fails (lengths / assistant vs tool); k=3 fails (t2 vs assistant); k=2 fails (user vs tool card once assistant is last). overlap=0 → this-run appended under the B8 overlay clock. F5 shouldAdoptServer adopts doubled user + mixed encoded/raw tool cards + doubled assistant. Same wipe-to-duplicate with /skill (skill_attached between user and tool). N=1 encoded-tool tests (host-encoded tool_run prior is not duplicated, helper does not duplicate a host prior whose tool_run payload differs) stay green — one host card vs one checkpoint tool is 1:1. Worker-to-worker two-persist (no host coalesce) also stays green because prior tools stay N raw rows. Envelope carrier off → host never writes this pointer and the hole is latent; this PR’s F5 path is that pointer, and turn-end host PUT is the common writer before the worker step. high
Minor L6 No unit/seam row for (a) host one tool_run vs checkpoint N≥2 tools, (b) skill_attached (or system/error) interrupting the this-run suffix. The N=1 encoded-tool tests do not catch the Major. Merge this PR. vitest run --changed and persist-parse int remain green. DI/cost is clean (memory stores, no extra PGlite). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON stays fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. A host mid-stream assistant prefix whose text ≠ the final checkpoint still fails exact role+text on that row (phase 4 mid-turn persist). Envelope reserved meta is overlaid on boot (overlayEnvelopeMeta); dropping meta from the worker blob is not a carrier wipe.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed. Suffix overlap must treat a single prior tool_run as covering a run of incoming tool_run rows when the next prior row is not tool_run (host live-paint card), keep 1:1 when both sides have consecutive tool_run (worker-to-worker), and skip host-only skill_attached / system / error in the prior suffix so they cannot zero overlap. Add tests for coalesced N≥2 and a skill_attached interrupt. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

Host live-paint grows one encodeToolRun card for N tools, and may
insert skill_attached in the this-run window. 1:1 suffix overlap
zeroed and duplicated this-run under the overlay clock. One prior
tool_run now covers an incoming tool run when the next prior row is
not tool_run; worker consecutive tool_run stays 1:1. Host-only
skill_attached/system/error rows are skipped so they cannot zero
overlap.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (19a27ea):

  • Suffix overlap is no longer 1:1 length. A single prior tool_run covers a run of incoming tool_run rows when the next prior row is not tool_run (host livePaintToolRun card). Consecutive prior tool_run rows stay 1:1 (worker-to-worker).
  • Host-only skill_attached / system / error in the prior suffix are skipped so they cannot zero overlap.
  • Tests: host one card vs N≥2 checkpoint tools (helper + seam); mid-turn card appends only the trailing assistant; skill_attached interrupt; worker-to-worker N tools stay 1:1.

npm run typecheck green. messageCheckpoint + turnPersistSeam 49 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L6, L8 (skip: L2 no secret/runner/client-bundle surface; L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L5 one persist stringify / bounded merge, not a poll/alloc storm; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

19a27ea closed the previous CONCERNS (host one tool_run card covering N checkpoint tools; host-only skill_attached / system / error skip). Remaining hole is the assistant shape: checkpoint is per-round, host session is not.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 mergeCheckpointOntoPrior / flexMatchExact (lib/agent/messageCheckpoint.ts) still assume this-run assistant rows line up with the host snapshot. They do not. derivePersistFold / checkpointRow (lib/workflows/turnLoop.ts) emit one assistant per model round (delta.text is always a string, including '' for tool-only rounds — lib/agent/generateOneRound.ts). Host runHarnessTurn (lib/harnessChat.ts) does not appendMessage(..., 'assistant') on text_delta; live assistant is bridge-only until the terminal appendMessage of concatenated done.text. Mid-turn onSessionPatch / usage / change_dir persist the session as […, user, encodeToolRun card(s)] with no assistant. Incoming [user, assistant(preamble or ''), tool…, assistant(final)] vs that prior: user matches, next incoming assistant vs host tool_run zeros overlap. Durable tool turn. Host onTurnStarted then a live usage or change_dir patchSession writes the pointer (HarnessHost onSessionPatch: persistTurn) after tools have painted. Worker persistStep runs before done (turnLoop awaits persist, then doneLine). Seam reads that host this-run suffix, overlap=0, appends the whole checkpoint under the B8 overlay clock. F5 / other-device shouldAdoptServer adopts duplicated user + mixed encoded/raw tools + split assistants. Same zero-overlap when the model emits a visible preamble (text: 'tooling' + toolCalls — already a turnLoop.test.ts shape) or a tool-only round (text: ''). Coalesced-tool tests stay green because incoming is [user, tool…, assistant] with no round-1 assistant row. Real generateOneRound always sets delta.text (typed string, default ''). “Host persistTurn at end overwrites” is a later best-effort PUT after done; it does not un-publish the merged blob, 409/network/detach leave it, and other-device F5 in the persist-before-done window reads it. pi === prior.length does not save this: the mismatch is inside the this-run suffix, not a short prefix of history. high
Minor L6 No helper/seam row for (a) incoming assistant before tools vs host tool card, (b) empty-string round-1 assistant, (c) host trailing concatenated done.text vs worker last-round assistant. N-tool tests omit the per-round assistant rows checkpointRow actually emits. Merge this PR. vitest run --changed and persist-parse int stay green. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON stays fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. Identical consecutive turns (same user+assistant text, prior is exactly this-run) still suffix-match as a retry and will not append — indistinguishable from persist retry without a turn boundary. Worker-shaped tool_run text is still the raw result, not encodeToolRun; hydrate coalesce may not decode those rows (accepted mapping). A host mid-stream assistant prefix in the session (if a future path writes live assistant text into SessionSnapshot) still fails exact role+text unless trailing-assistant coalesce is role-only after a tool match.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed. Suffix overlap must (1) not treat empty-text checkpoint assistants as rows the host snapshot can match, (2) skip incoming assistant while the current prior row is tool_run (preamble / empty rounds are not in the mid-turn host snapshot), (3) after a this-run tool match, let a single trailing prior assistant cover remaining incoming assistant rows (host done.text vs last-round text) the same way one host tool_run covers a run of checkpoint tools. Keep user as role+text. Worker-to-worker consecutive assistants that actually exist on both sides stay 1:1 via text equality when no skip applies. Add tests for preamble-before-tools, empty round-1 assistant, and host concatenated trailing assistant. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

Checkpoint emits one assistant per model round (including empty
tool-only text). Host mid-turn persist has tools and no assistant.
Skip incoming assistants while prior is tool_run; trailing host
done.text covers remaining this-run assistants.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (92e7863):

  • Empty-text checkpoint assistants are dropped (generateOneRound always sets delta.text, including '' for tool-only rounds).
  • Suffix overlap skips incoming assistant while the current prior row is tool_run (per-round preamble is not in the mid-turn host snapshot).
  • After a this-run tool match, a trailing prior assistant covers remaining incoming assistants (host concatenated done.text vs last-round checkpoint text). Worker-to-worker preamble stays 1:1.
  • Tests: empty-text drop; preamble vs host tool card (helper + seam); host concatenated trailing assistant; worker-to-worker preamble.

npm run typecheck green. messageCheckpoint + turnPersistSeam 54 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L6, L8 (skip: L2 no secret/runner/client-bundle surface; L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L5 one persist stringify / bounded merge, not a poll/alloc storm; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

92e7863 closed the previous CONCERNS (empty-text drop; skip incoming assistant while prior is tool_run; trailing host done.text covers remaining this-run assistants). Remaining hole is that after-tool assistant cover is role-only, so a completed prior tool-turn with the same user prompt swallows a new turn.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact (lib/agent/messageCheckpoint.ts) sets afterToolAssistant when matchedTool && both roles are assistant, then matches role only and may consume remaining incoming assistants. Combined with tool_run role-equal, the only remaining discriminator for a completed tool-turn is user text. Durable tool turn 1, user prompt "continue" (or any retry of the same line). Worker/host pointer is [user, tool_run, assistant_A]. Turn 2 uses the same prompt, different tools, different reply assistant_B. k=len(incoming) flex-matches the entire prior: user text equal, tool role-equal, assistants role-only. overlap=full → prior unchanged, B8 overlay clock still advances. F5 shouldAdoptServer adopts turn 1 as the full session. Reproduced: mergeCheckpointOntoPrior([continue, tool, first], [continue, tool, second]) returns length 3. “Identical consecutive turns are accepted residual” — that residual required equal assistant text. 92e7863 widened it to any two tool-turns that share a user line. Host concatenated done.text vs last-round checkpoint is a suffix/equal cover (Let me read that\nfile looks good ends with file looks good), not a license to match unrelated replies. Persist-retry against a host window that already ends with this turn still matches via equal or suffix. Tests use distinct 'turn-1 user' / 'turn-2 user' and never hit this. high
Minor L6 No helper/seam row for two completed tool-turns with the same user text and different assistants. Existing two-persist / host-prior rows stay green while the Major ships. Merge this PR. vitest run --changed and persist-parse int remain green. DI/cost is clean (memory stores). Concatenated-trailing-assistant test is a different shape (this-run window, not a prior completed turn). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON stays fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. A later assistant that is an accidental suffix of an earlier reply can still false-cover after a same-user tool match (narrower than role-only). Worker-shaped tool_run text is still the raw result, not encodeToolRun. Envelope reserved meta is overlaid on boot (overlayEnvelopeMeta); dropping meta from the worker blob is not a carrier wipe.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed. After a this-run tool match, a trailing prior assistant may cover remaining incoming assistants only when text is equal or a suffix/prefix cover (host concatenated done.text vs last-round checkpoint). Different replies with the same user prompt must append. Keep skip-incoming-assistant while prior is tool_run (preamble vs host card). Add a same-user-text / different-assistant tool-turn test (helper + seam). Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

Role-only trailing-assistant match after a tool_run let two completed
tool-turns that share a user prompt collapse to the first reply under
the overlay clock. Cover is now equal or suffix/prefix (host concatenated
done.text vs last-round checkpoint). Same-user different-reply appends.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (e18d4f9):

  • After a this-run tool_run match, a trailing prior assistant covers remaining incoming assistants only when text is equal or a suffix/prefix (host concatenated done.text vs last-round checkpoint). Role-only is gone — two tool-turns that share a user prompt keep both replies.
  • Empty strings never cover (endsWith('') would match every haystack).
  • Tests: same-user-text / different-assistant tool-turn (helper + seam). Existing concatenated-trailing-assistant and preamble-skip rows stay green.

npm run typecheck green. vitest run --changed: 33 files / 386 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L6, L8 (skip: L2 no secret/runner/client-bundle surface; L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L5 one persist stringify / bounded merge, not a poll/alloc storm; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

e18d4f9 closed the previous CONCERNS (after-tool assistant cover is equal/suffix/prefix, not role-only). Remaining holes are the real checkpoint shape (turnLoop interleaves per-round assistants with tools) and the reverse endsWith on that cover.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact host-card coalesce (lib/agent/messageCheckpoint.ts) only consumes consecutive incoming tool_run rows. runTurnLoop pushes {role:'assistant', delta} every round, then tools (lib/workflows/turnLoop.ts). Checkpoint is [user, asst1, tool1, asst2, tool2, asst3], not [user, preamble, tools…, final]. After matching the first tool against a host live-paint card, the next incoming row is assistant, so later tools are not coalesced. Durable two-round tool turn. Host onSessionPatch writes […, user, encodeToolRun(read+exec)]. Worker persist reads that pointer. Mid-turn merge keeps the card and appends asst2 + raw tool2 + asst3. F5 / other-device adopt shows a duplicate exec row (card + raw result). If a trailing host done.text concat is already on the pointer (persist retry), cover checks concat vs first remaining assistant (I will run the tests), fails, overlap=0, and the entire this-run is appended (duplicated user + mixed tools). Reproduced against HEAD. Tests only use preamble-then-all-tools ([u, pre, t1, t2, a]). “Preamble skip handles per-round assistants” — that skip runs only while prior[pi] is still tool_run. After the first tool match, pi has advanced off the card. Empty-text drop only removes '' rounds; generateOneRound routinely sets non-empty delta.text before more tools (“Let me read”, “I’ll run tests”). Worker persist is before done, so the live path is the mid-turn host card, not an after-the-fact host PUT. high
Major L1 assistantCovers (lib/agent/messageCheckpoint.ts) treats either text as a suffix of the other. Incoming is always the worker checkpoint (last-round / per-round text). The host-concat case only needs prior.endsWith(incoming). Reverse incoming.endsWith(prior) swallows a longer new reply that happens to end with the previous short ack. Durable tool turn 1, prompt "continue", assistant "OK". Turn 2, same prompt, different tools, assistant "All tests passed. OK". flexMatchExact user-text + tool role + reverse endsWith → overlap=full → prior unchanged, B8 clock still advances. F5 adopts turn 1 as the full session. Reproduced: merge of [continue, tool, OK] vs [continue, tool, All tests passed. OK] returns length 3. Last review locked “equal or suffix/prefix (host concatenated done.text vs last-round checkpoint).” That example is prior.endsWith(incoming) (concat is longer). Reverse is not required for worker incoming. Equal still covers persist-retry. Tests used unrelated long strings (here is the first analysis / now I will edit the file) and never a short ack. high
Minor L6 No helper/seam row for (a) interleaved per-round assistants vs a host tool card, (b) the same shape vs a trailing host concat, (c) same-user tool-turns where the new assistant ends with the prior assistant. Existing preamble/N-tool/same-user rows stay green. Merge this PR. vitest run --changed and persist-parse int remain green. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill) — first persist after upgrade of a multi-turn session can LWW-publish this run under a newer clock. Bound miss/non-JSON stays fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. A new last-round that is an accidental suffix of a prior host concat (the remaining prior.endsWith(incoming) direction) can still false-cover after a same-user tool match. Worker-shaped tool_run text is still the raw result, not encodeToolRun. Same-device F5 may keep a newer host persistTurn local and hide the mid-turn mixed blob; other-device / worker-pointer-wins will not.

Merge guidance

  • CONCERNS: do not merge until both Majors are fixed.
    1. When a prior tool_run is a coalesced host card (no later prior tool_run in the matched suffix), skip incoming assistant rows that are still followed by a tool_run and consume those tools — same as consecutive-tool coalesce. Worker-to-worker stays 1:1 when a later prior tool_run exists (interleaved [t1, asst, t2]). After that, trailing assistants still use equal / prior.endsWith(incoming) cover (or append).
    2. assistantCovers: equal or priorText.endsWith(incomingText) only. Drop reverse incoming.endsWith(prior). Empty strings still never cover.
    3. Tests: interleaved two-round tools vs mid-turn host card (helper + seam); same shape vs trailing concat (must not duplicate the user); reverse-endsWith short ack must append. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

The turn loop emits an assistant delta every model round, so a host
live-paint card vs [asst, tool, asst, tool, asst] was not coalesced
and appended duplicate tools (or the whole this-run when a trailing
concat was present). Reverse endsWith also swallowed a longer new
reply that ended with a previous short ack. Cover is equal or prior
ends with incoming only. Worker interleaved tools stay 1:1.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (5f27f48):

  • Host-card coalesce (no later prior tool_run in the matched suffix) skips incoming assistant rows that are still followed by a tool_run and consumes those tools. Interleaved per-round checkpoint text (turnLoop assistant-delta every round) no longer duplicates the host card or the user.
  • Worker-to-worker interleaved [t1, asst, t2] stays 1:1 (later prior tool_run exists).
  • assistantCovers is equal or prior.endsWith(incoming) only. Reverse dropped — "OK" vs "All tests passed. OK" appends.
  • Tests: interleaved vs mid-turn host card (helper + seam); same vs trailing concat (no duplicate user); reverse-endsWith short ack appends; worker-to-worker interleaved retry.

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop 93 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L6, L8 (skip: L2 no secret/runner/client-bundle surface; L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L5 one persist stringify / bounded merge, not a poll/alloc storm; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

5f27f48 closed the previous CONCERNS (host-card coalesce skips interleaved round assistants; assistantCovers is equal / prior.endsWith(incoming) only). Remaining hole: skipped incoming assistants are consumed as overlap, so they never reach the remainder.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact (lib/agent/messageCheckpoint.ts) skips incoming assistant rows to let a host tool_run card match (preamble while prior[pi] is tool_run; interleaved assts still followed by a tool_run under host-card coalesce). mergeCheckpointOntoPrior then takes incoming.slice(overlap) — those skipped rows sit inside the matched prefix, so they are discarded. runTurnLoop persists before done SSE (lib/workflows/turnLoop.ts). Host onTurnStarted / live usage / change_dir / meta_sandbox_switch all patchSessionputEnvelopeOnce (lib/harnessChat.ts), so a bound pointer after tools is commonly […, user, encodeToolRun card(s)] with no trailing assistant (live asst is bridge-only until done.text). Durable multi-round tool turn. First tools paint; a usage (or change_dir) persist writes the mid-turn card. Worker persistStep reads that pointer, suffix-merges, publishes […, user, card, last-round text] under the B8 overlay clock. F5 / other-device parseCloudSessionSnapshot + shouldAdoptServer adopts it. Per-round prose (Let me read the file, I will run the tests) is gone — only 3 passed remains. Reproduced: existing helper/seam rows already assert this (interleaved per-round assistants vs mid-turn host card → trailing '3 passed' only). “Host persistTurn after done writes the full concat and should LWW-win” — worker persist is before done; overlay clock is max(worker now, stored+1) on the Vercel clock, so the later browser PUT can 409/adopt the incomplete blob. Other-device F5 never sees host persistTurn; the worker blob is the DoD transcript. “Skip is required so overlap does not zero” — skip is valid for matching; it is not a license to drop unmatched assts from the remainder when the prior has no covering assistant. Trailing-concat cover (prior already has done.text) is a different path and must stay no-append. high
Minor L6 Helper + seam rows for interleaved vs mid-turn host card lock in last-round-only ('3 passed' / 'file looks good'). No row that skipped this-run assistant text survives onto the pointer when the prior ends on a tool card. Merge this PR. messageCheckpoint / turnPersistSeam stay green while other-device F5 after a usage mid-turn persist hydrates last-round-only. DI/cost is clean (memory stores). Trailing-concat rows are a different shape (prior already has done.text). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON stays fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match. Worker-shaped tool_run text is still the raw result; coalesceToolRunMessages fail-open keeps it as plain text if the worker blob wins before a host encodeToolRun PUT. Suffix search is O(incoming × prior) on an 8 MiB object — fine for typical sessions, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed.
    1. Skipping incoming assistants to match a host tool card must not drop them from the remainder when the prior suffix has no covering assistant. Fold those this-run assistant texts into the appended tail (one concatenated row matching host done.text += of per-round delta.text, or the skipped rows in order). Prior that already ends with a covering concat stays no-append.
    2. Tests: interleaved vs mid-turn host card (helper + seam) must keep all this-run assistant prose, not last-round-only. Trailing-concat / reverse-endsWith / same-user-different-reply / leftover { deltas } / bound miss rows stay as they are.
    3. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

Skipped incoming assistants sat inside the matched prefix, so
incoming.slice(overlap) dropped them. A mid-turn host pointer
(usage / change_dir) then LWW-published last-round-only under
the overlay clock. Fold this-run assistant texts into one
appended row (+= of delta.text) when prior ends on tool_run.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (8570ec3):

  • Skipping incoming assistants to match a host tool card no longer drops them from the remainder. When the prior suffix ends on tool_run (mid-turn usage / change_dir pointer, no covering assistant), this-run assistant texts are folded into one appended row (+= of per-round delta.text, same as host done.text).
  • Trailing-concat cover stays no-append. Reverse-endsWith short ack still appends. Same-user different reply still appends the whole this-run.
  • Tests: interleaved / preamble vs mid-turn host card keep all this-run assistant prose (helper + seam).

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop 93 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

8570ec3 closed the previous CONCERNS (fold skipped per-round assistants onto a mid-turn host card when the remainder is trailing assistants). Remaining hole: that fold is gated on a nonempty remainder, so a full-prefix match that ends on tool_run still drops the skipped prose.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 shouldFoldSkippedAssistants (lib/agent/messageCheckpoint.ts) returns false when appended.length === 0. checkpointToSnapshotMessages drops empty-text last-round assistants (generateOneRound uses (result.text ?? '').trim(), thinking-only / whitespace finish). Incoming then ends on tool_run. flexMatchExact matches the full prefix against a mid-turn host card (skip preambles, coalesce tools), overlap=incoming.length, remainder empty, fold never runs, skipped assts are discarded. Durable multi-round tool turn. Host usage / change_dir persist writes […, user, encodeToolRun card]. Last model round is empty/whitespace (no tools). Worker persistStep incoming is [user, asst1, t1, asst2, t2] (empty last asst dropped). Merge publishes the prior card and drops asst1/asst2. F5 / other-device shouldAdoptServer adopts user + tool card, no this-run prose. Reproduced on HEAD: mergeCheckpointOntoPrior([…, user, card], checkpointToSnapshotMessages([user, 'Let me read the file', tool, 'I will run the tests', tool, ''])) → texts are turn-1 + user + card only. 8570ec3 folds skipped assts” — only when the remainder is trailing assistants. The existing interleaved helper/seam rows keep a nonempty last-round (3 passed), so they do not hit full-prefix overlap. Covering concat is already excluded by lastKeptRole(prior) !== 'tool_run'; appended.length === 0 is not that path. “Host persistTurn after done writes concat” — worker persist is still before done; overlay clock can 409/beat the later browser PUT; other-device F5 never sees host persistTurn. high
Major L1 createTurnPersistSeam (lib/agent/turnPersistSeam.ts) catch-swallows readEnvelope throw as stored = null, then skips the prior-read (no pointer) and suffix-merges onto empty. Production Redis rejects commands when unreachable (lib/sessions/redisSessionStore.ts fail-closed, no offline queue). A first-read reject + B7 retry success publishes this-run-only under clock(0) = Date.now(). Complete turn 1 (bound readable pointer). Turn 2 persist: first readEnvelope rejects (socket blip / reconnect). Seam treats no envelope, writes [user2, assistant2], B7’s second GET succeeds and advances transcriptPointer, B8 stamps a newer clock. F5 LWW-adopts turn 2 only. Distinct from bound blob read() === null (already {ok:false}). “If Redis is down B7 also fails” — node-redis reconnects; first command reject + second success is the documented reconnect path. null (missing envelope, first persist) is not throw (read failed). The catch existed for the overlay clock; this PR tied merge skip to the same swallow. high
Minor L6 No helper/seam row for (a) empty last-round / incoming ending on tool_run vs mid-turn host card, (b) readEnvelope throw must {ok:false} and leave the pointer. Interleaved-with-trailing-asst rows stay green. Merge this PR. messageCheckpoint / turnPersistSeam stay green while other-device F5 after a thinking-only finish hydrates no this-run prose, or a Redis blip clobbers history. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON stays fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match. Worker-shaped tool_run text is still the raw result. Suffix search is O(incoming × prior) on an 8 MiB object — fine for typical sessions, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until both Majors are fixed.
    1. shouldFoldSkippedAssistants: drop the appended.length === 0 gate. Fold when lastKeptRole(prior) === 'tool_run' and this-run had assistants (covering concat already fails lastKeptRole). Empty last-round vs mid-turn card must keep all this-run assistant prose.
    2. readEnvelope throw → {ok:false, code:'write_failed'}, pointer unchanged. Missing envelope (null) still first-persist / this-run-only.
    3. Tests: empty last-round vs mid-turn host card (helper + seam); envelope-throw fail-closed. Trailing-concat / reverse-endsWith / leftover { deltas } / bound miss rows stay as they are.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

shouldFoldSkippedAssistants no longer requires a nonempty remainder, so a
full-prefix match that ends on tool_run (empty last-round assistant dropped)
still folds skipped this-run prose onto a mid-turn host card.

readEnvelope throw is write_failed (pointer unchanged), not stored=null
this-run-only. Missing envelope (null) stays first persist.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (120b2ef):

  • shouldFoldSkippedAssistants no longer requires a nonempty remainder. A full-prefix match that ends on tool_run (empty last-round assistant dropped by checkpointToSnapshotMessages) still folds skipped this-run assistant texts onto a mid-turn host card. Covering concat stays no-append (lastKeptRole !== 'tool_run').
  • readEnvelope throw → {ok:false, code:'write_failed'}, pointer unchanged. Missing envelope (null) still first-persist / this-run-only.
  • Tests: empty last-round vs mid-turn host card (helper + seam); envelope-throw fail-closed.

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop 96 passed. vitest run --changed: 33 files / 396 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: PASS WITH NOTES
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

120b2ef closed the previous CONCERNS pair (empty last-round full-prefix fold; readEnvelope throw fail-closed). This pass re-attacked HEAD as if those fixes were wrong, then enumerated remaining production host/checkpoint shapes that prior rounds never executed: skill-attached between two host cards, consecutive group-full cards vs interleaved tools, usage-before-first-tool (user-only prior), error-after-card empty-finish, text-only turn after a tool-turn, same-user no-tools different assistant, user-prompt substring. All held. Attack did not breach with current evidence.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
(none survived self-refutation)

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match. Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal) — no turn-boundary id on the blob. Worker-shaped tool_run text is still the raw result; hydrate coalesce may keep it as plain text if the worker blob wins before a host encodeToolRun PUT. Suffix search is O(incoming × prior) on an 8 MiB object — fine for typical sessions, not a poll loop.

Merge guidance

  • PASS WITH NOTES: safe to merge from this attack; nits optional. Do not start another adversarial round unless the merge predicate or persist seam changes again.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L5, L6, L8 (skip: L2 no secret/runner/client-bundle surface; L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

120b2ef closed the previous CONCERNS pair (empty last-round full-prefix fold; readEnvelope throw fail-closed). This pass re-attacked HEAD as if those fixes were wrong. Mid-turn host-card fold, covering concat, reverse-endsWith, same-user-with-trailing-assistant, leftover { deltas }, bound miss/non-JSON, envelope throw all still hold. Remaining hole is that the empty-remainder fold cannot tell a mid-turn host card from a worker-shaped prior that already is this run.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 shouldFoldSkippedAssistants (lib/agent/messageCheckpoint.ts) fires on lastKeptRole(prior)==='tool_run' + incoming has any assistant, including when that prior already is this-run (1:1 worker rows, no skipped assts). 120b2ef dropped the nonempty-remainder gate so a full-prefix match still folds. Fold then appends += of this-run assistant texts onto a blob that already contains them. Durable tool turn, last model round empty/whitespace (checkpointToSnapshotMessages drops it). First persist (empty prior / leftover { deltas }) writes [user, preamble, tool_run]. B7 advances transcriptPointer; the 'use step' then times out before B8 returns (the PR’s own B7/B8 partial-commit residual). Vercel retries persistStep. Second merge: prior ends on tool_run, overlap=full, remainder empty, fold appends the preamble again. F5 / other-device shouldAdoptServer adopts [user, preamble, tool, preamble]. Reproduced: mergeCheckpointOntoPrior([u1,a1, ...incoming], incoming) with empty last-round incoming → duplicate 'Let me'. “Persist is once per turn and overlayWorkerMeta never throws” — retry is timeout-after-B7, not a throw. The existing worker-to-worker interleaved tools stay 1:1 on persist retry row keeps a trailing assistant so lastKeptRole is assistant and never hits this gate. Mid-turn host-card fold does skip incoming assts against a tool_run card; worker 1:1 does not. Those are distinguishable: fold only when the winning flexMatchExact actually skipped an incoming assistant. high
Minor L6 No helper/seam row for worker-to-worker empty last-round persist retry. The 1:1 retry row has a nonempty trailing assistant; the empty-last-round rows use a host mid-turn card, not a worker prior that already contains this run. Merge this PR. messageCheckpoint / turnPersistSeam stay green while a B7-then-retry duplicates preamble prose. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match. Two consecutive tool-only turns that share a user prompt are indistinguishable from a persist retry without a turn-boundary id — including a completed empty-finish turn ([user, card]) followed by a new same-prompt turn with a reply (that reply glues onto the previous card; fixing it would re-break the mid-turn host-card fold). Worker-shaped tool_run text is still the raw result. Suffix search is O(incoming × prior) on an 8 MiB object — fine for typical sessions, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed.
    1. shouldFoldSkippedAssistants: fold only when the winning suffix match skipped incoming assistant rows against a prior tool_run (mid-turn host card / host-card coalesce). A 1:1 worker prior that already ends on tool_run must keep prior (no-append), including empty last-round.
    2. Tests: worker-to-worker empty last-round persist retry (helper + seam) must not duplicate this-run assistant prose. Existing mid-turn host-card empty-last-round / interleaved fold rows stay green.
    3. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

Empty-remainder fold treated a worker 1:1 prior that already ends on
tool_run as a mid-turn host card, so a persist-step retry after B7
duplicated this-run assistant prose. Fold only when flexMatchExact
skipped an incoming assistant against a prior tool_run.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (9b41884):

  • shouldFoldSkippedAssistants now requires the winning flexMatchExact to have skipped an incoming assistant against a prior tool_run (mid-turn host card / host-card coalesce). A worker 1:1 prior that already ends on tool_run (empty last-round persist retry after B7) stays no-append.
  • Tests: worker-to-worker empty last-round persist retry (helper + seam) does not duplicate this-run assistant prose. Existing mid-turn host-card empty-last-round / interleaved fold rows stay green.

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop 98 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: PASS WITH NOTES
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes

9b41884 closed the previous CONCERNS (shouldFoldSkippedAssistants only when the winning match skipped an incoming assistant against a prior tool_run). This pass re-attacked HEAD as if that gate was wrong, then enumerated remaining production host/checkpoint shapes: thinking-split two consecutive host cards (interleaved + empty last-round), group-full two cards vs N tools, usage-before-first-tool (user-only prior), error-after-card empty-finish, skill-attached between two cards with interleaved tools, text-only turn after a tool-turn, same-user no-tools different assistant, user-prompt substring, worker empty last-round persist retry. All held. Attack did not breach with current evidence.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
(none survived self-refutation)

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match (reproduced: "All tests passed. OK" vs "OK" keeps turn 1). Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal). Worker-shaped tool_run text is still the raw result; hydrate coalesce may keep it as plain text if the worker blob wins before a host encodeToolRun PUT. Suffix search is O(incoming × prior) on an 8 MiB object — fine for typical sessions, not a poll loop. A host-only row between two tool cards plus consecutive (non-interleaved) checkpoint tools can duplicate; stream skills are start-of-turn and JSON-path skills are end-of-turn, so that shape is not a current producer.

Merge guidance

  • PASS WITH NOTES: safe to merge from this attack; nits optional. Do not start another adversarial round unless the merge predicate or persist seam changes again.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

Adversarial PASS WITH NOTES on #868. Extra helper/seam rows pin production
host shapes that held but were not in the suite: consecutive tool cards
(thinking/text_delta split), usage-before-first-tool, error-after-card.

Copy link
Copy Markdown
Owner Author

Follow-up after adversarial PASS WITH NOTES (952816a):

  • Helper + seam rows lock production host shapes that held but were not in the suite: thinking-split two consecutive tool_run cards vs interleaved checkpoint tools (and empty last-round); user-only prior (usage before first tool); error-after-card empty-finish.
  • Merge predicate unchanged. messageCheckpoint + turnPersistSeam 73 passed.

No merge-predicate change — do not start another adversarial round.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: PASS WITH NOTES
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob @ 952816a · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path — persist stays Vercel worker + Blob, Wasm still never talks to storage; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes (docs/feature-divide.md envelope/Blob row checked; SECURITY.md blob-contents row checked)

9b41884 closed the last CONCERNS (fold only when the winning match skipped an incoming assistant against a prior tool_run). 952816a does not change the merge predicate; it only locks production host shapes that the previous PASS already executed off-suite. This pass re-attacked HEAD as if that gate and those new rows were wrong.

Re-executed against current mergeCheckpointOntoPrior / createTurnPersistSeam:

  • thinking-split two consecutive host cards vs interleaved tools (and empty last-round)
  • user-only prior (usage / patchSession before first tool)
  • error-after-card empty-finish
  • worker-to-worker empty last-round persist retry (no duplicate preamble)
  • same-user tool-turns with different replies; reverse-endsWith short ack appends
  • trailing host done.text concat cover (no duplicate user)
  • leftover { deltas } this-run-only; bound miss / non-JSON / envelope-throw fail-closed
  • clock stamped once and equal to B8; persistStep still has no Date.now()
  • missing scope.sessionId{ok:false, code:'invalid_scope'} before seam.persist

All held. Attack did not breach with current evidence.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
(none survived self-refutation)

Candidates that died in refutation (not findings): fold-join without \n vs some host concat fixtures — checkpoint rows themselves have no separators, and foldIncomingAssistants is += of per-round delta.text as locked; snapshotMessagesFromUnknown rejecting a whole bound snapshot because one row is malformed — host SessionMessage writers already require id/role/text/at, same as parseCloudSessionSnapshot; O(incoming × prior) suffix search on an 8 MiB object — one persist, not a poll loop.

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match ("All tests passed. OK" vs "OK" keeps turn 1). Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal). Worker-shaped tool_run text is still the raw result; hydrate coalesce may keep it as plain text if the worker blob wins before a host encodeToolRun PUT. A host-only row between two tool cards plus consecutive (non-interleaved) checkpoint tools can duplicate; stream skills are start-of-turn and JSON-path skills are end-of-turn, so that shape is not a current producer.

Merge guidance

  • PASS WITH NOTES: safe to merge from this attack; nits optional. Merge predicate is unchanged since 9b41884. No code push from this review.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob @ 952816a · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path — persist stays Vercel worker + Blob, Wasm still never talks to storage; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes (docs/feature-divide.md envelope/Blob row checked; SECURITY.md blob-contents row checked)

9b41884 closed the last CONCERNS (fold only when the winning match skipped an incoming assistant against a prior tool_run). 952816a only locked production host shapes off-suite; merge predicate unchanged. This pass re-attacked HEAD as if that gate and those rows were wrong, then executed remaining production shapes prior rounds never ran against the live helper: trailing Turn ended · model finished system on a completed host persistTurn, JSON-path skill_attached after the card, thinking-split two cards + concat + system, Stop/error turn-end after a mid-turn card, 3 consecutive host cards vs interleaved tools. Those held for a nonempty last-round. Remaining hole is persist retry onto the fold output when the last checkpoint round is empty.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact (lib/agent/messageCheckpoint.ts) requires pi === prior.length after consuming the incoming prefix. A successful mid-turn fold leaves prior […, user, host card, foldedJoin] (lastKeptRole === 'assistant'). Empty last-round incoming ends on tool_run (checkpointToSnapshotMessages drops ''). Coalesce consumes this-run tools against the card, but the leftover covering assistant is not skippable (host-only skip only), so the full prefix fails. The next-shorter prefix matches and appends the last raw checkpoint tool after the folded assistant. Reproduced on HEAD: mergeCheckpointOntoPrior([u1,a1,user,card,folded], checkpointToSnapshotMessages([user, 'Let me read the file', tool, 'I will run the tests', tool, ''])) → extra tool_run:"exit=1" after the folded prose. Durable multi-round tool turn, last model round empty/whitespace (generateOneRound .trim()). Host usage / change_dir persist writes the mid-turn encodeToolRun card. First persistStep folds skipped assts (+= of per-round delta.text) and B7 PUTs [user, card, foldedJoin]. 'use step' times out before B8 returns; Vercel retries persistStep. Second merge reads that folded pointer, overlap is not full, remainder is the last checkpoint tool. B8 overlay clock still advances. F5 / other-device shouldAdoptServer adopts mixed encoded card + extra raw tool_run after the assistant. worker-to-worker empty last-round persist retry is tested” — that prior is 1:1 checkpoint rows (lastKeptRole === 'tool_run', skippedAssistant === false, no-append). This prior is the output of a successful fold. “Host persistTurn after done overwrites” — runTurnLoop awaits persist before done SSE; a B7-then-retry is still inside that await, so host concat is not on the pointer yet. “Identical consecutive turns are accepted residual” — this is the same turn, same checkpoint, retried. high
Minor L6 No helper/seam row for (a) empty last-round retry onto the folded mid-turn snapshot, (b) production trailing Turn ended · model finished system on a completed host persistTurn (nonempty last-round held when executed off-suite). Existing empty-last-round rows use a mid-turn card (first persist) or 1:1 worker rows. Merge this PR. messageCheckpoint / turnPersistSeam stay green while a B7-then-retry after an empty-finish fold hydrates an extra raw tool row. DI/cost is clean (memory stores). Trailing-concat rows keep a nonempty last-round (3 passed) so afterToolAssistant consumes the covering concat. high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a new last-round that is an accidental suffix of a prior host concat after a same-user tool match. Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal). Worker-shaped tool_run text is still the raw result. A Stop/error Turn ended line already on a mid-turn card can sit before a folded assistant if persist races host abort — persist is the success path; that overlay is the pre-existing abort-vs-step race. Suffix search is O(incoming × prior) on an 8 MiB object — one persist, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed.
    1. When the incoming prefix is fully consumed after a this-run tool match, a leftover prior assistant that covers += of this-run assistant texts (the folded done.text) must not zero the match — persist retry onto a successful mid-turn fold / covering concat. Consecutive prior assistants stay 1:1. Different replies with the same user prompt must still append.
    2. Tests: empty last-round persist retry onto a folded mid-turn snapshot (helper + seam) must not append a leftover raw tool_run. Existing mid-turn host-card empty-last-round / worker 1:1 retry / trailing-concat nonempty-last rows stay green. Optional lock: completed host persistTurn trailing Turn ended · model finished + nonempty last-round (production pushTurnEnd).
    3. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

B7-then-retry after a mid-turn fold left the last raw checkpoint tool
appended: empty last-round incoming ends on tool_run, so the leftover
folded done.text assistant zeroed full-prefix overlap.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (fee19fb):

  • flexMatchExact skips one leftover prior assistant that covers += of this-run assistant texts when the incoming prefix is fully consumed after a this-run tool match (empty last-round persist retry onto a mid-turn fold). Consecutive prior assistants stay 1:1. Different replies still append.
  • Tests: empty last-round retry onto folded mid-turn snapshot (helper + seam) does not append a leftover raw tool_run; trailing Turn ended · model finished on a completed host persistTurn (nonempty last-round) is not duplicated. Existing 1:1 worker empty-last-round / mid-turn fold / reverse-endsWith rows stay green.

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop 108 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob @ fee19fb · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path — persist stays Vercel worker + Blob, Wasm still never talks to storage; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes (docs/feature-divide.md envelope/Blob row checked; SECURITY.md blob-contents row checked)

fee19fb closed the previous CONCERNS (leftover covering assistant on empty last-round persist retry onto a mid-turn fold). This pass re-attacked HEAD as if that leftover skip was wrong, then executed remaining production host/checkpoint shapes: two-card / three-card fold retry, nonempty last-round retry onto fold, fold+skill_attached retry, error-after-card fold retry, host += concat + Turn ended vs empty last-round, reverse-endsWith short ack, worker-to-worker same-user different preamble. Those held. Remaining hole is that leftover skip uses assistantCovers (endsWith) on a short incoming prefix, so a new same-user tool-turn whose first-round preamble is a suffix of the prior leftover is not treated as a new turn.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact leftover-assistant skip (lib/agent/messageCheckpoint.ts) fires whenever ii === prefixLen && matchedTool and assistantCovers(leftover, foldText of that prefix). fee19fb intended this for full incoming (empty last-round retry onto […, card, foldedJoin]). Longest-prefix search also tries short k. A short prefix whose only assistant text is a suffix of the leftover covers the entire prior, then incoming.slice(overlap) appends only the unmatched tail. Reproduced on HEAD: mergeCheckpointOntoPrior([continue, card, 'All tests passed. OK'], checkpointToSnapshotMessages([continue, 'OK', tool, 'now I will edit the file']))[continue, card, 'All tests passed. OK', 'now I will edit the file'] (new user + new tools dropped; orphan assistant glued on). Same with 'Finished. Done' vs first-round 'Done'. Durable tool turn 1, user prompt "continue" (or any retry of the same line), assistant leftover 'All tests passed. OK'. Turn 2, same prompt, real turnLoop checkpoint [user, asst_preamble, tool…, asst_final] with preamble 'OK' then different tools and a different reply. Worker persist is worker-to-worker (host persistTurn of user2 409s / carrier-off / int persistTurn2 shape: prior still ends on turn-1 leftover). B8 overlay clock still advances. F5 / other-device shouldAdoptServer adopts turn 1's card+concat plus an orphan turn-2 reply — no second user line, no turn-2 tools. fee19fb leftover skip is only for retry onto the same fold” — the skip does not require prefixLen === incoming.length, so a short k that ends on the first this-run tool matches the full prior. “Existing same-user / reverse-endsWith rows stay green” — those incoming rows omit the per-round preamble ([user, tool, asst]); real generateOneRound always emits an assistant delta, and the PR’s own lock is that shape. Reverse-endsWith ('OK' vs 'All tests passed. OK' as the trailing reply) still appends; this hole is leftover endsWith first-round preamble. “Host already wrote user2 before worker persist” — worker persist is at end of turn 2, but a 409 / carrier-off / worker-to-worker two-persist (this PR’s own persistTurn2 world, with distinct user strings so the suite missed it) leaves prior ending on the leftover. “Identical consecutive turns are accepted residual” — that residual is full-turn no-append when last-round is a suffix of leftover; this is a partial absorb of a different reply. high
Minor L6 No helper/seam row for same-user tool-turn whose first-round preamble is a suffix of the prior leftover covering assistant. Existing same-user row has no preamble; empty-last-round retry rows use the same fold text (exact cover of full incoming). Merge this PR. messageCheckpoint / turnPersistSeam stay green while a second "continue" whose model starts with 'OK' / 'Done' hydrates an orphan assistant. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. assistantCovers prior.endsWith(incoming) can still false-cover a full new turn whose entire assistant fold is an accidental suffix of a prior leftover (whole-turn no-append — already accepted). Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal). Worker-shaped tool_run text is still the raw result. A host concat that joins per-round text with \n (not production done.text, which is +=) still fails leftover skip and can append a leftover raw tool — not a current producer. Suffix search is O(incoming × prior) on an 8 MiB object — one persist, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed.
    1. Leftover covering-assistant skip must only run when the incoming prefix is the entire this-run (prefixLen === incoming.length) — empty last-round persist retry onto a fold / covering concat. A short prefix whose fold text is a suffix of leftover must not consume the prior; same-user different-reply with a first-round preamble must append.
    2. Tests: helper + seam, same-user tool-turn with first-round preamble 'OK' vs leftover 'All tests passed. OK' (and 'Done' / 'Finished. Done') must append the whole this-run (second user line + new tools + new reply). Existing empty last-round fold-retry / worker 1:1 retry / reverse-endsWith / trailing-concat rows stay green.
    3. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

A short prefix whose fold text is a suffix of leftover (OK vs
All tests passed. OK) matched the entire prior and appended an
orphan assistant. Leftover skip is empty last-round retry only.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (3e76b50):

  • flexMatchExact leftover covering-assistant skip now requires prefixLen === incoming.length (empty last-round persist retry onto a fold / covering concat). A short prefix whose fold text is a suffix of leftover (OK vs All tests passed. OK) no longer consumes the prior.
  • Tests: same-user tool-turn with first-round preamble 'OK' / 'Done' vs leftover 'All tests passed. OK' / 'Finished. Done' (helper + seam) appends the whole this-run. Existing empty last-round fold-retry / worker 1:1 retry / reverse-endsWith rows stay green.

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop 111 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob @ 3e76b50 · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path — persist stays Vercel worker + Blob, Wasm still never talks to storage; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes (docs/feature-divide.md envelope/Blob row checked; SECURITY.md blob-contents row checked)

3e76b50 closed the previous CONCERNS (leftover covering-assistant skip only on the full incoming prefix). This pass re-attacked HEAD as if that gate was wrong, then executed remaining production checkpoint shapes: 3e76b50 preamble-suffix + different last-round still appends; empty last-round + different preamble still appends; nonempty last-round retry onto a mid-turn fold stays no-append; leftover { deltas } / bound miss / envelope-throw unchanged. Remaining hole is afterToolAssistant last-round cover after skip-preamble.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact (lib/agent/messageCheckpoint.ts) skips incoming assistant rows while prior[pi] is tool_run (mid-turn host-card path), then afterToolAssistant covers remaining incoming assistants when leftover endsWith last-round. Combined, a new same-user tool-turn whose last-round is equal/suffix of leftover is treated as persist-retry even when the skipped preamble and tools differ. Reproduced on HEAD: mergeCheckpointOntoPrior([continue, card, 'All tests passed. OK'], checkpointToSnapshotMessages([continue, 'Let me edit the file', tool, 'OK'])) returns length 3 (turn 2 dropped). Same for 'Finished. Done' vs last-round 'Done', equal short 'OK' vs 'OK' with a different preamble, and thinking-split two cards. Durable tool turn 1, user prompt "continue" (or any retry of the same line), leftover covering assistant 'All tests passed. OK' / 'OK' / 'Finished. Done'. Turn 2, same prompt, real turnLoop checkpoint [user, preamble, tool…, last] with a different preamble ('Let me edit the file') and different tools, last-round a short ack ('OK' / 'Done'). Worker-to-worker / host-409 / carrier-off leaves prior ending on leftover. B8 overlay clock still advances. F5 / other-device shouldAdoptServer adopts turn 1 as the full session. “Last-round suffix cover is accepted residual (All tests passed. OK vs OK)” — that residual was last-round-as-the-turn's-reply. Production generateOneRound always emits a per-round assistant; skip-preamble throws away the actual new prose and leaves only the short ack as discriminator. 3e76b50 closed leftover-skip on a short prefix whose fold is a suffix of leftover (orphan glue). It does not gate afterToolAssistant. “Existing same-user / reverse-endsWith / 3e76b50 rows stay green” — those either omit the preamble or use a last-round that does not suffix leftover (now I will edit the file). “Host concat done.text needs prior.endsWith(last-round)” — same-turn leftover is += of this-run assts (doneLine(assistantText) / finalizeAssistant(ev.text)), so leftover already covers the full this-run fold, not just last-round. A leftover that does not start with the skipped preamble is a different turn. high
Minor L6 No helper/seam row for same-user tool-turn with a different preamble and a last-round that is equal/suffix of leftover. 3e76b50 rows use a last-round that does not suffix leftover; reverse-endsWith rows omit the preamble. Merge this PR. messageCheckpoint / turnPersistSeam stay green while a second "continue" whose model ends with 'OK' / 'Done' hydrates turn 1 only. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal). A new turn with no nonempty preamble (empty first rounds dropped) whose last-round is still a suffix of leftover remains last-round-only cover — not a current generateOneRound producer when any earlier round had text. Worker-shaped tool_run text is still the raw result. Suffix search is O(incoming × prior) on an 8 MiB object — one persist, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed.
    1. After skip-preamble, trailing prior-assistant cover must require leftover to cover the full this-run assistant fold (+= of skipped preambles + last-round, the same done.text / foldIncomingAssistants string), not last-round alone. A leftover that does not cover that fold (different preamble) must append. Worker 1:1 (no skip) keeps equal / prior.endsWith(incoming) on the current row. Host concat fixtures that join with \\n are not production (doneLine / generateOneRound .trim() then +=); production leftover is the fold.
    2. Tests: helper + seam, same-user tool-turn with preamble 'Let me edit the file' / 'I will apply the patch' and last-round 'OK' / 'Done' vs leftover 'All tests passed. OK' / 'OK' / 'Finished. Done' must append the whole this-run. Existing 3e76b50 preamble-suffix + different last-round / empty last-round fold-retry / trailing-concat / reverse-endsWith rows stay green.
    3. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob @ 3e76b50 · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path — persist stays Vercel worker + Blob, Wasm still never talks to storage; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes (docs/feature-divide.md envelope/Blob row checked; SECURITY.md blob-contents row checked)

3e76b50 closed leftover covering-assistant skip only on the full incoming prefix. This pass re-attacked HEAD as if that gate was wrong, then executed remaining production checkpoint shapes against flexMatchExact afterToolAssistant. 3e76b50 preamble-suffix + different last-round still appends; empty last-round retry onto a fold stays no-append; leftover { deltas } / bound miss / envelope-throw unchanged. Two last-round-endsWith holes remain.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact (lib/agent/messageCheckpoint.ts) skips incoming assistant rows while prior[pi] is tool_run (mid-turn host-card path), then afterToolAssistant covers remaining incoming assistants when leftover endsWith last-round. Combined, a new same-user tool-turn whose last-round is equal/suffix of leftover is treated as persist-retry even when the skipped preamble and tools differ. Reproduced on HEAD: mergeCheckpointOntoPrior([continue, card, 'All tests passed. OK'], checkpointToSnapshotMessages([continue, 'Let me edit the file', tool, 'OK'])) returns length 3 (turn 2 dropped). Same for 'Finished. Done' vs last-round 'Done', equal short 'OK' vs 'OK' with a different preamble, and thinking-split two cards. Durable tool turn 1, user prompt "continue" (or any retry of the same line), leftover covering assistant 'All tests passed. OK' / 'OK' / 'Finished. Done'. Turn 2, same prompt, real turnLoop checkpoint [user, preamble, tool…, last] with a different preamble ('Let me edit the file') and different tools, last-round a short ack ('OK' / 'Done'). Worker-to-worker / host-409 / carrier-off leaves prior ending on leftover. B8 overlay clock still advances. F5 / other-device shouldAdoptServer adopts turn 1 as the full session. “Last-round suffix cover is accepted residual (All tests passed. OK vs OK)” — that residual was last-round-as-the-turn's-reply. Production generateOneRound always emits a per-round assistant; skip-preamble throws away the actual new prose and leaves only the short ack as discriminator. 3e76b50 closed leftover-skip on a short prefix whose fold is a suffix of leftover (orphan glue). It does not gate afterToolAssistant. “Existing same-user / reverse-endsWith / 3e76b50 rows stay green” — those either omit the preamble or use a last-round that does not suffix leftover (now I will edit the file). “Host concat done.text needs prior.endsWith(last-round)” — same-turn leftover is += of this-run assts (doneLine(assistantText) / finalizeAssistant(ev.text)), so leftover already covers the full this-run fold, not just last-round. A leftover that does not start with the skipped preamble is a different turn. high
Major L1 Worker 1:1 (no skip): afterToolAssistant still uses assistantCovers (equal or prior.endsWith(incoming)). A new same-user tool-turn whose first-round preamble matches leftover's preamble 1:1, then a last-round that is a suffix of leftover last-round, is treated as persist-retry. Tools are role-equal so they cannot discriminate. Reproduced on HEAD: mergeCheckpointOntoPrior(checkpointToSnapshotMessages([fix it, 'Let me look at the file', old-tool, 'All tests passed. OK']), checkpointToSnapshotMessages([fix it, 'Let me look at the file', new-tool, 'OK'])) returns length 4 (turn 2 dropped). Same for worker-interleaved [t1, mid, t2, last] when mid matches and last is a suffix. Durable worker-to-worker (this PR's persistTurn2 world, host 409, carrier-off). Turn 1 user "fix it", model 'Let me look at the file' + tool + 'All tests passed. OK'. Turn 2 same prompt, same common opening, different tool result, last-round 'OK' / 'Done'. B8 overlay clock advances. F5 adopts turn 1 only. “Identical consecutive turns are accepted residual” — leftover 'All tests passed. OK' is not identical to 'OK'; equal-only would append, endsWith is what swallows. “Worker 1:1 retry needs endsWith” — retry leftover equals last-round ('use step' retries the same checkpoint). endsWith is only required for host concat leftover (no pre-tool assistant row; live assistant is bridge-only until done.text). Once a pre-tool / interleaved assistant has already 1:1-matched, leftover is worker last-round, not concat. “Models never repeat first-round text” — "Let me look at the file" / "I'll check" are stock openings on a repeated user line. high
Minor L6 No helper/seam row for (1) same-user tool-turn with a different preamble and a last-round that is equal/suffix of leftover, or (2) worker 1:1 matching preamble + last-round suffix of leftover. 3e76b50 rows use a last-round that does not suffix leftover; reverse-endsWith rows omit the preamble or use a longer new last-round. Merge this PR. messageCheckpoint / turnPersistSeam stay green while a second "continue" / "fix it" whose model ends with 'OK' / 'Done' hydrates turn 1 only. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. Two consecutive tool-only turns that share a user prompt and have no assistant prose are indistinguishable from a persist retry (tool_run is role-equal). A new turn with no nonempty preamble (empty first rounds dropped) and no 1:1 assistant match whose last-round is still a suffix of leftover remains last-round-only cover — host concat retry needs that endsWith. Two consecutive turns that share user + first-round and an identical last-round (OK vs OK) stay indistinguishable from retry. Worker-shaped tool_run text is still the raw result. Suffix search is O(incoming × prior) on an 8 MiB object — one persist, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until both Majors are fixed.
    1. After skip-preamble, trailing prior-assistant cover must require leftover to cover the full this-run assistant fold (+= of skipped preambles + last-round, the same done.text / foldIncomingAssistants string), not last-round alone. A leftover that does not cover that fold (different preamble) must append. Worker 1:1 (no skip) does not use fold cover on last-round (leftover is last-round, not concat).
    2. After a 1:1 assistant match (worker preamble before tools, or interleaved mid-round p.text === n.text), trailing leftover cover must be equal-only, not endsWith. Host concat with no pre-tool assistant row keeps assistantCovers (equal / prior.endsWith(last-round)). Worker exact persist retry (leftover === last-round) stays no-append.
    3. Tests: helper + seam — (a) same-user different preamble + last-round 'OK' / 'Done' vs leftover 'All tests passed. OK' / 'OK' / 'Finished. Done' must append; (b) worker 1:1 matching preamble + last-round suffix of leftover must append; (c) worker 1:1 exact retry / empty last-round fold-retry / host concat trailing += / reverse-endsWith / 3e76b50 preamble-suffix + different last-round stay no-append or append as today.
    4. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

Skip-preamble plus last-round-only endsWith swallowed a new same-user
tool-turn whose last-round was a short ack of leftover (OK / Done)
even when the preamble and tools differed. Trailing cover after a
skip requires leftover to cover += of all this-run assistant texts.

After a 1:1 assistant match (worker preamble / interleaved mid),
leftover is last-round not concat — equal-only, not endsWith — so
All tests passed. OK vs OK on a matching preamble appends.

Copy link
Copy Markdown
Owner Author

Follow-up on the adversarial CONCERNS (a153a0a):

  • After skip-preamble (host card), trailing leftover cover is against += of all this-run assistant texts (foldIncomingAssistants / host done.text), not last-round alone. Same-user different preamble + last-round OK / Done vs leftover All tests passed. OK / OK / Finished. Done now appends.
  • After a 1:1 assistant match (worker preamble / interleaved mid), trailing leftover is last-round not concat — equal-only, not endsWith. Worker 1:1 matching preamble + last-round suffix of leftover now appends. Worker exact persist retry and host concat with no pre-tool assistant stay no-append.
  • Tests: helper + seam for both gates. Existing 3e76b50 preamble-suffix + different last-round / empty last-round fold-retry / trailing-concat += / reverse-endsWith stay green.

npm run typecheck green. messageCheckpoint + turnPersistSeam + turnLoop: 121 passed. persist-parse int: 3 passed.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #868

Verdict: CONCERNS
Repo: btipling/invincible
Scope: mainplan/f5-readable-blob @ a153a0a · 10 files · worker transcriptPointer SessionSnapshot + suffix-merge
Lenses run: L1, L2, L5, L6, L8 (skip: L3 no DOM/Wasm chat path — persist stays Vercel worker + Blob, Wasm still never talks to storage; L4 no workflow/artifact change; L7 no host/tenant hardcoding; L9 no UI)
AGENTS.md read: yes (docs/feature-divide.md envelope/Blob row checked; SECURITY.md blob-contents row checked)

a153a0a closed the previous CONCERNS pair (skip-preamble trailing cover is full-fold, not last-round; 1:1 assistant leftover is equal-only). This pass re-attacked HEAD as if those gates were wrong, then executed remaining production checkpoint shapes: 3e76b50 preamble-suffix + different last-round still appends; same-user different preamble + last-round OK/Done still appends; worker 1:1 matching preamble + last-round suffix still appends; empty last-round fold-retry / trailing-concat += / reverse-endsWith / leftover { deltas } / bound miss / envelope-throw unchanged. Remaining hole is that assistantCovers (equal or prior.endsWith) is still used on two paths that same-turn leftover already equals.

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Major L1 flexMatchExact (lib/agent/messageCheckpoint.ts) still calls assistantCovers (equal or prior.endsWith) on (1) skip-preamble trailing cover vs foldIncomingAssistants, (2) no-skip / no-1:1 trailing cover vs last-round, (3) leftover covering-assistant skip. After a153a0a, same-turn leftover is that compared string: host done.text / agentResult.text.trim() and worker fold are both += of nonempty per-round delta.text (empty tool-only rounds are omitted on both sides — if (persistDelta.text) and checkpointToSnapshotMessages drop ''). endsWith is therefore not required for host-concat retry or empty last-round fold retry; it only false-covers a new same-user tool-turn. Reproduced on HEAD: mergeCheckpointOntoPrior([continue, card, 'Let me look at the fileAll tests passed. OK'], checkpointToSnapshotMessages([continue, '', tool, 'OK'])) returns length 3 (turn 2 dropped). Same for worker-to-worker [continue, tool, 'All tests passed. OK'] vs [continue, tool, 'OK'] (no preamble). Same for skip-preamble full-fold suffix: leftover 'Let me edit the fileOK' vs incoming 'edit the file' + 'OK'. Durable tool turn 1, user prompt "continue" (or any retry of the same line), leftover covering assistant ends with 'OK' / 'Done' (concat or last-round). Turn 2, same prompt, generateOneRound tool-only first rounds (text: '' → dropped) then last-round 'OK' / 'Done', different tools. Worker-to-worker / host-409 / carrier-off leaves prior ending on leftover. B8 overlay clock still advances. F5 / other-device shouldAdoptServer adopts turn 1 as the full session. “Host concat with no pre-tool assistant needs endsWith last-round” — that was true when skip-preamble still compared leftover to last-round. After a153a0a, skip-preamble compares leftover to the full fold. Incoming with no preamble means every earlier checkpoint assistant was empty; those rounds are not in done.text either (if (persistDelta.text)), so leftover equals last-round. Worker exact retry leftover equals last-round / fold. “Last-round suffix cover is accepted residual” — that residual was justified by host-concat retry. It is not justified on HEAD. “Existing a153a0a / 3e76b50 rows stay green” — those incoming rows have a nonempty preamble, so they hit fold-cover, not this no-preamble path. high
Minor L6 No helper/seam row for (1) same-user tool-turn with empty first rounds (dropped) and last-round 'OK' / 'Done' vs leftover that ends with that ack, or (2) skip-preamble incoming whose full fold is a suffix of leftover. a153a0a rows all have a nonempty different preamble. Merge this PR. messageCheckpoint / turnPersistSeam stay green while a second "continue" whose model tools first then acks 'OK' hydrates turn 1 only. DI/cost is clean (memory stores). high

Residual risk

Leftover { deltas } first persist is still this-run-only (locked, no backfill). Bound miss/non-JSON and envelope throw stay fail-closed. B7/B8 remain two envelope upserts; concurrent host LWW on B8 still leaves the pointer advanced. Oversize merged JSON still write_failed at 8 MiB. Two consecutive tool-only turns that share a user prompt and an identical last-round (OK vs OK) stay indistinguishable from retry (tool_run is role-equal; equal-only leftover matches). Worker-shaped tool_run text is still the raw result. A future producer that joins per-round text with \\n (not production doneLine / generateOneRound .trim() then +=) would fail equal-only cover and append — not a current producer. Suffix search is O(incoming × prior) on an 8 MiB object — one persist, not a poll loop.

Merge guidance

  • CONCERNS: do not merge until the Major is fixed.
    1. Trailing leftover cover and leftover covering-assistant skip must be equal-only, not prior.endsWith. After skip-preamble, leftover must equal foldIncomingAssistants (the same done.text string). After no-preamble / no 1:1 assistant, leftover must equal last-round. Empty last-round persist retry onto a fold / covering concat stays no-append via leftover === fold. Drop assistantCovers.
    2. Tests: helper + seam — (a) same-user empty first-round + last-round 'OK' / 'Done' vs leftover 'Let me look at the fileAll tests passed. OK' / 'All tests passed. OK' / 'Finished. Done' must append; (b) skip-preamble incoming whose full fold is a suffix of leftover ('edit the file' + 'OK' vs 'Let me edit the fileOK') must append; (c) existing trailing-concat += / empty last-round fold-retry / worker 1:1 exact retry / a153a0a different-preamble / reverse-endsWith stay no-append or append as today.
    3. Leftover { deltas } JSON must stay this-run-only; bound miss/non-JSON must stay {ok:false}.
    4. Living docs (docs/session-model.md) still say host concat with no pre-tool assistant covers by endsWith last-round — that sentence is the hole; replace with equal-only.

What was not attacked

Live DO runner, prod Gateway, Vercel Blob signed GET against Production, real F5 vs Production Redis, Wasm hydrate paint of raw vs encodeToolRun rows, host putEnvelopeOnce vs B8 overlay on a live session, NEXT_PUBLIC_HARNESS_CARRIER_ENVELOPE off (rollforward PUT) as a substitute pointer writer, live 'use step' timeout-retry against Vercel Workflows.

@btipling
btipling merged commit a5ba806 into main Aug 28, 2026
3 checks passed
@btipling
btipling deleted the plan/f5-readable-blob branch August 28, 2026 22:11
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.

plan: F5 readable worker blob — phase 2 — one transcript schema

1 participant