Skip to content

Fix open Collie issues: stops hold, gone agents restart, unsettled launches park, and more - #218

Open
madskronborg wants to merge 18 commits into
masterfrom
madskronborg/fix-open-collie-issues-2026-10-26
Open

madskronborg wants to merge 18 commits into
masterfrom
madskronborg/fix-open-collie-issues-2026-10-26

Conversation

@madskronborg

Copy link
Copy Markdown
Collaborator

This branch fixes a batch of open Collie issues, one ticket each. These are its effects:

  • A stop holds: no new step, no filing, and a running check ends with the Run.
  • A gone agent is started again.
  • A launch that cannot tell whether its agent got its work parks instead of failing, and a steer waits for a new agent's first step.
  • A start from a Run's plan directory lands on that Run's Task branch.
  • Reviewers get the spec.
  • A live Run's outcome kind can be changed.
  • A Run's own judgement sees its Outputs, and a sibling's commit is read in the sibling's own checkout.
  • A Run's handoffs directory exists and its Claude agents can write to it.
  • Build prompts name only the work that applies.
  • The Codex stop test holds in either order.
  • Collie's own check is left to CI's test job.

It addresses #159, #160, #161, #162, #163, #164, #166, #167, #172, #174, #176, #196, #199, #203, #204, #205, #206, #207, #210, #211 and #212. None is closed automatically, because several have checks that can only run after the merge (listed below).

The outcome this Run was held to: bug.

Verifications
Passed on the branch as it stands (3469260), run by an agent through Collie's collector: regression, typecheck, lint, format-check and gate-fix-1-suites. check, which Collie ran itself, failed: 4637 tests passed and 1 failed. The failure is "a host that finds its Herd while a Run finishes offers that Run's blocking drift" (test/oversight.test.ts), which also fails at 56d3c96, where this branch leaves the default branch.

This Run is held to one verification:

  • check: /home/mk/.local/share/mise/shims/bun run check (in /home/mk/.herdr/worktrees/.collie/madskronborg/fix-open-collie-issues-2026-10-26)

After the last review
Two gate fixes came after the last review. Each was checked by its own tests and not by a reviewer:

  • Gate fix 1 (3469260): ticket 03 made a start herdr never admits park instead of fail. The nine never-admitted tests in test/codex-stop.test.ts now wait for that park. A stop that lands during such a start used to leave the start's server running, and now stops it when the launch parks as well as when it fails (src/agents.ts).
  • Gate fix 2 changed no code. It re-ran regression in the worktree itself: it failed with ticket 03's sources set back to 6d3d421, then passed on HEAD, so one command now shows both.

Open findings, all non-blocking:

  • [minor] "a resumed Run does not ask again, and waits rather than assuming it holds it" fails here and on the default branch (test/helle.test.ts).
  • [minor] "a host that finds its Herd while a Run finishes offers that Run's blocking drift" fails here and on the default branch (test/oversight.test.ts).

Not settled by the run

  • assumed in 01-a-stop-holds.md: Two tests sit in different files from the ticket: filing is in test/host-issues.test.ts and cleanup is in test/worktree.test.ts, because their fake-forge and worktree-sweep harnesses live only there. The planner (run-ae707bcf-grill-r1) agreed and left the tickets unchanged.
  • assumed in 01-a-stop-holds.md: When a stop ends the host's own check, verify suspends the WorkflowInstance in scope, so inside an Activity the Activity parks and a resume runs it again. Where no instance is in scope (the finish pass), it fails with a WorkflowError naming the stop, which finish already logs as a refusal.
  • assumed in 01-a-stop-holds.md: An agent's verify is ended by a stop whoever started it, not only when the client declared itself as an agent, because a stop ends everything the Run is running. A verify started after the stop is ended within a second.
  • assumed in 01-a-stop-holds.md: On the board, only a running-check record (not the older verifying marker alone) outranks a Run's ending, as the ticket says. When a Run has a record but no marker, as an agent's verify does, its check sentence is built from the record.
  • assumed in 01-a-stop-holds.md: self-improve still records a filing refused by a stop as a cached refused outcome, so a resume does not retry that finding. Step entry stops a new filing step, and the next self-improve Run sees the finding again. Making that loop suspend instead was left out as beyond the ticket.
  • assumed in 02-a-gone-agent-is-relaunched.md: Before starting a gone agent again, Collie closes the pane herdr still lists it in, because real herdr refuses agent_name_taken for a name it still lists. I asked the planner (run-ae707bcf-grill-r1) and it chose this. If the pane does not close, nothing is started and herdr's words are given as the reason.
  • assumed in 02-a-gone-agent-is-relaunched.md: Gone is read from herdr's "not an active named agent" wording, not from the agent_not_ready code. A delivery's refusal reaches agents.ts as text without its code, and that wording only comes with agent_not_ready.
  • assumed in 02-a-gone-agent-is-relaunched.md: The revive asks agent get only about an agent herdr still lists, so an agent it no longer lists costs no extra herdr call. The same predicate also decides gone in steering.
  • assumed in 02-a-gone-agent-is-relaunched.md: The dispatcher's entryFromLive is unchanged. It sees only the listing, and the delivery it feeds now reports an inactive refusal as gone.
  • assumed in 04-a-start-from-a-runs-plan-directory.md: planRunOf now lives in src/strategies.ts beside workSourceOf, and engine, worktree and outcome share it. It cannot stay in engine.ts, because worktree.ts and outcome.ts would then import the engine.
  • assumed in 04-a-start-from-a-runs-plan-directory.md: Branch names were already scoped to Tasks, so a Task branch here means a branch a Run whose lineage includes the plan Run was placed on: the plan Run itself or any Run descended from it. Ancestors are left out. That covers the An implement Run started from another Run's plan directory gets a fresh branch named plan, not that Run's branch #159 case, where the failed Implement now child built the branch.
  • assumed in 04-a-start-from-a-runs-plan-directory.md: Merged or closed is read from the merge watch's recorded states (mr-states, as cleanup reads them), keyed by the merge request a Run on that branch recorded. A branch whose merge request the watch has never seen is taken as open, and Collie asks no forge during placement.
  • assumed in 04-a-start-from-a-runs-plan-directory.md: The Task branch rule comes after the task Input, not before it. A fan-out's repository Runs, and Implement now, carry task and keep their shared branch name. Only a start with no task, as a by-hand start has none, takes the Task's branch, so no Run is handed a branch from another repository.
  • assumed in 04-a-start-from-a-runs-plan-directory.md: The Task branch is taken as a reviewed branch: cut from its remote tip, fetched once if this checkout lacks it, and refused if it is neither local nor on the remote, rather than recreated from the default branch.
  • assumed in 04-a-start-from-a-runs-plan-directory.md: With no Task branch to continue, a Run's own plan directory names the branch after the Run, and the path is never slugged as the work itself. This is the fresh branch the ticket asks for after a merge.
  • assumed in 05-reviewers-get-the-spec.md: A gap a reviewer can move is exactly a missing review verdict: scope_met, behavior_preserved, supported, accurate or compatible. Every other gap (checks, references outside the run, a missing conclusion, tickets_done or reproduced) is one a fresh review cannot change.
  • assumed in 05-reviewers-get-the-spec.md: The SDK gains reviewGapsOf beside checkGapsOf, declared in collie.d.ts and documented in docs/sdk.md, so the workflow asks the outcome module rather than matching gap text.
  • assumed in 05-reviewers-get-the-spec.md: "The outcome table marks which gaps a reviewer can move" is met in code by gapsOf tagging each gap check, review or claim. docs/cli.md gains a sentence after its Outcomes table naming the verdicts a reviewer can move, rather than a new column.
  • assumed in 05-reviewers-get-the-spec.md: specNow is an Activity named spec.N, read before each rally that follows a build and once before the gate's proof Activity, whose fresh review uses it. A plan directory skips the Activity and returns the source itself, as ticketsNow does for non-plan sources.
  • assumed in 05-reviewers-get-the-spec.md: The scenarios write plan/SPEC.md before the Run, as the Linear scenario they copy does, so they show which spec is handed but not when it is read. The read placement is in the code only.
  • assumed in 05-reviewers-get-the-spec.md: When gaps remain but none is reviewable, the Run fails with "Outcome unproved, and no reviewer can change that: …" instead of claiming a fresh review ran.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: Where the kind is stored: in the Intent, as an optional outcome field. Unset means the admitted kind stands, and null means cleared. host.place, a Run's view and its offer facts all lay it over the launch options, so every reader of options.outcome sees the current kind.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: How to clear it: the word unspecified is the CLI and chat spelling, since it is the name Collie already gives a Run with no kind.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: Which kinds are allowed: the host refuses any word outside feature, bug, refactor, investigation, docs and migration with invalid_input. It also refuses a Run whose workflow fixes its own kind, as admission already does. Unlike admission, it does not check a workflow's selectable list.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: No --propagate: set-outcome changes only the Run named, because the kind is a Run's own, and a child keeps its own kind when its parent's Intent propagates.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: Chat goes through the host: chat's update_intent for set-outcome calls the host's changeIntent, so the refusals and the audit are the CLI's. The base_version is checked against the Intent before the call, not under the host's lock.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: Where the kind is read: in an outcome.N Activity before each review round, which also refreshes the round's fix prompt, and before the mr step. Inside the gate's gap Activities and the proof's fresh review it is read directly. Build and criteria prompts for later tickets still show the admitted kind, since the ticket names only the rally, the gate and the merge request.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: Naming the kind in the merge request: the mr prompt asks the description to state the outcome the Run was held to. Its header now carries the current kind, which is what the baseline scenarios assert.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: test/outcome.test.ts: the spec lists it as a seam, but gapsOf's per-kind table did not change, so it got no new test.
  • assumed in 06-the-outcome-kind-can-be-changed-live.md: test/support/hosted.ts: hosted takes an optional module list, so the intent test can save a fixed-outcome fixture beside the defaults.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: How the goal is read: from the first ## Objective, else the first ## Solution, whichever order they appear in. I replaced the Objective state machine with one firstParagraphUnder helper used for both, so a spec whose first Objective is empty no longer falls through to a later Objective.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: How no checkout is detected: git rev-parse --git-dir failing with "not a git repository". The diff's own message cannot be used, because git diff says "Not a git repository" with a capital N in a usage warning.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: A Run with no checkout and no Outputs is skipped with git's words rather than "no change to judge". This keeps the guard test unchanged, and it says why there was no diff.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: judge takes agentsDir and boundary as optional fields. No agentsDir means no Outputs, and no boundary means the finish. This keeps the existing callers and the unchanged guard test compiling. Oversight passes both.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: A boundary skipped for truncated evidence logs to the Run log, records no skipped drift line and writes no new judged.json at. This matches how a mid-Integration boundary is already skipped, so the card does not list a reason the finish will answer.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: outputsIn moved into src/drift.ts unchanged, with the same caps, credential-name redaction and excluded launch files. Its element type is exported as ShownOutput and also replaces oversight's CrossRunOutput.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: The rule check in a directory with no checkout still records skipped, as before. The ticket names only the judgement, so the docs say that a rule check git fails is recorded as skipped.
  • assumed in 07-a-runs-own-judgement-sees-its-outputs.md: workflows/plan.md asks the spec to open with a one-paragraph ## Objective, which each Run takes as its goal. The after-merge check of a real plan Run's intent.json is left to the human, as the ticket says.
  • assumed in 08-a-siblings-commit-is-read-in-its-own-checkout.md: Watched gains cwdOf(id): Effect<string> beside dirOf. It is an Effect because a sibling's checkout comes from its store row, and owed Runs outside the family need one too. The engine resolves it with the same worktree-else-placed-cwd-else-directory rule, now shared as checkoutOf.
  • assumed in 08-a-siblings-commit-is-read-in-its-own-checkout.md: Each cross-run target keeps its checkout, and a report's absolute diff path is resolved against the target's checkout, not the judging Run's. Otherwise a sibling's own absolute path could never be cited.
  • assumed in 08-a-siblings-commit-is-read-in-its-own-checkout.md: The nothing-to-show check runs in standForElection, before the judge is asked and before the no-Herd check. When no target shows a diff file or an Output, it logs cross-run judgement not asked at <when>: no related Run's work can be shown and returns, with no pending, no evaluated line and nothing owed, even for a Run leaving with nobody to pay.
  • assumed in 08-a-siblings-commit-is-read-in-its-own-checkout.md: Because of that, the election test "a Run with relatives stands for the cross-run check, and one leaving unanswered leaves it owed" now gives r2 an Output. That test is about owing a check there is work for, and with no work the ticket says nothing is owed.
  • assumed in 08-a-siblings-commit-is-read-in-its-own-checkout.md: Ticket 04 exported evidenceRoots from src/sdk.ts without declaring it in SDK_DECLARATIONS, so the shipped implement workflow failed engine's toolchain test. I fixed it here in a separate commit rather than leave a known gate failure on the branch.
  • assumed in 09-a-runs-directory-is-usable-by-its-agents.md: host.place now makes <run dir>/handoffs recursively, in place of the Run's directory, under the same condition: only for a Run with a store row. Asking about a Run that was never started still leaves nothing behind.
  • assumed in 09-a-runs-directory-is-usable-by-its-agents.md: The adapter declaration is an optional dirArgs(dir); only Claude declares it, as --add-dir <dir>. The launch passes it the Run's directory as ${host.dir}/runs/<run>, the same form agents.ts already uses for attachments, so agents.ts does not import the engine.
  • assumed in 09-a-runs-directory-is-usable-by-its-agents.md: --add-dir goes after startArgs and before the settings and MCP arguments, so the existing args.slice(0, 2) model checks and startArgs tests stand unchanged.
  • assumed in 09-a-runs-directory-is-usable-by-its-agents.md: docs/internals.md, where a Run's handoffs/ is described, now says the directory is made when the Run is placed and that a Claude agent gets the Run's directory through --add-dir. The live checks after merge (a hand-off note written, a chrome-devtools screenshot saved under the Run directory) are left to the human, as the ticket's After merge section says.
  • assumed in 10-prompts-name-only-the-work-that-applies.md: The ticket puts The implement prompt renders all five work-source kinds and six outcomes and tells the agent to ignore all but one #205's investigation assertions in the existing no-evidence scenario. That scenario fails on this Machine before the branch and must not be touched, so they are in a new scenario of the same shape: text source, outcome investigation. It reads the build prompt once written and stops the Run there.
  • assumed in 10-prompts-name-only-the-work-that-applies.md: The source sections are the five kinds src/inputs.ts has: plan-dir, review, linear, followup and text. The ticket's "GitHub/GitLab issue" is not a work source kind, so there is no section for it.
  • assumed in 10-prompts-name-only-the-work-that-applies.md: A Run with no outcome kind, or one with no section (unspecified), gets ## outcome.unspecified: "No outcome kind is given, so only the checks have to pass." The sentence is a section in implement.md, beside the others, so a user layer can override it like them.
  • assumed in 10-prompts-name-only-the-work-that-applies.md: Moved text keeps {{inputs.plan}} and {{run.dir}}. The workflow's sectionOf fills them when it selects a section, as plan.workflow.ts does for attendance, because the template renders in one pass.
  • assumed in 10-prompts-name-only-the-work-that-applies.md: "Where a ticket's Checks: line names one of this run's checks above, it is not a command for you to run: the gate proves it on the final tree" moved out of the Linear and text sections into the shared build text. Every source's tickets can carry such a line, and plan-directory builds would otherwise have lost it (the blocking-build-finding scenario guards it).
  • assumed in 10-prompts-name-only-the-work-that-applies.md: The build is still told the outcome kind as it was at start (input.inputs.outcome), as before this ticket. Re-reading it live for the build (ticket 06's kindNow) is out of this ticket's scope.
  • assumed in 10-prompts-name-only-the-work-that-applies.md: Desktop's prompt gets one sentence, beside the AskUserQuestion rule it qualifies. A second sentence under the DESKTOP_SAID paragraph would only repeat it.
  • assumed in 11-the-codex-stop-test-holds-in-any-order.md: The two orders are a test.each([1, 2]) of the one scenario rather than two hand-written tests, so the assertion is the same code in both orders.
  • assumed in 11-the-codex-stop-test-holds-in-any-order.md: The drain is taken at once when the SIGTERM comes after the count is already reached, so a server that read its signal late never stays undrained.
  • assumed in 11-the-codex-stop-test-holds-in-any-order.md: Interrupts and the stand-in's started turns are decoded as { threadId, turnId } before they are compared, because lint refuses a sort over unparsed unknown values.
  • assumed in 11-the-codex-stop-test-holds-in-any-order.md: The falsifiability variants edit the stand-in's record, not Collie, because the product must not change. They are kept as diffs in the Run's handoffs rather than committed, as stand-in options that only exist to break the test.
  • assumed in 12-collies-check-is-left-to-ci.md: The test sits in test/ci-workflow.test.ts, which already parses ci.yml. It reads the job named by the resolved check's ci field, so the tie holds in both directions.
  • assumed in 12-collies-check-is-left-to-ci.md: The Release scenarios run on GitHub only, Collie's own forge. They sit just before the per-forge Release scenarios rather than beside the implement CI scenarios, because the Release helpers they use (releasable, driven, releaseHost) are defined there.
  • assumed in 12-collies-check-is-left-to-ci.md: A red or missing job cannot park a Release directly: the Release first runs a fix round on it. The scenarios queue one fix that changes nothing, so the Run parks after that round, which is how the shipped Release behaves.
  • assumed in 12-collies-check-is-left-to-ci.md: This Run's own checks were frozen at its start without ci, so its gate still runs bun run check locally. I did not amend the Run's verification, which the ticket did not ask for. The merge request's test job proves the check for later Runs.
  • assumed in 12-collies-check-is-left-to-ci.md: D5 now reads "Collie's Checks passed at its head, a Check left to CI by its pipeline job there, and so did the forge's pipeline". Each doc gets one sentence: cli.md beside the ci example, workflows.md in the Release section's Checks paragraph.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: A steer waits only for a new agent's first work. A reattached agent releases the latch at once: test/agents.test.ts holds that a steer reaches a reused agent while its boundary waits for its turn to end, and A steer sent to a just-launched agent before its step makes the step fail with an empty reason #162 is about a just-launched agent.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: The latch is in-process: a map from agent name to a Deferred, released when the launch ends however it ends. The host is the only actor over a Run's agents (ADR-0029), so a steer and the launch it waits for run in the same process.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: Ledger contention in the patient submit is bounded by the same patience as agent_blocked, ten minutes from the first contention. It then returns exhausted, which parks like a pane that stayed busy. That bound has no test of its own.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: The already-open case is its own TransactionOpen error, not DispatcherDefect, because it is now an expected, transient condition. DispatcherDefect keeps only the channel-used-after-close case.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: The empty-reason fallback is in undeliverable, the delivery refusal the ticket names, rather than in the shared reason() every caller uses.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: A pane that would not close before a gone agent was started again (ticket 02) still fails as AgentUncertain: the ticket names only the start, listing and never-sent sites.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: The parked reason names the prompt file even when the start failed before the file was written: it is where the work will be when a resume starts the agent.
  • assumed in 03-a-start-that-never-got-its-work-parks.md: The verify-told fix narrows the test to undotted step sections instead of repeating the line in each spliced fragment, which would print it twice in a build prompt. It is its own commit because it fixes ticket 10's change.
  • 01-a-stop-holds.md: after merge: On vm-mk, stop a Run while an agent's collie verify is running: its processes are gone within the stop's grace period.
  • 01-a-stop-holds.md: after merge: On vm-mk, stop a Run while its check is running. Its bun processes are gone within the stop's grace period, and its worktree survives a cleanup. Resume finishes the check (Stopped merged Run leaves background recheck running; cleanup deletes its live worktree #211).
  • 01-a-stop-holds.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: Collie's gate runs check on the final tree after review; per the step I did not run the whole suite. Its parts I could run passed through collie verify: typecheck, lint (0 errors; the 112 warnings were there before this branch), format-check, and touched-suites.
  • 02-a-gone-agent-is-relaunched.md: after merge: On a Machine, kill the herdr session hosting a Run's agent, then run stop and run resume the Run. The agent is started again and the Run carries on (A Run whose agent died with its Machine stays running, and resume does not start the agent again #160).
  • 02-a-gone-agent-is-relaunched.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: Collie's gate runs check on the final tree after review. Per the step, I did not run the whole suite. These parts of it passed through collie verify on 293f6a7: typecheck, format-check, touched-suites (350 pass, 0 fail across 12 files), and lint (0 errors; its 112 warnings predate this branch). lint ran on the working tree before the commit.
  • 04-a-start-from-a-runs-plan-directory.md: after merge: An implement started by hand from a finished plan Run's plan/ directory opens its merge request from that plan Run's Task branch, not from plan (An implement Run started from another Run's plan directory gets a fresh branch named plan, not that Run's branch #159).
  • 04-a-start-from-a-runs-plan-directory.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: Collie's gate runs check on the final tree; per the step I did not run the whole suite. It will hit one baseline scenario that already fails on the release base 56d3c96 (see findings). touched-suites ran 601 tests across 8 files: 600 passed, and that pre-existing scenario failed. typecheck, lint (0 errors, the 112 warnings predate the branch) and format-check passed.
  • 05-reviewers-get-the-spec.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: per the step I did not run the whole suite; the gate runs check, and with ticket 12 on the branch it is left to CI's test job. Locally, touched-suites (outcome, outcome-records, sdk, implement-content, baseline, baseline-unrelated) had 747 pass and 2 fail. Both failures are the pre-existing, machine-local no-evidence timeout in findings.
  • 06-the-outcome-kind-can-be-changed-live.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: per the step I did not run the whole suite, and with ticket 12 on the branch the gate leaves check to CI's test job. Locally, touched-suites covered intent, tools, chat-parity, proposals, evaluator, steer, collie-cli, remote-cli, credentials, outcome, sdk, implement-content, lifecycle, baseline and baseline-unrelated. 943 passed and 1 failed. The failure is the pre-existing, machine-local no-evidence scenario in findings.
  • 07-a-runs-own-judgement-sees-its-outputs.md: after merge: A plan Run's implement child, started from its plan/ directory, has the spec's Objective as the goal in its intent.json, and its card's record shows it (A Run reports aligned: true — every constraint was checked when nothing was judged #164).
  • 07-a-runs-own-judgement-sees-its-outputs.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: per the step I did not run the whole suite. The gate runs check, and with ticket 12 on the branch it leaves it to CI's test job. Locally, on cf6a5cb's tree:
  • touched-suites passed: 314 tests across intent, drift, oversight, correction, live, plan-repos, implement-content and agents.
  • baseline passed 694 of 696. The 2 failures are the pre-existing, machine-local scenario in findings.
  • 08-a-siblings-commit-is-read-in-its-own-checkout.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: per the step, I did not run the whole suite; the gate runs check. Locally, on the final tree:
  • touched-suites passed 160 of 160 (oversight, engine, cards, correction, placement, drift).
  • engine's toolchain test failed until I declared evidenceRoots, which ticket 04 exported from the SDK but did not declare for authors. That fix is its own commit.
  • cross-run-neighbours had one failure, a timeout that predates the branch (see findings).
  • 09-a-runs-directory-is-usable-by-its-agents.md: after merge: A Claude agent of a Run on the merged build writes a hand-off note into <run dir>/handoffs/ (Prompts send agents to a handoffs/ directory Collie never creates #203).
  • 09-a-runs-directory-is-usable-by-its-agents.md: after merge: The same agent saves a chrome-devtools screenshot under its Run directory (chrome-devtools refuses screenshots under the Run's handoffs/, outside the agent's roots #204). Record this live result in the merge request.
  • 09-a-runs-directory-is-usable-by-its-agents.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: per the step, I did not run the whole suite; the gate runs check. Locally:
  • touched-suites (agents, harness, handoffs, run-detail) passed 219 of 219.
  • run-dir-neighbours (the cleanup, host, lifecycle, only-writer, run-detail and worktree suites) passed 230 of 231. The one failure is the timeout that predates the branch, in findings.
  • 10-prompts-name-only-the-work-that-applies.md: after merge: A plan Run given a design URL leaves a copy under its plan/design/, and its tickets name that copy (Implementers re-read a design artifact at the 50k cap when the plan already saved a local copy #206).
  • 10-prompts-name-only-the-work-that-applies.md: after merge: A proactive Desktop turn that needs a decision asks it in its reply, with no NO_HUMAN denial in its transcript (Desktop calls AskUserQuestion in turns it started itself and gets bounced every session #207).
  • 10-prompts-name-only-the-work-that-applies.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: per the step, I did not run the whole suite; the gate runs check. baseline (test/baseline.test.ts) at d557148 passed 346 of 347. The one failure is the no-evidence scenario that predates the branch, in findings. touched-suites, typecheck, lint and format-check pass.
  • 11-the-codex-stop-test-holds-in-any-order.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: the gate runs check on the final tree; per the step, I did not run the whole suite. This ticket changes only test/codex-stop.test.ts and its stand-in. codex-stop, typecheck, lint (0 errors) and format-check pass on 6cd1ed3's tree.
  • 12-collies-check-is-left-to-ci.md: after merge: CI's test job is green on the merge request's head, and the gate recorded that as the check's proof.
  • 12-collies-check-is-left-to-ci.md: after merge: The next Release of Collie asks for its go once CI's test job is green at the head, with no local bun run check in its record.
  • 12-collies-check-is-left-to-ci.md: after merge: The next implement Run on Collie waits for the test job after opening its merge request instead of running the suite locally.
  • 12-collies-check-is-left-to-ci.md: The full check passes (guard). bun run check passes on the branch's final tree. It passed on origin/master e53cd71 through collie verify (see handoffs/base-check-e53cd719.log), and in CI run 40305594214. — after merge: the gate runs check on the final tree, and I do not run the whole suite.
  • This Run's own check was frozen at start, without ci, so this Run's gate still runs bun run check locally. The merge request's test job proves it for the Runs that start after the merge.
  • Passing on 6d3d421's tree: typecheck, lint, format-check, touched-suites (ci-workflow, verify-spec, ci-job: 28 pass), ci-gate-guards and regression.
  • docs-guards failed only on the collie-cli timeouts in findings.
  • 03-a-start-that-never-got-its-work-parks.md: The full check passes (guard). The gate runs the check Check (bun run check) on the final tree, and it passes. It passed on origin/master e53cd71 through collie verify: see handoffs/base-check-e53cd719.log. — after merge: the gate runs check on the final tree, and I do not run the whole suite. On this tree the following pass:
  • touched-suites (agents, resume, dispatcher, step-ahead): 224 pass;
  • regression;
  • typecheck, lint (0 errors) and format-check;
  • verify-told.
    steer-neighbours ran 12 files that steer or deliver (attachments, agent-origin, chat-parity, evaluator, steering-caps, report, finished-steer, host-issues, verify-memory, only-writer, verify-told, live). It had 98 pass and 1 fail: verify-told, which also failed at HEAD and is fixed in 8f69c72 (see findings).
  • check: a host that finds its Herd while a Run finishes offers that Run's blocking drift (test/oversight.test.ts) also fails at 56d3c96, where this branch leaves the default branch, so it failed before this Run's changes.

Mads Kronborg added 18 commits October 26, 2026 13:33
…th the Run

A stopped Run carried on after a host restart and filed an issue (#176),
and a check it was running outlived the stop, dropped off the board and
lost its worktree to cleanup (#211). STOP was honoured only at agent
launch and collection and in the memory and CI waits.

Step entry now suspends on a stop as it does on a hold. The host refuses
to file or comment on an issue for a stopped Run. The host's own check
and an agent's collie verify race STOP and end their process group: the
host's check parks the Run so a resume runs it again, and the agent is
refused with a reason naming the stop. A live running-check record keeps
the card working and the worktree out of cleanup.
…gain

herdr keeps listing an agent whose process died with its Machine and refuses it
as not active. Collie counted an agent gone only when herdr stopped listing it,
so the step failed undelivered, a revive waited on a dead agent, and resume said
the Run was already running (#160). One predicate now decides gone for delivery,
relaunch, revive and steering; the dead agent's pane is closed first, because
herdr keeps a name while it lists it. A startup block is no longer read from
every agent_not_ready, only from herdr's own wording.
…and take its files as evidence

A start given <state>/runs/<id>/plan by hand was put on a branch named
plan, cut from the default branch, and its gate refused the plan Run's
handoffs as outside every root (#159, #174). One shared predicate now
recognises a Run's own plan directory: branch naming never slugs it,
placement continues the branch that Run's lineage was placed on unless
its merge request has merged or closed, and the gate counts that Run's
directory as evidence.
…nly where a reviewer can move a gap

A typed, Linear or follow-up source's build writes plan/SPEC.md, yet reviewers were told
there was none. Evidence outside every root, or a check that has not passed, is no
reviewer's to change, so a fresh gate review over it bought nothing.
… gate and merge request to the current one

A Run admitted with the wrong kind looped on gaps it could never close: its gate kept asking
a misclassified migration for migrate-up/down, and its reviewers a misclassified refactor for
behavior_preserved (#172). set-outcome is an Intent change every door can make, and the
implement workflow now reads the kind in an Activity at each review round, gate pass and the
merge request instead of once at admission. The plan prompt says what each kind obliges.
… the cap once at the finish, and take a plan's goal from its Solution

A Run whose work is only its Outputs could never be judged aligned, a branch past the
evidence cap paid for the same truncated judgement at every boundary, and every Run
started from a Collie plan had no goal because the planner never wrote an Objective.
…typechecks against the declarations it is held to
…agent its Run's directory, so notes and MCP output land where the prompts ask
…ep a plan's design artifact as a local copy, and have Desktop's chat ask in its reply when nobody can click
… once, so the test holds whichever order the server takes its drain in

A loaded server can take its SIGTERM after a second interrupt, start a
further continuation, and have the stop interrupt that too; that is
correct under ADR-0059, so the stand-in's lateDrain now holds the drain
back by a count to make that order on demand.
…ent gates stop running the whole suite again on a head CI already proves

The check came only from the checks remembered for the remote, with no
ci field, so nothing told the gate or a Release that CI's test job runs
the same bun run check. The committed .collie/verify.json says so and
wins over the remembered checks; a test ties it to ci.yml so renaming
either side breaks it.
…rk, and hold a steer until a new agent's step has gone out

A timed-out start, an unanswered agent listing or a step prompt that did not go out failed the Run, which resume refuses, though a resume lists herdr's agents again and can take up or start the agent. A steer that reached a just-launched agent first held its ledger, and the step's submission failed on that contention with an empty reason. Ledger contention is now waited out like a busy pane, and a refusal with no message says the error's tag and fields.
…rce and outcome sections spliced into them

Splitting the build prompt's source and outcome instructions into sections of their own left fragments that mention collie verify without the line, which the build step they are spliced into already carries.
… so two edits made on the same version cannot both apply
…when it failed, and have the never-admitted tests wait for that park
@madskronborg madskronborg self-assigned this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant