Skip to content

bug(unic-archon-dlc): /qa ends green on paths where nothing merged #652

Closed

Description

@orioltf

Problem

/qa ends green on paths where nothing merged. The reported case: when verify-pr-base confirms
there is no open PR, it sets base_ok to "true", merge runs, and the run prints
complete — 0 item(s) resolved. ✓. The same shape holds wherever /qa does not merge: a failed
test, a red e2e or coverage-gate, a wrong base, a failed base query, and a merge node that
does not merge. Archon skips the node, nothing fails, and the run reads as a success.

After #439, a red /build opens no PR, so a
/qa on that branch meets the reported case on run 4's path.

This predates PR #650
(#505), which kept the behaviour and stated it
in the 0.30.0 changelog. The round 2 silent-failure review of that PR found it.

Rulings (grilled with the maintainer, 2026-10-27)

  • Every /qa path that does not merge ends cancelled, never completed and never failed. This
    matches bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439, where a red /build is a result and ends cancelled.
  • The cancel nodes follow the sibling idiom bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439 ruled: a cancel: leaf whose when is the exact
    negation of the when of the node it guards.
  • The PR's existence is a signal of its own, pr_state, with five values:
    open | merged | closed | none | unknown. base_ok keeps one meaning, "the open PR targets
    $BASE_BRANCH", and is never set to stand for a missing PR.
  • The PR check runs right after bootstrap, before any test, and again inside verify-pr-base,
    because a PR can be merged or closed during UAT.
  • A red check still reaches uat-gate. Its reject path is where a human files the failure as a
    ticket, and AFK skips it at no cost.
  • A merge that landed but failed to write resolved on some items ends completed. It is not undone.

Acceptance criteria

  1. Before any Box YAML changes, a probe on Archon 0.12.1 measures the behaviours the criteria
    below rest on.
    It uses the probe shape of #439's
    criterion 0: Archon run by path, an isolated ARCHON_HOME, a scratch repository outside every clone,
    and a minimal workflow. It measures bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439's items 2, 3 and 4:

    1. A cancel: node whose when holds sets terminal status cancelled, and a sibling with the
      inverse when does not run, nor does any node that depends on that sibling.
    2. On the other branch, the skipped cancel: leaf does not stop the run from reaching completed.
    3. A cancel: message substitutes node-output references.

    The loop runs the probe when it can, otherwise it is a HITL step for the maintainer before any YAML
    changes. Stop rule, the same as bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439's: if any of the three does not hold, stop and report what
    you measured. Do not adapt the design in the implementation. The PR records the probe's date, the
    Archon version and each result, and states that bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439's criterion 0 may cite this probe for its
    items 2, 3 and 4 instead of re-running them.

  2. A /qa on a branch whose PR state is not open ends cancelled before test runs. Its last
    message names the case and the next action:

    • none: no PR was ever opened for the branch. Fix the build and re-run /build.
    • merged: the PR is already merged. Nothing to do.
    • closed: the PR was closed without merging. Reopen it, or abandon the work.
    • unknown: the PR state could not be read. The message carries the cause. A failed query gives the
      error as received and says to check access to the tracker and re-run /qa. A missing or unusable
      tracker contract names the file and says to add it with /unic-archon-dlc:setup.
  3. verify-pr-base reports pr_state as well as base_ok. It no longer sets base_ok to "true"
    when no PR exists. A PR that is no longer open when verify-pr-base runs ends the run cancelled,
    and the message carries the text for its case from criterion 1, joined as criterion 4 says.

  4. A /qa on an open PR with the wrong base ends cancelled, and its message says the PR targets
    <actual> but <expected> was expected. It never says the PR is missing.

  5. When test is not pass, e2e or coverage-gate is fail, the base is wrong, or the base query
    failed, the run ends cancelled after verify-pr-base. Its message names every cause that held,
    not only the first. At verify-pr-base, a PR that is not open and a wrong base are causes like the
    others: the message joins the text from criterion 1 or 3 with every failed check, and no cause
    replaces another.

  6. In HITL, merge-gate asks for approval only when merge would run. Its when equals the
    conditions of merge's when.

  7. merge reports as structured output whether it merged. When it runs and does not merge (the tracker
    contract is missing, the tracker cannot merge, the branch policy refuses, or the merge call errors),
    the run ends cancelled. The message gives the reason, and the manual steps when the tracker cannot
    merge.

  8. The line merge: QA for "<slug>" complete … ✓ is printed only after a merge that landed. If writing
    resolved failed on some items, the line names them and does not count them as resolved.

  9. No path through /qa that does not merge ends completed.

  10. docs/boxes/unic-dlc-qa.md describes the PR check, each cancel case and its message, and the
    changed merge-gate condition.

  11. docs/architecture/20260925-unic-dlc-qa-pipeline.json shows the new nodes, and both PNGs are
    exported again from it.

  12. CHANGELOG.md records the change under ### Breaking: runs that ended completed now end
    cancelled. The release is a minor bump.

Activity

  1. orioltf commented on Oct 21, 2026

    @orioltf
    MemberAuthor

    This was generated by AI during triage.

    Triage notes. Found by the round 2 silent-failure review of PR #650, at head bd943acd. I did not run /qa. I read verify-pr-base, merge-gate and merge in unic-dlc-qa.yaml at that head. base_ok is "true" for a confirmed "no open PR", and merge has no branch for that case. Blocked by #505, because PR #650 rewrites verify-pr-base and this ticket edits it again.

  2. orioltf commented on Oct 26, 2026

    @orioltf
    MemberAuthor

    Stale — do not follow. The criteria are approved and the fix is dispatched under /afk-loop 498; the opener for the fix is the newer comment that starts with **Opener for #652**.

    Opener — How to start this session (written 2026-10-26 by unic-sdlc-orchestrator-6, at dispatch)

    What this session produces

    Triage and approved acceptance criteria in this ticket's body, then the label ready-for-agent. Nothing else. The fix runs later under /afk-loop 498. This ticket now blocks #439, so /afk-loop 498 reaches #439 only after this one merges.

    Start: the maintainer types /wayfinder 498 #652. When the grilling starts, the maintainer types /grill-with-docs. Both carry disable-model-invocation, so the session cannot invoke them itself.

    Do not close this ticket. This overrides /wayfinder step 4. This stream grills a ticket into its own criteria and implements it under the same number. Do not invoke /implement, /tdd or /to-tickets. Replace needs-triage with a state label when the maintainer approves.

    Read in this order

    1. This ticket's body, then the triage comment. The comment's "blocked by No Box can target a base branch that is not the trunk, so run 4 cannot merge to integration/dlc #505" is resolved: No Box can target a base branch that is not the trunk, so run 4 cannot merge to integration/dlc #505 merged as PR #650.
    2. #439's body, § Rulings of 2026-10-26. After bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439, a red /build run opens no pull request. A /qa on that branch is the case this ticket fixes, so this ticket is now on run 4's path.
    3. apps/claude-code/unic-archon-dlc/.archon/workflows/unic-dlc-qa.yaml on origin/develop: verify-pr-base, merge-gate, merge, and guard-not-ready for the Box's own cancel idiom.
    4. docs/boxes/unic-dlc-qa.md, the part on the base check.

    The trap that costs an hour

    Fixing it by setting base_ok to "false" when no PR exists. merge-gate and merge would skip, the run would stop being green-with-nothing-merged, and the criteria would read satisfied. But base_ok means "the PR targets the right base". Overloading it makes "no PR" and "wrong base" one value, and the operator reads a base mismatch where there is no PR at all. The no-PR case needs its own signal and its own message. Name that signal in the criteria.

    What this ticket does not decide yet

    Each of these is a question for the maintainer. None is yours to settle with a plausible default.

    Other traps

    • This repository is public, and its issues are too. Name no client, no Consumer repository, no city, sector or product. Write "the Consumer". The NDA hook refuses listed terms, and it does not catch a paraphrase.
    • A new node in /qa stales apps/claude-code/unic-archon-dlc/docs/architecture/20260925-unic-dlc-qa-pipeline.json. If the criteria add one, they require its JSON updated and both PNGs exported again.
    • The CHANGELOG.md entry goes under ### Breaking if a run that ended green now ends cancelled.
    • Ask one question at a time while the answers still branch. Links, never bare ids, in everything you write on the tracker.

    The bar that proves it

    Run the four reads from docs/agents/dispatching-and-learning.md § Before you post one on the criteria as a set. Then check:

    • A /qa dispatched on a branch with no open PR cannot end with a success line, and its last message says no PR exists.
    • A /qa on a PR with the wrong base still says the base is wrong, not that the PR is missing.
    • No criterion offers two acceptable outcomes.

    A false pass is the overloaded base_ok: every criterion reads satisfied, and the two failure cases print the same thing.

    On landing

    1. Rewrite this ticket's body with the approved criteria, and post a comment saying what changed.
    2. Before you apply any label, report to unic-sdlc-orchestrator-7 with the link. The orchestrator reads the criteria as one set and replies.
    3. Then replace needs-triage with ready-for-agent, set its priority if the maintainer moves it from p2, and leave it unassigned for /afk-loop 498.
    4. Change no file in the repository.

    Report back

    BEFORE YOU FINISH, AND WHENEVER YOU LEARN SOMETHING THAT WOULD HAVE CHANGED THIS PROMPT,
    report to unic-sdlc-orchestrator-7 with four things and nothing else:
      1. what you expected
      2. what happened
      3. the command or file that proved it
      4. whether it changes only this ticket, or every session in this repo
    Send it when you learn it, not only at the end — a session that dies unreported
    takes its learnings with it.
    Talk only to unic-sdlc-orchestrator-7. Do not message another orchestrator or its
    sessions; tell unic-sdlc-orchestrator-7, who relays it.
    

    Review and handover

    There is no pull request. The maintainer approves the criteria in the session. The orchestrator reads them as one set before the label goes on. Implementation runs under /afk-loop 498, which this seat records as unproven in the Consumer until a Consumer run reads it.

    Edited 2026-10-27 by unic-sdlc-orchestrator-7: report-back address moved from orchestrator-6, which has handed off.

  3. self-assigned this
    on Oct 27, 2026
  4. changed the title [-]bug(unic-archon-dlc): `/qa` ends green without merging when no open PR exists[/-] [+]bug(unic-archon-dlc): `/qa` ends green on paths where nothing merged[/+] on Oct 27, 2026
  5. orioltf commented on Oct 27, 2026

    @orioltf
    MemberAuthor

    Body rewritten with the criteria the maintainer approved in a grilling on 2026-10-27. What changed:

    • Scope widened. The ticket covered the no-open-PR case only. It now covers every /qa path that does not merge: a failed check, a wrong base, a failed base query, and a merge node that does not merge. The maintainer chose this over a sibling ticket to avoid another round of delay. The title changed with it.
    • One outcome, no choice. Old criterion 1 allowed cancel or report. Every non-merging path now ends cancelled, with a message per cause.
    • A signal of its own. The PR's existence is pr_state (open | merged | closed | none | unknown), and base_ok keeps its one meaning.
    • Checked early. The PR check runs before any test, and again in verify-pr-base.
    • Measured first. Criterion 0 measures the cancel: leaf on Archon 0.12.1 once, before the YAML changes, because this ticket lands before bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439's own probe.
    • Priority moved from p2 to p1.
  6. orioltf commented on Oct 27, 2026

    @orioltf
    MemberAuthor

    Criteria amended after the orchestrator read them as one set. The maintainer approved each change on 2026-10-27.

    • Criterion 0 now uses #439's probe shape and its stop rule. The old wording ran /qa on a branch with no PR. That needs a tracker a scratch repository cannot give, and the current Box has no cancel: leaf on that path to measure. The PR states that bug(unic-archon-dlc): open-pr precedes its gate, and a config-value gate has no safe middle #439's criterion 0 may cite this probe for its items 2, 3 and 4.
    • Criteria 2 and 4: at verify-pr-base, a PR that is not open and a wrong base are causes like the failed checks. The message joins all of them, and no cause replaces another.
    • Criterion 6: merge reports whether it merged as structured output, and a missing tracker contract is one more non-merge cause.
  7. added
    ready-for-agentFully specified, ready for an AFK agent
    p1High priority
    and removed
    needs-triageMaintainer needs to evaluate
    p2Medium priority
    on Oct 27, 2026
  8. removed their assignment
    on Oct 27, 2026
  9. self-assigned this
    on Oct 27, 2026
  10. orioltf commented on Oct 27, 2026

    @orioltf
    MemberAuthor

    Opener for #652

    Written 2026-10-28 by the /afk-loop 498 orchestrator, at dispatch. It supersedes the grilling opener above, whose job ended when the criteria were approved.

    What this session produces

    First the probe of criterion 0, then, only if all three of its items hold, one pull request to develop that changes apps/claude-code/unic-archon-dlc/.archon/workflows/unic-dlc-qa.yaml, its Box doc, its architecture diagram and the changelog, so that no /qa path that does not merge ends completed. The criteria in this ticket's body are the spec. Do not invoke /tdd or /to-tickets: the Box is prose, and the bar is a run and a read (AGENTS.md § Acceptance criteria are prose).

    Read in this order

    1. This ticket's body, whole. The two comments after the grilling opener say why it changed. The body already holds their content.
    2. The #505 spike comment. It is the method for criterion 0: the v0.12.1 release binary downloaded with gh release download v0.12.1 --repo coleam00/Archon into a scratch directory, checksums checked, a wrapper that sets ARCHON_HOME to a scratch folder and runs that binary by its path, and a scratch repository outside every clone. This machine's own archon is v0.10.1. Leave it, ~/.archon and ~/.claude untouched.
    3. unic-dlc-qa.yaml on origin/develop: bootstrap, guard-not-ready (the Box's own cancel: idiom), test, uat-gate, verify-pr-base, merge-gate and merge, with the comments above each.
    4. apps/claude-code/unic-archon-dlc/docs/boxes/unic-dlc-qa.md, and docs/architecture/20260925-unic-dlc-qa-pipeline.json with the archify skill, which renders it.

    The trap that costs an hour

    A path that reaches neither merge nor a cancel: leaf. The defect is a run where every node is skipped or green and nothing merged, so a fix is correct only if every path ends in a merge that landed or a cancel. Two things make a path easy to miss:

    • verify-pr-base and merge run on trigger_rule: all_done, and test, e2e and coverage-gate can be skipped or unresolved. A cancel leaf's when must be the exact negation of the when it guards, written against the same outputs, so the two cannot both be false.
    • merge itself can run and not merge (criterion 6). That needs its own leaf after merge, reading merge's new structured output.

    Before you edit, list every path through the new graph on paper: the PR states, the check results, HITL and AFK, and the merge outcome. Put that list in the PR body, with the node each path ends in. Criterion 8 is that list.

    What this ticket does not decide

    • The node names and where the early PR check lives. A new node after bootstrap, or a change to bootstrap, both fit criterion 1. test must then depend on that check, so that a cancel stops the run before test starts. A sibling that depends on bootstrap alone can start in parallel with the cancel.
    • How pr_state is read. The tracker contract governs it, as it does for verify-pr-base today. Name no tracker in the Box.

    Other traps

    • The probe's stop rule is binding. If any of the three items does not hold on 0.12.1, write the probe up as a comment on this ticket, change no YAML, and report. Do not adapt the design.
    • #439 waits on this ticket, and its criterion 0 may cite your probe. Say so in the PR body, as criterion 0 asks.
    • The new nodes stale the diagram. Update the JSON, then export both PNGs with the archify skill. Print no PNG to your context.
    • e2e and coverage-gate cancel only on fail. unresolved still lets the merge through, as the comment above merge explains. Criterion 4 keeps that.
    • This repository is public. Name no client and no Consumer repository. Use synthetic examples only.
    • Use absolute paths in every shell call, and never cd. The NDA hook refuses a gh command that changes directory.

    The bar that proves it

    The probe's three results, measured on 0.12.1 and written into the PR body with the date. Then the path list from the trap above, read against the YAML at your head: every path ends in a merge that landed or in a named cancel, and each cancel message carries the text criteria 1, 3, 4 and 6 give it.

    A false pass is a run that reaches completed with nothing merged on one path the list left out. Another false pass is a cancel message that names only the first cause when several held (criterion 4).

    On landing

    1. Add the entry to apps/claude-code/unic-archon-dlc/CHANGELOG.md under ## [Unreleased], ### Breaking, and commit it with the change.
    2. Bump with pnpm --filter unic-archon-dlc bump minor, and commit the result on its own as chore(unic-archon-dlc): release <version>.
    3. The PR body holds Closes #652, the probe results, the path list, and a line saying the change is unproven in the Consumer until a Consumer run reads it.

    Report back

    Report in your final answer, as your worker prompt's step 7 says, and stop after the handover. If the probe's stop rule fires, your report is the probe comment's link and its three results. The orchestrator may continue you with fix rounds.

    Review and handover

    The orchestrator runs the review rounds, sends you the findings to fix, and merges when the gate holds. You do not merge, and you do not answer review threads.

  11. added
    resolvedImplemented; ready for a PR
    and removed
    ready-for-agentFully specified, ready for an AFK agent
    on Oct 27, 2026
  12. added
    closedPR has been merged
    and removed
    resolvedImplemented; ready for a PR
    on Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions