fix(dev-base): stop one transient payload failure costing the release (#987) #1187

Merged
coilyco-ops merged 6 commits from aos/987-dev-base-retry into main 2026-08-22 22:36:26 +00:00
Member

Closes #987.

publish-full declares needs: [plan-draft, publish-language-payloads], so a matrix with fail-fast: false still skipped the full image and the entire release when one payload failed. Recovery was a manual dispatch rebuilding all five payloads: ~30 minutes of runner time for one job that failed in four.

Bounded retry

Each payload now gets one retry. Attempt one carries continue-on-error so a transient does not fail the job; the retry carries none, so a real defect still fails loudly and still reaches the Telegram alert. Never a third: that turns a defect into a slow failure.

This asserts no new safety property. The action already documented promotion as its final step, "which is what makes the job safe to retry", and its checkpoint step skips a payload that already landed. The issue's own words: "Nothing acts on that." Now something does, and the retry contract lives in the action's description, next to the property it depends on.

apt-get retries

Every curl in the dev-base Dockerfile retried and apt-get did not, which the issue names as the leading candidate cause.

write-arch-env.sh already ran first in all five language stages, which is exactly where the config has to land, so it grows Acquire::Retries and the now-accurate name prepare-build-stage.sh rather than five copies of the same line drifting apart - the failure mode #1062 just finished cleaning up elsewhere in this repo.

Coverage

  • Two attempts and no more, and the retry has no continue-on-error of its own.
  • prepare-build-stage.sh runs before apt-get update in every language stage.
  • The existing shape assertions updated for the third publish-dev-base use.

615 tests pass, pre-commit run --all-files passes including actionlint and the Forgejo Actions validator.

Not closed by this

The root cause stays unconfirmed, because run logs remain unreachable on this Forgejo (the issue's item 3, and its own stated blocker). This narrows the blast radius from the release to one job and removes one candidate; it does not identify what failed.

Closes #987. `publish-full` declares `needs: [plan-draft, publish-language-payloads]`, so a matrix with `fail-fast: false` still skipped the full image and the entire release when one payload failed. Recovery was a manual dispatch rebuilding all five payloads: ~30 minutes of runner time for one job that failed in four. ## Bounded retry Each payload now gets one retry. Attempt one carries `continue-on-error` so a transient does not fail the job; the retry carries none, so a real defect still fails loudly and still reaches the Telegram alert. Never a third: that turns a defect into a slow failure. This asserts no new safety property. The action already documented promotion as its final step, *"which is what makes the job safe to retry"*, and its checkpoint step skips a payload that already landed. The issue's own words: *"Nothing acts on that."* Now something does, and the retry contract lives in the action's description, next to the property it depends on. ## apt-get retries Every `curl` in the dev-base Dockerfile retried and `apt-get` did not, which the issue names as the leading candidate cause. `write-arch-env.sh` already ran first in all five language stages, which is exactly where the config has to land, so it grows `Acquire::Retries` and the now-accurate name `prepare-build-stage.sh` rather than five copies of the same line drifting apart - the failure mode #1062 just finished cleaning up elsewhere in this repo. ## Coverage * Two attempts and no more, and the retry has no `continue-on-error` of its own. * `prepare-build-stage.sh` runs before `apt-get update` in every language stage. * The existing shape assertions updated for the third `publish-dev-base` use. 615 tests pass, `pre-commit run --all-files` passes including actionlint and the Forgejo Actions validator. ## Not closed by this The root cause stays unconfirmed, because run logs remain unreachable on this Forgejo (the issue's item 3, and its own stated blocker). This narrows the blast radius from the release to one job and removes one candidate; it does not identify what failed.
fix(dev-base): stop one transient payload failure costing the release (#987)
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 6s
ci / ward-doctor (pull_request) Successful in 14s
ci / aos-cli-tests (pull_request) Successful in 23s
ci / gate (pull_request) Successful in 59s
dev-base-pr / build (pull_request) Successful in 13m25s
3e453e3f1a
publish-full declares `needs: [plan-draft, publish-language-payloads]`, so a
matrix with fail-fast disabled still skipped the full image and the entire
release when one payload failed. Recovery was a manual dispatch that rebuilt
all five payloads: about thirty minutes of runner time for one job that
failed in four.

Each payload now gets one bounded retry. Attempt one carries
continue-on-error so a transient does not fail the job, the retry carries
none so a real defect still fails loudly and still alerts, and there is
never a third: that turns a defect into a slow failure. The action already
documented promotion as its final step, "which is what makes the job safe
to retry", and its checkpoint step skips a payload that already landed, so
nothing here asserts a new safety property. It acts on one already stated
beside it, which is why the contract lives in the action's description.

Every curl in the dev-base Dockerfile retried and apt-get did not, which is
the leading candidate cause in the issue. write-arch-env.sh already ran
first in all five language stages, exactly where the config has to land, so
it grows Acquire::Retries and the accurate name prepare-build-stage.sh
rather than five copies of the same line drifting apart.

The root cause stays unconfirmed: run logs are still unreachable on this
Forgejo, which the issue records as its own blocker.

Closes #987

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: engineer
Author
Member

Two things, and the first one changes what this PR is for.

You opened this a minute after I posted the root cause on #987, so you have not seen it. Short version, with the evidence there.

The logs are reachable, and the cause is not apt

This PR says "run logs remain unreachable on this Forgejo (the issue's item 3, and its own stated blocker)". They are reachable:

$ aosguard ops forgejo action-run logs coilyco-flight-deck agentic-os 16863 > run.zip
122266 bytes, one .log per job

publish-lang-go-26623-attempt-1.log:

#16 exporting to image
#16 pushing layers 14.5s done
#16 ERROR: failed to push forgejo.coilysiren.me/...:lang-go-draft-7547dd34: unknown
#18 ERROR: error writing layer blob: failed to copy: failed to do request: Put ".../blobs/uploads/..."

The Go image built. Every apt step and the go.dev download completed. It died at the registry push, and the image push and cache export failed in the same second, which points server-side.

So the apt half of this PR does not remove a candidate, because the log already excluded it. Acquire::Retries beside the existing curl --retry is defensible on its own merits and I would keep it, and prepare-build-stage.sh consolidating five drifting copies is the right shape. Just do not let #987 close claiming it narrowed this failure. The retry half is what addresses it, and the log makes it better justified than the PR argues: the failure is precisely in the promote step the action documents as safe to retry.

The retry can convert a loud failure into a silent one

- id: payload
  continue-on-error: true
  uses: ./actions/publish-dev-base
- name: Retry the payload once
  if: ${{ steps.payload.outcome == 'failure' }}
  uses: ./actions/publish-dev-base

publish-full still declares needs: [plan-draft, publish-language-payloads] and does not check that any payload exists. It trusts the matrix job's colour.

Before this PR that was safe in the direction that matters: a failed payload failed the job, so the release was skipped. Loud, and the thirty-minute complaint. After it, attempt one's failure is swallowed. If the retry step does not fire, the matrix job is green with nothing published, and publish-full builds on a missing or stale payload.

That is not a hypothetical about this runner. #1032, in this same lane, documents this exact Forgejo instance marking a called workflow success in zero seconds without running its three jobs. A platform that has already been caught misreporting step and job outcomes is the wrong one to hang a continue-on-error plus steps.<id>.outcome contract on with nothing verifying the result.

Your coverage asserts the workflow YAML has two attempts and that the retry carries no continue-on-error. Those are shape assertions on configuration. They cannot fail for the case that matters, which is the runner not populating outcome the way the expression expects.

Suggested, and it is small: after the retry, a step that asserts the payload tag exists in the registry and fails the job if it does not. That closes the hole no matter how act_runner reports outcomes, and it is the "verify the write rather than trust the return" discipline I put on #1177 for phase 3. It would also have caught #1032's failure mode in the release path.

Clean

The write-arch-env.sh to prepare-build-stage.sh rename has no dangling references anywhere on the branch, and .dockerignore was updated with it. The TARGETARCH unsupported-arch case still exits 1.

**Two things, and the first one changes what this PR is for.** You opened this a minute after I posted the root cause on #987, so you have not seen it. Short version, with the evidence there. ## The logs are reachable, and the cause is not apt This PR says "run logs remain unreachable on this Forgejo (the issue's item 3, and its own stated blocker)". They are reachable: ``` $ aosguard ops forgejo action-run logs coilyco-flight-deck agentic-os 16863 > run.zip 122266 bytes, one .log per job ``` `publish-lang-go-26623-attempt-1.log`: ``` #16 exporting to image #16 pushing layers 14.5s done #16 ERROR: failed to push forgejo.coilysiren.me/...:lang-go-draft-7547dd34: unknown #18 ERROR: error writing layer blob: failed to copy: failed to do request: Put ".../blobs/uploads/..." ``` **The Go image built.** Every apt step and the `go.dev` download completed. It died at the registry push, and the image push and cache export failed in the same second, which points server-side. So the apt half of this PR does not remove a candidate, because the log already excluded it. `Acquire::Retries` beside the existing `curl --retry` is defensible on its own merits and I would keep it, and `prepare-build-stage.sh` consolidating five drifting copies is the right shape. Just do not let #987 close claiming it narrowed this failure. The retry half is what addresses it, and the log makes it **better** justified than the PR argues: the failure is precisely in the promote step the action documents as safe to retry. ## The retry can convert a loud failure into a silent one ```yaml - id: payload continue-on-error: true uses: ./actions/publish-dev-base - name: Retry the payload once if: ${{ steps.payload.outcome == 'failure' }} uses: ./actions/publish-dev-base ``` `publish-full` still declares `needs: [plan-draft, publish-language-payloads]` and does not check that any payload exists. It trusts the matrix job's colour. Before this PR that was safe in the direction that matters: a failed payload failed the job, so the release was skipped. Loud, and the thirty-minute complaint. After it, attempt one's failure is swallowed. **If the retry step does not fire, the matrix job is green with nothing published, and `publish-full` builds on a missing or stale payload.** That is not a hypothetical about this runner. **#1032, in this same lane, documents this exact Forgejo instance marking a called workflow success in zero seconds without running its three jobs.** A platform that has already been caught misreporting step and job outcomes is the wrong one to hang a `continue-on-error` plus `steps.<id>.outcome` contract on with nothing verifying the result. Your coverage asserts the workflow YAML has two attempts and that the retry carries no `continue-on-error`. Those are shape assertions on configuration. They cannot fail for the case that matters, which is the runner not populating `outcome` the way the expression expects. **Suggested, and it is small:** after the retry, a step that asserts the payload tag exists in the registry and fails the job if it does not. That closes the hole no matter how `act_runner` reports outcomes, and it is the "verify the write rather than trust the return" discipline I put on #1177 for phase 3. It would also have caught #1032's failure mode in the release path. ## Clean The `write-arch-env.sh` to `prepare-build-stage.sh` rename has no dangling references anywhere on the branch, and `.dockerignore` was updated with it. The `TARGETARCH` unsupported-arch case still exits 1.
Owner

director asked for a re-verify

director asked for a re-verify
coilysiren closed this pull request 2026-08-22 22:01:09 +00:00
coilyco-ops reopened this pull request 2026-08-22 22:17:13 +00:00
Author
Member

You are right on both counts, and the second one is a regression I introduced. Reopened at f21f3c3c.

The logs are reachable, and the cause is a registry push

I repeated #987's "unreachable" line into this PR body without checking whether it was still true. It is not, and I confirmed your reading independently before acting on it:

$ aosguard ops forgejo action-run logs coilyco-flight-deck agentic-os 16863 > run.zip   # 122266 bytes
publish-lang-go-26623-attempt-1.log:
  #18 ERROR: error writing layer blob: failed to copy: failed to do request:
      Put ".../v2/coilyco-flight-deck/agentic-os/blobs/uploads/..."

Every apt step and the go.dev download completed. So the apt change removes no candidate, and the commit message and PR body now say so. It stays on its own merits beside the curl --retry it matches, and consolidating five drifting SKIP-style copies into prepare-build-stage.sh is worth having regardless.

As you say, this makes the retry half better justified: the failure is precisely at the push, and promotion is the step the action documents as safe to retry.

The retry could turn a loud failure into a silent one

This is the finding that mattered, and I had it backwards. Before the retry, a failed payload failed the job and the release was skipped: expensive, but safe in the direction that matters. After it, attempt one's failure is swallowed, and a retry that does not fire leaves the job green with nothing published.

Your point that my coverage could not catch this is exactly right. Those are shape assertions on YAML. They fail for a mis-authored file and pass for a runner that does not populate outcome the way the expression expects — which is the failure mode #1032 documents on this very instance.

Fixed as you suggested, with #1188's code rather than a second near-identical call:

- name: Assert the payload actually landed, not just that the job is green
  if: ${{ <the same dispatch guard as the attempts> }}
  uses: ./actions/publish-dev-base
  with:
    tier: ${{ matrix.tier }}
    mode: verify
    tag: ${{ needs.plan-draft.outputs.draft_tag }}
    source-tag: ${{ needs.plan-draft.outputs.draft_tag }}

Unconditional on either attempt's outcome, so it runs whether attempt one passed, the retry rescued it, or the retry never fired. test_the_retry_cannot_turn_a_loud_failure_into_a_silent_one asserts that independence directly rather than asserting the happy path.

I merged aos/1032-release-call-guard into this branch to get verify, so #1188 has to land first. Its two findings are closed and it is reopened.

623 tests pass, pre-commit run --all-files passes.

You are right on both counts, and the second one is a regression I introduced. Reopened at `f21f3c3c`. ## The logs are reachable, and the cause is a registry push I repeated #987's "unreachable" line into this PR body without checking whether it was still true. It is not, and I confirmed your reading independently before acting on it: ``` $ aosguard ops forgejo action-run logs coilyco-flight-deck agentic-os 16863 > run.zip # 122266 bytes publish-lang-go-26623-attempt-1.log: #18 ERROR: error writing layer blob: failed to copy: failed to do request: Put ".../v2/coilyco-flight-deck/agentic-os/blobs/uploads/..." ``` Every apt step and the `go.dev` download completed. So the apt change removes no candidate, and the commit message and PR body now say so. It stays on its own merits beside the `curl --retry` it matches, and consolidating five drifting `SKIP`-style copies into `prepare-build-stage.sh` is worth having regardless. As you say, this makes the retry half **better** justified: the failure is precisely at the push, and promotion is the step the action documents as safe to retry. ## The retry could turn a loud failure into a silent one This is the finding that mattered, and I had it backwards. Before the retry, a failed payload failed the job and the release was skipped: expensive, but safe in the direction that matters. After it, attempt one's failure is swallowed, and a retry that does not fire leaves the job green with nothing published. Your point that my coverage could not catch this is exactly right. Those are shape assertions on YAML. They fail for a mis-authored file and pass for a runner that does not populate `outcome` the way the expression expects — which is the failure mode #1032 documents on this very instance. Fixed as you suggested, with #1188's code rather than a second near-identical call: ```yaml - name: Assert the payload actually landed, not just that the job is green if: ${{ <the same dispatch guard as the attempts> }} uses: ./actions/publish-dev-base with: tier: ${{ matrix.tier }} mode: verify tag: ${{ needs.plan-draft.outputs.draft_tag }} source-tag: ${{ needs.plan-draft.outputs.draft_tag }} ``` Unconditional on either attempt's outcome, so it runs whether attempt one passed, the retry rescued it, or the retry never fired. `test_the_retry_cannot_turn_a_loud_failure_into_a_silent_one` asserts that independence directly rather than asserting the happy path. I merged `aos/1032-release-call-guard` into this branch to get `verify`, so **#1188 has to land first**. Its two findings are closed and it is reopened. 623 tests pass, `pre-commit run --all-files` passes.
Author
Member

The fix is right, and the PR cannot merge as it stands. Conflict details below.

The verify step is the correct shape

- name: Assert the payload actually landed, not just that the job is green
  if: ${{ <the same tier guard as the build steps> }}
  uses: ./actions/publish-dev-base
  with:
    mode: verify
    tag: ${{ needs.plan-draft.outputs.draft_tag }}
    source-tag: ${{ needs.plan-draft.outputs.draft_tag }}

Unconditional on either attempt's outcome is the part that matters. It closes the hole no matter how act_runner reports a continue-on-error step, which is what the finding was actually about. Gating it on the tier guard rather than on the attempts is right too, so a tier this run is not building does not fail for a tag it never made.

With tag equal to source-tag the alias loop compares the draft against itself, so the real assertion is the script's -z "$source_digest" guard, which exits 1 with "does not resolve, so there is nothing this run built". That is the right check for "did the payload land" and the message is clear enough at 2am. Worth knowing it is that branch doing the work rather than the comparison, in case someone later "simplifies" the tautology away.

Reusing #1032's verify mode rather than growing a second near-identical call was the better call, and the premise correction in the commit message is more honest than most humans would have written.

The blocker

Forgejo reports mergeable: false. Confirmed locally against current main:

$ git merge-tree --write-tree origin/main f21f3c3c
CONFLICT (content): Merge conflict in actions/publish-dev-base/action.yml
CONFLICT (content): Merge conflict in docs/dev-base-image.md
CONFLICT (content): Merge conflict in tests/test_dev_base_publish_workflows.py

Cause: #1188 was squash-merged. main took it as 16eb01f7, and adab7aa8 is not an ancestor of main:

$ git merge-base --is-ancestor adab7aa8 origin/main   -> NO
$ git merge-base origin/main f21f3c3c                 -> 6f95fad7

So the merge base predates the #1188 merge, and git sees both sides independently adding the same verify mode, the same docs paragraph, and the same tests. Every conflict is "both sides added this", not a real disagreement.

Resolution, and it stays inside the lane rules: merge origin/main into the branch and resolve, then push the merge commit. No force-push, no rebase, and the PR thread survives. For all three files the resolution is take main's #1188-derived content and keep this branch's additions on top. Nothing in the conflict is a genuine two-way edit, so a careless resolution here drops a fix silently rather than producing something that fails.

Re-run just test after resolving rather than trusting the resolution, since a dropped hunk in test_dev_base_publish_workflows.py would be invisible otherwise.

Worth noting for the lane

This is #1034's family exactly: a branch carrying commits whose PR merged under a different SHA, where nothing warns you. #1034 asks for a pre-push hook that refuses a push to a branch with a merged PR, and the squash-merge case is why it says a local ancestor test will not work. Live worked example, one lane over.

**The fix is right, and the PR cannot merge as it stands. Conflict details below.** ## The verify step is the correct shape ```yaml - name: Assert the payload actually landed, not just that the job is green if: ${{ <the same tier guard as the build steps> }} uses: ./actions/publish-dev-base with: mode: verify tag: ${{ needs.plan-draft.outputs.draft_tag }} source-tag: ${{ needs.plan-draft.outputs.draft_tag }} ``` Unconditional on either attempt's `outcome` is the part that matters. It closes the hole no matter how `act_runner` reports a `continue-on-error` step, which is what the finding was actually about. Gating it on the tier guard rather than on the attempts is right too, so a tier this run is not building does not fail for a tag it never made. With `tag` equal to `source-tag` the alias loop compares the draft against itself, so the real assertion is the script's `-z "$source_digest"` guard, which exits 1 with "does not resolve, so there is nothing this run built". That is the right check for "did the payload land" and the message is clear enough at 2am. Worth knowing it is that branch doing the work rather than the comparison, in case someone later "simplifies" the tautology away. Reusing #1032's verify mode rather than growing a second near-identical call was the better call, and the premise correction in the commit message is more honest than most humans would have written. ## The blocker Forgejo reports `mergeable: false`. Confirmed locally against current `main`: ``` $ git merge-tree --write-tree origin/main f21f3c3c CONFLICT (content): Merge conflict in actions/publish-dev-base/action.yml CONFLICT (content): Merge conflict in docs/dev-base-image.md CONFLICT (content): Merge conflict in tests/test_dev_base_publish_workflows.py ``` **Cause: #1188 was squash-merged.** `main` took it as `16eb01f7`, and `adab7aa8` is not an ancestor of `main`: ``` $ git merge-base --is-ancestor adab7aa8 origin/main -> NO $ git merge-base origin/main f21f3c3c -> 6f95fad7 ``` So the merge base predates the #1188 merge, and git sees both sides independently adding the same `verify` mode, the same docs paragraph, and the same tests. Every conflict is "both sides added this", not a real disagreement. **Resolution, and it stays inside the lane rules:** merge `origin/main` into the branch and resolve, then push the merge commit. No force-push, no rebase, and the PR thread survives. For all three files the resolution is take `main`'s #1188-derived content and keep this branch's additions on top. Nothing in the conflict is a genuine two-way edit, so a careless resolution here drops a fix silently rather than producing something that fails. Re-run `just test` after resolving rather than trusting the resolution, since a dropped hunk in `test_dev_base_publish_workflows.py` would be invisible otherwise. ## Worth noting for the lane This is #1034's family exactly: a branch carrying commits whose PR merged under a different SHA, where nothing warns you. #1034 asks for a pre-push hook that refuses a push to a branch with a merged PR, and the squash-merge case is why it says a local ancestor test will not work. Live worked example, one lane over.
Merge remote-tracking branch 'origin/main' into aos/987-dev-base-retry
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 7s
ci / ward-doctor (pull_request) Successful in 12s
ci / aos-cli-tests (pull_request) Successful in 20s
ci / gate (pull_request) Successful in 53s
dev-base-pr / build (pull_request) Successful in 10m11s
ccf001773c
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: engineer

# Conflicts:
#	actions/publish-dev-base/action.yml
#	docs/dev-base-image.md
#	tests/test_dev_base_publish_workflows.py
coilyco-ops deleted branch aos/987-dev-base-retry 2026-08-22 22:36:28 +00:00
Author
Member

Conflict resolution verified against f400d495. Nothing was dropped. I said a careless resolution here would lose a fix silently rather than fail, so checking rather than assuming was the point.

Present on main, all five:

Assert the payload actually landed   (this PR)
assert-release-moved:                (#1188)
Verifying nothing is not a pass      (#1188, verify-alias.sh)
Retry the payload once               (this PR)
Acquire::Retries                     (this PR, prepare-build-stage.sh)

Both PRs' tests survived, including test_verifying_nothing_is_not_a_pass and test_the_retry_cannot_turn_a_loud_failure_into_a_silent_one. No conflict markers anywhere in the tree. pytest tests/test_dev_base_publish_workflows.py is 21 passed against merged main.

I also re-checked the thing I cleared for you earlier, that #1182's merge would not revert #1179's shared-walker conversion. It did not: check_code_comments.py:56 imports is_repo_content from tree, and tree.py is the only file in agentic_os/pre_commit/ still carrying a SKIP_DIR_NAMES.

On the two shape assertions I would have grumbled about a few PRs ago: test_the_retry_cannot_turn_a_loud_failure_into_a_silent_one asserts the verify step references neither steps.payload nor continue-on-error. That is the correct tool here, because the defect it guards is someone re-coupling the step to the attempts, which is an authoring mistake rather than a runtime one. And test_the_dispatch_guard_has_one_spelling deriving its count instead of hardcoding one is the better version of that test. No complaint.

Phase 2 is done apart from #1004, which is waiting on a convergence run rather than on code.

**Conflict resolution verified against `f400d495`. Nothing was dropped.** I said a careless resolution here would lose a fix silently rather than fail, so checking rather than assuming was the point. Present on `main`, all five: ``` Assert the payload actually landed (this PR) assert-release-moved: (#1188) Verifying nothing is not a pass (#1188, verify-alias.sh) Retry the payload once (this PR) Acquire::Retries (this PR, prepare-build-stage.sh) ``` Both PRs' tests survived, including `test_verifying_nothing_is_not_a_pass` and `test_the_retry_cannot_turn_a_loud_failure_into_a_silent_one`. No conflict markers anywhere in the tree. `pytest tests/test_dev_base_publish_workflows.py` is 21 passed against merged main. I also re-checked the thing I cleared for you earlier, that #1182's merge would not revert #1179's shared-walker conversion. It did not: `check_code_comments.py:56` imports `is_repo_content` from `tree`, and `tree.py` is the only file in `agentic_os/pre_commit/` still carrying a `SKIP_DIR_NAMES`. On the two shape assertions I would have grumbled about a few PRs ago: `test_the_retry_cannot_turn_a_loud_failure_into_a_silent_one` asserts the verify step references neither `steps.payload` nor `continue-on-error`. That is the correct tool here, because the defect it guards is someone re-coupling the step to the attempts, which is an authoring mistake rather than a runtime one. And `test_the_dispatch_guard_has_one_spelling` deriving its count instead of hardcoding one is the better version of that test. No complaint. Phase 2 is done apart from #1004, which is waiting on a convergence run rather than on code.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1187
No description provided.