fix(unic-archon-dlc): explicit staging, and composed repository pinning in the Archon Boxes - #308
Conversation
…ng in the Archon Boxes Two defects, both present since the Boxes were written. `/explore`'s `preserve-spike` ran `git add -A` and `/build`'s `open-pr` said "stage everything changed by the build". A Box runs in an isolated worktree with fresh context, so "everything changed" sweeps in whatever else is on disk — including `build-state.json`, which the build loop rewrites on every one of up to 60 iterations. No PR or tracker call named the repository it acted on, so a host tool inferred it from the checkout. In a fork clone that is the parent, and the PR opens on someone else's project. Changes: - Every committing node stages a named list, one `git add <path>` per path, then confirms with `git status --porcelain`. The deny list (`pr-body.md`, `*.tmp.md`, `*.scratch.md`, `$ARTIFACTS_DIR`) is stated inline in each, because an Archon node imports nothing from the Plugin (ADR-0023 §5). - `build-state.json` is committed once, at `open-pr`, never in a loop iteration — it is the durable proof of ADR-0012's anti-cheat record. - Every Box's bootstrap DERIVES the target repository from the worktree's `origin` remote. `project.repo_ref` is an optional override, absent by default, so no existing config breaks. A new `guard-ambiguous-repo` node CANCELS only when the checkout names more than one repository and no override is set (ADR-0011). - No prompt or command doc carries a host CLI token, subcommand, flag, or provider name. Each states "act on THIS repository, never the one a tool infers from the checkout" and composes the skill registered under `tracker.access`, reading that skill's own current interface (ADR-0016). - New `test/box-staging-and-repo-pinning.test.mjs` greps ten shipped files for CLI and provider tokens and fails loudly with file:line. It self-tests its own patterns, so a mistyped regex cannot fail open. Fixes #289
🔍 Comprehensive PR ReviewPR: #308 SummaryPrompt/config-only PR: explicit named-path staging replaces every blind Verdict:
🟢 Low IssuesView 4 low-priority items
✅ What's Good
Next Steps
Reviewed by Archon comprehensive-pr-review workflow |
Add assert.ok guards after the two unchecked nodeSource() extractions in box-staging-and-repo-pinning.test.mjs, matching the file's own convention, so a future extraction failure surfaces a descriptive message instead of a bare TypeError. Add a CONTEXT.md Language entry for repository derivation — the vocabulary AGENTS.md's new doctrine bullet coins but the Language section didn't carry. Fixed: - Two nodeSource() call sites (guard-ambiguous-repo, guard-not-ready) now assert.ok before use - CONTEXT.md Language section gained a "Repository derivation" entry, linking ADR-0011 Skipped: - test-coverage Finding 1 (stub .md files not checked for repo-invariant wording): reviewer's own assessment marks this intentional by design — stubs are thin pointers, the YAML is the enforcement point
⚡ Self-Fix Report (Aggressive)Status: COMPLETE Fixes Applied (3 total)
View all fixes
Tests Added(none) — fix was an existence assertion on an existing test path; 220/220 tests still pass. Skipped (1)
Suggested Follow-up Issues(none) Validation✅ Type check | ✅ Lint ( Self-fix by Archon · aggressive mode · fixes pushed to |
There was a problem hiding this comment.
Pull request overview
This PR hardens the unic-archon-dlc Archon workflows (“Boxes”) by enforcing explicit staging and deriving the target repository from the worktree origin, while introducing a regression test barrier that prevents provider-/CLI-specific tokens from reappearing in guarded prompts and command docs.
Changes:
- Replaced blind staging guidance with explicit, named-path staging rules (including deny-lists and staged-set verification).
- Added repository derivation + an “ambiguous repository” cancel guard across the Archon workflows and updated interactive command docs to derive
TARGET_REPO. - Added a new barrier test that scans guarded workflows/docs for provider knowledge and asserts the positive staging/repo-derivation invariants.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| apps/claude-code/unic-archon-dlc/test/config-schema.test.mjs | Adds tests ensuring project.repo_ref is absent by default and preserved when overridden. |
| apps/claude-code/unic-archon-dlc/test/command-methods.test.mjs | Extends harness doc token allowlist (incl. pr-body.md) to support new deny-list prose. |
| apps/claude-code/unic-archon-dlc/test/box-staging-and-repo-pinning.test.mjs | New barrier test enforcing “no provider knowledge”, explicit staging, and repo derivation rules. |
| apps/claude-code/unic-archon-dlc/test/archon-box-methods.test.mjs | Adjusts comments to reflect provider-agnostic wording and staging-rule references. |
| apps/claude-code/unic-archon-dlc/README.md | Documents project.repo_ref as an optional override and describes derived-repo behavior. |
| apps/claude-code/unic-archon-dlc/package.json | Bumps version to 0.15.1 and adds the new test to the test script. |
| apps/claude-code/unic-archon-dlc/CONTEXT.md | Adds vocabulary/notes for repository derivation and guard behavior. |
| apps/claude-code/unic-archon-dlc/commands/specs.md | Adds TARGET_REPO derivation section and updates PR gate staging + provider-agnostic PR-opening instructions. |
| apps/claude-code/unic-archon-dlc/commands/tickets.md | Adds TARGET_REPO derivation section and updates staging + provider-agnostic publishing/PR-opening instructions. |
| apps/claude-code/unic-archon-dlc/commands/setup.md | Clarifies that project.repo_ref is not asked/written by default (override only on request). |
| apps/claude-code/unic-archon-dlc/CHANGELOG.md | Adds 0.15.1 entry describing staging hardening, derived repo, and the barrier test. |
| apps/claude-code/unic-archon-dlc/AGENTS.md | Adds a load-bearing invariant capturing explicit staging + derived repository rules and the barrier test. |
| apps/claude-code/unic-archon-dlc/.claude-plugin/plugin.json | Bumps plugin version to 0.15.1. |
| apps/claude-code/unic-archon-dlc/.claude-plugin/marketplace.json | Bumps marketplace version to 0.15.1. |
| apps/claude-code/unic-archon-dlc/.archon/workflows/unic-dlc-build.yaml | Derives repo in bootstrap, adds ambiguous-repo cancel guard, and makes open-pr staging explicit (incl. build-state handling). |
| apps/claude-code/unic-archon-dlc/.archon/workflows/unic-dlc-explore.yaml | Derives repo in bootstrap, adds ambiguous-repo cancel guard, and stages spike artifacts by recorded paths instead of sweeping. |
| apps/claude-code/unic-archon-dlc/.archon/workflows/unic-dlc-pr-review.yaml | Derives repo in bootstrap, adds ambiguous-repo cancel guard, and makes PR-touching nodes explicitly repository-scoped/provider-agnostic. |
| apps/claude-code/unic-archon-dlc/.archon/workflows/unic-dlc-qa.yaml | Derives repo in bootstrap, adds ambiguous-repo cancel guard, and scopes PR/issue operations to the derived repository. |
| apps/claude-code/unic-archon-dlc/.archon/commands/unic-dlc-build.md | Updates Archon command stub to reflect derived repository + explicit staging changes. |
| apps/claude-code/unic-archon-dlc/.archon/commands/unic-dlc-explore.md | Updates Archon command stub to reflect derived repository + named-path spike preservation. |
| apps/claude-code/unic-archon-dlc/.archon/commands/unic-dlc-pr-review.md | Updates Archon command stub language around intent sources and provider-agnostic targeting. |
| apps/claude-code/unic-archon-dlc/.archon/commands/unic-dlc-qa.md | Updates Archon command stub to reflect derived repository + explicit repo naming for PR/issue operations. |
Suppressed comments (2)
apps/claude-code/unic-archon-dlc/.archon/commands/unic-dlc-pr-review.md:12
- This overview still describes the /pr-review workflow as fanning out seven aspects, but the workflow YAML now documents a two-axis review (Standards + Spec). Leaving this as-is will mislead operators reading the Archon command stub.
This issue also appears on line 44 of the same file.
Runs the `pr-review` box: composes a shared **Intent Brief** (from the linked work items, the referenced
docs pages, the PR description, and `PRD.md`), fans out **seven review aspects** as parallel fresh nodes
(code-quality, test-coverage, silent-failure, type-design, comment-rot, code-simplification, and an
intent/AC-coverage check), synthesises the findings, **reconciles them against the prior iteration**
(new / still-present / fixed / regressed), and — after a config-gated human confirm — posts or updates a
single structured **summary comment** plus **inline comments** on the current PR.
apps/claude-code/unic-archon-dlc/.archon/commands/unic-dlc-pr-review.md:48
- This step list still claims there are "7 aspect nodes" with spawn gates, which no longer matches the current /pr-review workflow description (two-axis Standards/Spec fan-out). Consider updating this section so the command doc reflects the current node structure.
3. **7 aspect nodes** (parallel, fresh) — each reads the shared Intent Brief (**every aspect is
intent-grounded**) + the diff and emits findings scored on the **confidence rubric** (90–100 Critical
/ 80–89 Important / 60–79 Minor / below the threshold dropped). **Spawn gates** run each aspect only
when meaningful: code-quality + intent-check always; tests/type-design/comment-rot/simplifier/
silent-failure gated on the changed-file categories.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…he /pr-review stub Three Copilot findings on PR #308, all confirmed by running them. The directory-sweep guard was anchored to end-of-line, so it only ever saw `git add docs/adr/` alone on its line. Four spellings walked past it: a trailing comment, a quoted path, an `&&` chain, and `git add -- docs/adr/` — which is the `git add -- "<path>"` form these prompts themselves prescribe, so a sweep written in the house style was invisible. Replaced with a token-wise reader, self-tested against all seven sweep spellings and three named-path forms it must stay silent on. Injecting the `--` spelling into unic-dlc-build.yaml now fails the barrier; the old pattern reported the same file clean. The /pr-review command stub still advertised "seven review aspects" with spawn gates in its frontmatter, its overview and its step list. #281 collapsed those seven nodes into one `review` node hosting the code-review Method's own two-axis Standards/Spec fan-out (unic-dlc-pr-review.yaml:233), and the categories in `prep` no longer gate anything. This PR had already edited that sentence for provider-agnostic wording and left the wrong claim standing beside the new words. Verified at this commit: 220/220 tests, typecheck and ci:check all exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgKAGuqw6tnVZqHzPa3xC3
Fixes #289.
Why
Two defects, both present in the Boxes since they were written, found by reading the Archon 0.7.0 release against our own workflows.
Blind staging.
/explore'spreserve-spikerangit add -A;/build'sopen-prsaid "stage everything changed by the build". A Box runs in an isolated worktree with fresh context, so it cannot tell its own output from whatever else is on disk — and "everything changed" includesbuild-state.json, which the build loop rewrites on every one of up to 60 iterations.Unpinned repository. No PR or tracker call named the repository it acted on, so a host tool inferred it from the checkout. In a fork clone that is the parent, and the PR opens on someone else's project.
A first attempt (#307, closed unmerged) fixed the second defect by prescribing the flag per host, and so wrote 22
--repository, 16gh pr createand 11az repos proccurrences into seven prompt blocks — including oneaz repos pr threadsubcommand that does not exist. That is what ADR-0016 forbids and what this PR is shaped to prevent: an agent composing a call at run time reads the tool as it is today, whereas a flag table frozen in a YAML file is stale the moment the tool changes, cannot be verified without a live tenant, and is copied as precedent by the next agent that reads it.What changed
Staging (AC 1–5, 8). Every committing node stages a named list, one
git add <path>per path, then confirms withgit status --porcelainand unstages anything else./build'sopen-prlist is explicit — source, tests,PRD.md,issues.json,report.md,build-state.json, each drafteddocs/adr/NNNN-*.md./explore'sspikenode now records the paths it wrote sopreserve-spikecan name them./specsand/ticketsstage named paths in both theopen-prandstage-onlygates, and no longergit add docs/adr/as a directory. The deny list (pr-body.md,*.tmp.md,*.scratch.md, anything under$ARTIFACTS_DIR) is inline in each node, not doctrine: an Archon node imports nothing from the Plugin (ADR-0023 §5), so a rule that lives only inAGENTS.mdis invisible at run time.build-state.json(AC 3). Committed once, atopen-pr; the loop is told explicitly never to stage it. That commit is the durable proof of ADR-0012's anti-cheat record, which previously died whenever/cleanuppruned the worktree.Repository pinning (AC 6, 7). Each Box's
bootstrapderives the repository from the worktree'soriginremote.project.repo_refis an optional override, absent from the default config, so no existing Consumer config breaks. A newguard-ambiguous-reponode cancels — not fails (ADR-0011) — only when the checkout names more than one repository and no override is set; a checkout with a singleoriginnever reaches it. Every PR-touching prompt states the invariant "act on THIS repository, never the one a tool infers from the checkout", names the derived repository, and stops if the registered system-skill cannot target a repository explicitly.No provider knowledge (AC 6). Ten shipped files lose their per-provider branches. They name the config keys (
tracker.type,tracker.access) and compose the skill the team registered, reading that skill's own current interface. Behaviour that used to be hardcoded per host — is there a queryable PR, can it comment on a file and line, can it merge — is now a capability the composed skill is asked about, degrading to summary-only or manual steps when the answer is no.The barrier (AC 10).
test/box-staging-and-repo-pinning.test.mjsgreps the four Box YAMLs, both interactive command docs and the four Archon command docs — AC 10 names the first six; the stubs are in because AC 6's rule is "no Box prompt or command doc", and a Consumer's agent reads a stub as readily as a prompt. On a hit it fails naming every token byfile:line. It self-tests its own patterns so a mistyped regex cannot fail open, checks the guarded files are non-empty so a rename cannot reduce coverage to zero, and asserts the positive rules too: named-path staging, the deny list, the derived repository, the two mutually-exclusive guards, and the invariant per PR-touching node. Proven to fail on a synthetic violation before being trusted.commands/setup.mdis deliberately not guarded:/setupis the one surface that legitimately holds provider values, because it conducts the conversation that writestracker.type.Verification
pnpm --filter unic-archon-dlc testpnpm --filter unic-archon-dlc typecheckpnpm ci:checkpnpm --filter unic-archon-dlc verify:changelogVersion bumped to
0.15.1viapnpm bump patch, with a dated CHANGELOG entry.Note for the reviewer
.archon/commands/unic-dlc-build.mdandunic-dlc-pr-review.mdstill describe a REFACTOR phase and seven aspect nodes respectively — both retired by #281. That staleness is pre-existing and out of this ticket's scope; only their provider tokens were touched here.Scope note (self-fix, code-review Finding 1)
The
guard-ambiguous-reponode andrepo_ref/repo_ref_sourcederivation were extended to/exploreas well as/build,/qa, and/pr-review, even though the review scope's OUT-OF-SCOPE list named this deferred. This was a deliberate widening during implementation for symmetry — every Box that writes to a repository gets the same guard — not an unscoped addition. Code, CHANGELOG ("every Box"), and the new test'sWORKFLOWSconstant all agree with each other on this boundary; they just disagree with the scope artifact. Noting here per the code-review agent's Option A recommendation rather than reverting the guard.🤖 Generated with Claude Code