Skip to content

fix(core): keep build job notices out of the transcript, and close jobs of a chat being deleted - #411

Merged
nickruigrok merged 2 commits into
mainfrom
fix/build-job-notices
Oct 11, 2026
Merged

nickruigrok merged 2 commits into
mainfrom
fix/build-job-notices

Conversation

@nickruigrok

Copy link
Copy Markdown
Contributor

What and why

GRA-443: follow-ups from the post-merge audit of #409 (Code Mode build jobs).

  1. Medium: job notices never left the prompt. A notice that a build job ended was stored as a system message. recentHistory sends every system message and measureTurns subtracts them all, so after a few hundred notices every question failed with agent.question_too_long, and old notices pointed at pruned jobs.
    • Notices now stay the turn's alone. The Workspace DO still queues them for the submitting turn, and Pi carries them in that turn's context.
    • The turn's keep passes over them by content, so they are never written to chat_messages and leave the prompt with their turn.
    • Nothing visible is lost, since the person never sees system messages. A later turn reads how a job ended with env.build.job.
  2. Low: deletion race. deleteChat now cancels the chat's jobs and terminates their instances right after marking the chat deleting, before it awaits connect. admitFromBuildJob also refuses any job of a chat in #deleting. If the delete then fails, the jobs stay cancelled.
  3. Low: "Submit it again" after a commit. A job that broke off now reconciles its receipt first, whether its instance went (failDeadJobs) or finish ran after a step failed for good. It then ends with brokenOff(version): "ended unexpectedly after committing version N, which is proposed for review. Don't propose it again". Only a job that committed nothing is told to submit again. The receipt lookup is shared in the new build-job-receipts.ts.
  4. Revocation scope (decided, recorded on GRA-443 and in build-jobs.ts): any revocation of the agent's permissions still ends a job. A revocation narrows the agent's authority; a job mustn't outlive it on a guess at which grants it rests on, and a job is cheap to submit again.
  5. Nits
    • admitJob's doc now says its own check runs first and last.
    • buildJobInputSchema, admitJob and maxRunningJobs are no longer exported.
    • reconcileReceipt now reads plainly.
    • The submitting run's ID is now recorded in each job call's audit detail.
    • codeRunRetention() stays: workerd exposes every public method of a Durable Object, it returns only counts, and the tests need the object's own private state.

How it was tested

apps/core/test/build-jobs.test.ts now has 21 tests, in workerd against the real engine, DO, model loop and D1.

Changed test

  • Outlives its run: the notice reaches the submitting turn's last request. It is not stored in the transcript, and a later turn's request doesn't carry it.

New tests

  • Chat deleted mid-commit: a propose job is held in its tree write while deleteChat waits on connect. The job ends cancelled and no version is created.
  • Broke off after its commit: the instance is terminated after the commit landed, before its receipt was recorded. job() then reports failed with version: 1 and an error that names the commit, not "Submit it again".
  • DO restart mid-job (test gap): the Workspace object is aborted while the job checks. The job completes with version 1 and no notice is stored.
  • Revocation landing in finish for a check job (test gap): the job ends revoked with no result. Role loss in finish for a check job was already covered.

Mutation checks. Each was applied on its own and reverted:

Mutation Test that fails
Store notices Outlives its run
Remove both deletion guards Chat deleted mid-commit
brokenOff(null) after a commit Broke off after its commit
A wake cancels running jobs DO restart mid-job
No admission in finish Revocation in finish

Removing either deletion guard alone keeps that test green, because the other guard still refuses: the two are deliberate defence in depth.

Regression: build-jobs.test.ts, agent.test.ts, chats.test.ts and agent-builds.test.ts pass: 162 tests, 3 workers. vp check and vp run check:migrations pass.

Checklist

  • vp check and targeted vp test pass
  • Schema changes are expand-only (none)
  • New external calls go through connect; new model calls through the model gateway (none added)
  • No secrets, client names or client configuration

@nickruigrok
nickruigrok marked this pull request as ready for review October 11, 2026 16:37
@nickruigrok

Copy link
Copy Markdown
Contributor Author

@greptileai review

@greptile-apps

greptile-apps Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new blocking issue was found.

Summary

The PR keeps build-job notices out of saved chat messages, cancels jobs before deleting their chat, and checks whether interrupted jobs already committed a version.

  • Build-job notices stay with the turn that submitted them.
  • Deleting a chat cancels its running build jobs right away.
  • Broken-off jobs report versions they committed instead of asking for another submission.
  • Build jobs still stop when an agent permission is revoked.
  • Build-job audit records now name the run that submitted the job.

Reviews (2) · Last reviewed commit: "test(core): wrap and restore connect in ..." · Reviewed by Greptile

Comment thread apps/core/test/build-jobs.test.ts Outdated
@nickruigrok

Copy link
Copy Markdown
Contributor Author

@greptileai review

@nickruigrok
nickruigrok merged commit e39e269 into main Oct 11, 2026
9 checks passed
@nickruigrok
nickruigrok deleted the fix/build-job-notices branch October 11, 2026 16:57
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