Skip to content

[AGE-4063] test(qa): make continuity a real dimension of the agent release gate - #5697

Merged
mmabrouk merged 2 commits into
release/v0.108.1from
test-/-release-gate-continuity-coverage
Aug 3, 2026
Merged

[AGE-4063] test(qa): make continuity a real dimension of the agent release gate#5697
mmabrouk merged 2 commits into
release/v0.108.1from
test-/-release-gate-continuity-coverage

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Aug 3, 2026

Copy link
Copy Markdown
Member

Context

The Codex subscription bug in #5692 reached a release through a gate that could not have caught it. Three things lined up.

The gate cell labelled "the Codex subscription path" (S1) runs the Pi harness with the openai-codex provider. Pi never loads codex-acp and never assembles a .codex home, so the code that broke had no coverage. The cell that does run the Codex harness (X1) uses a managed vault key, and managed mode is deliberately file-free with no auth.json at all. "Codex harness plus your own login" was a supported, documented configuration with zero gate coverage, in a matrix that read as though it had some.

The pre-merge QA that did cover that configuration was four single-turn checks (docs/design/codex-harness/reports/m4-implementation-notes.md). The failure only appears on turn two.

And the gate's one multi-turn journey (warm) fired three quick turns against a live daemon on a live mount. The working directory is a geesefs mount over S3, and it only makes the round trip through the object store when something unmounts and remounts it. geesefs serves a symlink correctly while the mount is up, so a warm-only journey never takes the trip where the symlink turns into a 0-byte object.

The bug class is bigger than one symlink: an entry inside the durable working directory that the object store cannot represent. It has now bitten symlinks, and it was pre-empted twice before (SQLite write-ahead logging, which is why CODEX_SQLITE_HOME is split onto container-local disk, and hard links).

Changes

Continuity is now a dimension of the gate rather than a single journey, using the tier names the approvals QA already established in reports/warm-approvals-qa.md: warm (same daemon, same live mount), cold 1 (session evicted, runner alive), cold 2 (runner replica replaced). All three run in every cell, so Codex, Claude and Pi are covered across the credential modes that matter.

Each journey is multi-turn over a store-backed working directory, and the transition in the middle is the only difference.

cold1 forces the eviction from the client. Changing the agent's instructions changes the config fingerprint, the runner evicts the pooled session (mismatch (config) ...; evict + cold), and the rebuild unmounts and remounts the durable cwd. That is a real store round trip driven by a real product action (editing an agent mid-session), and it leaves the transcript untouched, so the history guard stays out of it.

cold2 needs the runner replica replaced, which no HTTP client can do, so it takes an operator hook. --cold2-replace-cmd must SIGKILL the replica, never docker stop (on SIGTERM the runner destroys every sandbox it owns, including the session under test), and the driver then waits out the session-owner TTL. The expected result differs per sandbox, exactly as warm-approvals-qa.md worked out: a local sandbox must REFUSE (local sandbox requires a single runner), a remote one resumes cold. It SKIPs loudly without the hook.

The store is a precondition, not a detail. mount.ts degrades silently to an ephemeral directory when the sign call 503s, and every turn still looks fine, so a continuity pass on a storeless deployment would be green and meaningless. The journeys resolve the session's durable mount through GET /api/sessions/mounts/?session_id=... before asserting anything, and SKIP without one, or FAIL with --require-store.

The assertions are store-side, not "turn two replied":

  • Turn 1 writes a token generated by the sandbox's own shell, so it is unguessable and never appears in the transcript. The client then reads it straight out of the object store (GET /api/mounts/{id}/files?read=..., which goes to S3, not to the mount). That proves the cwd is durable and teaches the client the true token.
  • The client writes a second file directly into the store. On the cold tiers the agent must be able to cat it. Content that only ever existed as an object cannot reach the agent unless that turn's cwd really resolves to that store prefix.
  • Results carry the turn ledger's agent_session_id and sandbox_id (POST /api/sessions/turns/query, the only continuity signal a client can see). warm fails if either changed, since a rebuilt session means the turn was not warm.
  • Results also list any 0-byte objects in the durable cwd. That is the store-side fingerprint of this whole bug class, and it is what (bug) Codex subscription auth fails on every turn after the first when the durable cwd is on the object store #5692 left behind.

Every result prints the runner-log grep that settles the tier definitively, because nothing about warm versus cold reaches the SSE stream.

Cells changed:

  • S2 added: the codex harness with runtime_provided credentials. The genuine Codex subscription cell, and the only one that exercises CODEX_HOME pointed at <cwd>/.codex with auth.json symlinked into the durable cwd.
  • X2 added: codex on Daytona. A cold-2 resume can only complete on a remote sandbox (on local it correctly refuses), so without it the gate can never observe a finished codex cold 2. This was verified out of band during the v0.108.0 release run with a one-off probe. It belongs in the gate.
  • S1 relabelled as what it is, Pi on a ChatGPT/Codex subscription provider, with a pointer to S2.

Docs: coverage.md gains the continuity section, the stated cold-2 method, and a table of what each cell needs beyond the three env vars (which cells need a store-backed deployment, which need the subscription sidecar). SKILL.md tells a release conductor about --require-store and the cold-2 hook. The lesson is recorded as #16 in LESSONS.md and as a one-page retrospective in docs/design/codex-harness/reports/durable-cwd-entries-lesson.md.

Folded in from the release run

Cell P2 was corrected during the v0.108.0 release and the fix was never committed. It touches the same file, so splitting it would only create a conflict. Under v0.107.x resolver semantics a named custom connection needs connection mode agenta and a provider-less config, and --custom-slug must send the full <slug>/custom/<model> key (a bare id that also exists in the shared catalog gets its provider inferred first, and the pair check then rejects the run).

Two other corrections described as pending from that release, CLAUDE_CONFIG_DIR with a writable login copy for C1 and the shared runner token for the sidecar, are not present as uncommitted changes in the release worktree. Only the P2 fix and two one-off probe scripts are there, so only P2 is included. The probe scripts are release-night one-offs with a hardcoded vault slug. The X2 cell above is the durable version of one of them.

Tests / notes

  • ruff format and ruff check are clean, and uv run qa_product.py --help works with the cell and journey lists updated.
  • The journey control flow was exercised offline with invoke and api_call stubbed: warm passes on a store-backed deployment and fails when the ledger shows a rebuilt session, both cold tiers pass on a healthy store round trip and fail when the durable file never reaches the store, the storeless case SKIPs and becomes a FAIL under --require-store, and cold 2 SKIPs without the hook, passes on a local refusal, and fails if a local sandbox resumes instead. That stub harness is scratch and is not committed.
  • Nothing here has run against a live stack. That needs a running deployment, provider keys and a subscription sidecar. The next release run is the first real exercise of these journeys. Two numbers to watch there: the store settle window (--store-settle, default 45s, since geesefs uploads on close), and whether the deployment pins AGENTA_RUNNER_REPLICA_ID, which would make a local cold 2 resume instead of refusing.
  • No product code changes. The fix for (bug) Codex subscription auth fails on every turn after the first when the durable cwd is on the object store #5692 ships separately, which is why this references the issue rather than closing it.

Refs #5692

…lease gate

The Codex subscription bug in #5692 shipped through a gate that could not see
it: the only multi-turn journey stayed on the warm daemon, and the cell labelled
"Codex subscription" actually ran the Pi harness with an OpenAI-compatible
subscription provider, so the code that broke had no coverage at all.

Adds warm / cold1 / cold2 journeys (the tier vocabulary from
reports/warm-approvals-qa.md), running in every cell, over a store-backed
durable cwd:

- cold1 forces an eviction from the client by changing the agent's instructions
  (a configFingerprint input), so the runner unmounts and remounts the cwd.
- cold2 replaces the runner replica through an operator hook (SIGKILL + owner
  TTL wait); local sandboxes must refuse, remote ones resume cold.
- The store is a precondition: the journeys resolve the session's durable mount
  over the API and SKIP (FAIL with --require-store) when there is none, so a
  green result can never mean "the store was not in play".
- Evidence is store-side, not prose: the client reads the agent's token straight
  out of the object store and writes a store-only file the agent must read back,
  plus the turn ledger's agent_session_id/sandbox_id and any 0-byte objects in
  the cwd.

Cells: S2 (codex + runtime_provided — the genuine subscription cell), X2 (codex
on daytona, so a completed cold 2 is observable), S1 relabelled as what it is.

Also folds in the QA-infrastructure fix left over from the v0.108.0 release run:
P2 needs connection mode `agenta` plus the full `<slug>/custom/<model>` key
under v0.107.x resolver semantics.

Refs #5692
@linear-code

linear-code Bot commented Aug 3, 2026

Copy link
Copy Markdown

AGE-4063

@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Aug 3, 2026
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 3, 2026 7:13pm

Request Review

@dosubot dosubot Bot added the tests label Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: de82b8da-0241-4224-9d54-feef98f7133a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added warm, cold-start, and runner-replacement continuity checks for durable working directories.
    • Added validation for object-store-backed files, session recovery, and persistence across remounts.
    • Expanded release coverage across authentication methods, subscription flows, and supported agent harnesses.
    • Added controls for requiring storage, waiting for synchronization, and handling unavailable storage.
  • Documentation

    • Documented storage prerequisites, evidence requirements, continuity journeys, and known durability failure modes.
    • Added guidance for detecting unsupported filesystem behavior, including zero-byte persisted files.

Walkthrough

The release gate adds store-backed warm, cold1, and cold2 continuity journeys. It expands Codex coverage, validates durable working-directory state through store-side checks, adds runtime controls, and documents the related failure lesson and operator requirements.

Changes

Durable continuity release gate

Layer / File(s) Summary
Coverage matrix and continuity requirements
.agents/skills/agent-release-gate/resources/coverage.md
The matrix adds Codex cells and defines warm, cold1, and cold2 continuity requirements, evidence, storage, credentials, and replacement hooks.
Continuity journey implementation
.agents/skills/agent-release-gate/resources/qa_product.py
The QA harness verifies durable mounts, store-side files, persisted tokens, ledgers, zero-byte objects, eviction, replica replacement, and storage failure behavior.
Cell and runtime configuration
.agents/skills/agent-release-gate/resources/qa_product.py
The harness adds and corrects test cells, supports query parameters, registers continuity journeys, and adds storage, settling, replacement, and TTL controls.
Operator guidance and regression lesson
.agents/skills/agent-release-gate/SKILL.md, .agents/skills/agent-release-gate/resources/LESSONS.md, .agents/skills/agent-release-gate/resources/seeds/README.md, docs/design/codex-harness/reports/durable-cwd-entries-lesson.md, docs/design/codex-harness/status.md, docs/designs/testing/README.md
Documentation records store enforcement, sidecar requirements, zero-byte symlink failures, continuity evidence, release status, and new canary token patterns.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseGate
  participant DurableMount
  participant ObjectStore
  participant SessionRunner
  ReleaseGate->>DurableMount: Start continuity journey
  DurableMount->>ObjectStore: Persist cwd files and session state
  SessionRunner->>DurableMount: Resume after warm, eviction, or replacement
  ReleaseGate->>ObjectStore: Verify files, tokens, ledgers, and zero-byte objects
Loading

Possibly related issues

  • Issue 5692 — The release gate adds continuity and store-side checks for the durable-cwd symlink failure.

Possibly related PRs

  • Agenta-AI/agenta#5268 — The continuity QA validates durable agent-mount and object-store behavior introduced by this PR.
  • Agenta-AI/agenta#5351 — This PR extends the agent-release-gate harness introduced there.
  • Agenta-AI/agenta#5696 — The continuity checks cover the durable-mount symlink failure addressed by this PR.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly describes the main change: adding continuity as a dimension of the agent release gate.
Description check ✅ Passed The description directly explains the continuity journeys, new cells, store requirements, documentation, tests, and scope.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test-/-release-gate-continuity-coverage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f64b12dc-9601-43cc-8f22-0a00cd80e5a3

📥 Commits

Reviewing files that changed from the base of the PR and between 7e9206e and cc7fe29.

📒 Files selected for processing (8)
  • .agents/skills/agent-release-gate/SKILL.md
  • .agents/skills/agent-release-gate/resources/LESSONS.md
  • .agents/skills/agent-release-gate/resources/coverage.md
  • .agents/skills/agent-release-gate/resources/qa_product.py
  • .agents/skills/agent-release-gate/resources/seeds/README.md
  • docs/design/codex-harness/reports/durable-cwd-entries-lesson.md
  • docs/design/codex-harness/status.md
  • docs/designs/testing/README.md

Comment thread .agents/skills/agent-release-gate/resources/qa_product.py Outdated
Comment thread .agents/skills/agent-release-gate/resources/qa_product.py
Comment thread .agents/skills/agent-release-gate/resources/qa_product.py
@mmabrouk
mmabrouk changed the base branch from main to release/v0.108.1 August 3, 2026 17:09
- Bound the cold2 operator hook (3 min) and wait the owner TTL plus a 20s
  margin. The key lapses at the boundary and the replacement replica may still
  be starting, so a resume timed exactly on the TTL races both and fails for the
  misleading reason this journey exists to avoid. Matches what the
  approval-matrix driver already does.
- An empty turn ledger no longer reads as a stable warm run. `_turn_ledger`
  returns [] on any non-200, and "at most one id" let missing evidence pass as
  evidence. Require exactly one, record `ledger_available`, and say so in the
  failure reason.
- Single-source the local cold-2 refusal text as LOCAL_NOT_OWNER_MARKER, quoted
  in coverage.md and in the journey's own `why`, so the doc and the assertion
  cannot drift. Coerce error entries to str before the substring test.

Refs #5692
@mmabrouk
mmabrouk merged commit 6c820fd into release/v0.108.1 Aug 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant