Skip to content

regressions: red/green flows for the 2026-08-27 platform bugs (dormant until gates 2+6) - #5

Merged
khaliqgant merged 1 commit into
mainfrom
flows/regression-suite
Aug 27, 2026
Merged

regressions: red/green flows for the 2026-08-27 platform bugs (dormant until gates 2+6)#5
khaliqgant merged 1 commit into
mainfrom
flows/regression-suite

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

Four platform bugs were found on 2026-08-27, during the first dogfood runs. This
PR writes each of them down as a pair of executable flows in the v2 dialect,
so they stop being prose in a report and start being something a machine re-runs.

The method: red, then green

  • <slug>.red.flow.ts reproduces the failure. Its gates assert the broken
    behaviour, so it passes while the bug is present. This is the bug report.
  • <slug>.green.flow.ts asserts the corrected behaviour. It fails while
    the bug is present
    and passes once it is fixed. This is the acceptance test.

A bug is closed only when its red case starts failing and its green case starts
passing, in the same run. Either half alone can lie — a green test that never ran
red proves nothing about the bug it claims to cover.

The four bugs

slug bug evidence
enrollment-token-bearer-auth Minting an enrollment token gates on requireSessionAuth, so a valid CLI bearer is answered 403. Worker enrollment has no headless, self-host, or CI path. cloud packages/web/app/api/v1/workers/enrollment-tokens/route.ts:113-115; {"error":"Forbidden"} (403). Tracked as cloud#3202.
worker-daemon-bun-argv agent-relay cloud worker start --daemon re-execs the bun-compiled binary passing process.argv[1], which under bun build --compile is the virtual /$bunfs/root/agent-relay-darwin-arm64. The child dies immediately; the parent has already printed success. relay packages/cli/src/cli/commands/cloud-worker.ts:266 (process.argv[1] ?? 'agent-relay'), :279 (spawn process.execPath), :396 (Cloud worker daemon started: <pid>); error: unknown command '/$bunfs/root/agent-relay-darwin-arm64'.
cron-succeeded-into-void RelayCron marks a fired schedule lastTriggerStatus: "succeeded" as soon as the launch POST returns a runId — even with no worker to claim it. A schedule can be silently zero forever. cloud packages/web/app/api/v1/workflows/schedules/trigger/route.ts:178-192; observed twice on schedule flows-drive: runs 8e3e5916 and 740c3a27, both succeeded, nothing executed, no branch, no PR.
cross-account-workspace-404 Two accounts each own a workspace named "Default". Asking for the other one answers 404 with no code and no user-facing message, and the client maps every non-ok response to one string — so a wrong account reads as a role problem and the user retries with permissions they already have. cloud .../enrollment-tokens/route.ts:29-32 (404 {"error":"Workspace not found"}), cloud packages/web/components/workers/NewWorkerForm.tsx:91-92; workspaces 50587328-441d-4acb-b8f3-dbe1b3c5de99 (khaliq@agentrelay.com) vs 0fb35c2e-861f-4d44-848e-fa3f5a3e192e (khaliqgant@gmail.com).

Two of these are covenant violations rather than mere defects.
cron-succeeded-into-void is covenant 2 verbatim — "a 'succeeded' that did
nothing is by definition a kernel bug"
— and worker-daemon-bun-argv is the
same shape at the CLI: a reported pid for a process that is already gone.
cross-account-workspace-404 is covenant 1: the error names the wrong condition
in the user's vocabulary.

This suite does not run yet — and must not

No flow here declares an on() trigger, none is deployed, no schedule is
registered, and nothing outside regressions/ references the directory except a
single backlog line. Typechecking is opt-in
(cd sdk && npx tsc -p ../regressions/tsconfig.json) and is deliberately not part
of npm test — which still passes, 54/54, unchanged.

The flows target @relayflows/surface, the v2 authoring surface, which does not
exist yet. regressions/surface.d.ts is a declaration-only slice of it carrying
exactly the shapes these four pairs need, so it doubles as a requirements list
for gate-1 SDK work; delete it when the real surface ships.

Which gates unblock each pair (machine-readable in regressions/MANIFEST.json):

slug required gates why
enrollment-token-bearer-auth 1, 6, 8 kernel; a relayfile adapter for AgentWorkforce cloud; scoped per-principal credentials
worker-daemon-bun-argv 1, 6, 7 kernel; cloud liveness reads; a darwin-arm64 sandbox profile — the bug is invisible under node or bun run
cron-succeeded-into-void 1, 2, 6 kernel; the trigger plane and its executor-liveness check; schedule/journal helpers
cross-account-workspace-404 1, 6, 8 kernel; cloud adapter; three principals in one run

cron-succeeded-into-void.green and worker-daemon-bun-argv additionally depend
on cloud#3202 being fixed, since both need to enrol a worker headlessly.

What the dialect cannot say yet

Named in regressions/README.md rather than worked around silently:

  1. No declared-failure assertion. A red case needs "this fails, in this
    declared way". The surface has .gate(), which causes a typed failure, but
    nothing that asserts one. Every red probe is therefore a deterministic step
    that always exits 0 and prints <body>\n<status> for a postfix gate to judge.
    The shape it wants is a first-class negative gate — gate-1 verification work.
  2. No browser helper, so "the UI shows this string" is not assertable. The
    cross-account pair asserts the API-level cause instead, and its green case
    moves the user-facing message to the API, where the condition is known.
  3. No macOS placement in the sandbox router (gate 7).
  4. Multi-principal runs are declarative only — expressed as
    principals/<name>/token mount reads plus an as: argument, pending gate 8.

Adoption

Once flows run in cloud, the Software Garden should adopt this suite: run each
red case expecting a pass (the standing proof the bug is still open) and each
green case expecting a fail, and flip the pair to green-only when the fix lands.
MANIFEST.json carries the gates, blockedUntil notes, and dependsOn edges so
that pickup can be automatic.

🤖 Generated with Claude Code

Four bugs found during the first dogfood runs, each written twice in the
flows v2 dialect: a red case that passes while the bug is present (the
executable bug report) and a green case that fails until it is fixed (the
acceptance test). A bug is closed when red starts failing and green starts
passing in the same run.

  enrollment-token-bearer-auth   mint gates on requireSessionAuth, so a CLI
                                 bearer gets 403 and enrollment has no
                                 headless path (cloud#3202)
  worker-daemon-bun-argv         --daemon re-execs with a $bunfs argv; the
                                 daemon dies while the CLI reports a pid
  cron-succeeded-into-void       a schedule reports succeeded with no worker
                                 to execute it (covenant 2)
  cross-account-workspace-404    a not-found workspace is rendered to the
                                 user as a permissions problem (covenant 1)

The suite is DORMANT: no on() trigger, no schedule, no deploy, nothing in a
drive loop or CI. It targets @relayflows/surface, which does not exist yet;
surface.d.ts is a declaration-only slice of the v2 surface carrying exactly
what these pairs need, so it doubles as a requirements list for gate-1 SDK
work. Typechecking is opt-in (regressions/tsconfig.json), not part of
`npm test`. MANIFEST.json records the gates each pair waits on so the Garden
can adopt them automatically once flows run in cloud. README names the four
things the dialect cannot yet say, rather than working around them silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 17 minutes.

View limit details

Limit details: You’ve used the included review currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: e546a0f5-d675-4ec9-a28b-cec313e516cd

📥 Commits

Reviewing files that changed from the base of the PR and between f59e279 and 50c317a.

📒 Files selected for processing (14)
  • ops/BACKLOG.md
  • regressions/MANIFEST.json
  • regressions/README.md
  • regressions/cron-succeeded-into-void.green.flow.ts
  • regressions/cron-succeeded-into-void.red.flow.ts
  • regressions/cross-account-workspace-404.green.flow.ts
  • regressions/cross-account-workspace-404.red.flow.ts
  • regressions/enrollment-token-bearer-auth.green.flow.ts
  • regressions/enrollment-token-bearer-auth.red.flow.ts
  • regressions/probe.ts
  • regressions/surface.d.ts
  • regressions/tsconfig.json
  • regressions/worker-daemon-bun-argv.green.flow.ts
  • regressions/worker-daemon-bun-argv.red.flow.ts

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/settings/billing.

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

@khaliqgant

Copy link
Copy Markdown
Member Author

Upstream tracking: AgentWorkforce/cloud#3202 covers three of the four bugs here (bearer-auth enrollment, cross-account 404 messaging, cron-succeeded-into-void). The worker-daemon-bun-argv pair is a CLI-side bug (relay cloud-worker.ts:266/:279) and needs its own issue.

Note the dependency edge already in MANIFEST.json: cron-succeeded-into-void.green and both worker-daemon-bun-argv flows require headless worker enrolment, so they cannot go green until cloud#3202 ships.

@khaliqgant
khaliqgant marked this pull request as ready for review August 27, 2026 18:09
@khaliqgant
khaliqgant merged commit e0d65f1 into main Aug 27, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the flows/regression-suite branch August 27, 2026 18:09

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 50c317a079

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread regressions/probe.ts
`-X ${input.method}`,
`"$(cat ${CLOUD_MOUNT}/base_url)${input.path}"`,
`-H "Authorization: Bearer $(cat ${CLOUD_MOUNT}/principals/${input.principal}/token)"`,
"-H 'Content-Type: application/json'",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Send browser-session credentials as cookies

When the enrollment and cross-account flows select browser-session or browser-session-member, this helper still sends the credential through Authorization: Bearer. The endpoint under test explicitly distinguishes session auth via requireSessionAuth, so these requests exercise bearer auth as well: the enrollment control receives the same 403 as the CLI case, and the cross-account cases never reach the workspace lookup. Emit the authentication mechanism appropriate to each principal rather than treating every mounted credential as a bearer token.

Useful? React with 👍 / 👎.

// The durable half: local liveness is not enough, cloud has to see it.
// `awaitHeartbeat` compiles to a kernel wait, so this parks rather than polls.
await f.cloud.workers
.awaitHeartbeat({ workerId: "regression-daemon", as: "cli-bearer", within: "90s" })

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Query the worker ID actually started by the daemon

On any sandbox whose registered worker ID is not literally regression-daemon, this waits on an unrelated or nonexistent worker even if the daemon fix is correct. The flow neither registers a worker nor captures an ID before cloud worker start, while registration elsewhere returns a server-generated workerId; therefore this gate cannot establish that the process started above heartbeated. Capture the active worker's ID from registration or the local daemon record and pass that value here.

Useful? React with 👍 / 👎.

` --token-file ${enrolment.tokenPath} --name regression-cron-worker --json` +
" && agent-relay cloud worker start --daemon",
)
.gate((out) => out.includes("daemon started"), "an executor now exists");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wait for the executor heartbeat before firing the schedule

When daemon startup returns before its first cloud heartbeat, this gate only proves that the CLI printed a success line, not that an eligible executor exists; the immediately following fire can consequently report no_executor on a fully fixed platform. This is especially relevant because the adjacent daemon regression is explicitly about the success message preceding real liveness. Wait for the newly registered worker to become online before triggering phase 2.

Useful? React with 👍 / 👎.

"every step carrying a completionReason (AGENTS.md rule 4)",
);

await f.cloud.schedules.remove({ scheduleId: schedule.id, as: "cli-bearer" });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clean up schedules after expected gate failures

This cleanup is reached only when every preceding gate passes, but the documented red/green protocol deliberately expects one twin to fail in either platform state. While the bug is open, the green flow stops at the no_executor assertion; after the fix, the red twin stops at its succeeded assertion, leaving their fixed-name disposable schedules behind on every suite run. Subsequent creates can conflict, and leaked schedules can later fire; arrange cleanup in a failure-safe finalizer or use a lifecycle that removes the schedule even when a gate fails.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant