Skip to content

fix(harness): sync arm-loop.sh setup template to v7 + guard against drift - #223

Merged
robercano-ghbot merged 1 commit into
mainfrom
fix/arm-loop-template-parity
Aug 6, 2026
Merged

fix(harness): sync arm-loop.sh setup template to v7 + guard against drift#223
robercano-ghbot merged 1 commit into
mainfrom
fix/arm-loop-template-parity

Conversation

@robercano-ghbot

Copy link
Copy Markdown
Collaborator

What

arm-loop.sh is maintained in two places:

Path Role Marker before this PR
.claude/scripts/arm-loop.sh what actually runs from the installed plugin cache v7
.claude/skills/setup/templates/arm-loop.sh what scaffold.sh writes into a consumer repo and sync.sh re-stamps from v6

Nothing kept them in sync — release.sh doesn't copy one onto the other, and no check compared them. They drifted.

Why it matters

sync.sh stamps consumers from the template, so every already-onboarded repo is reported up to date at v6 forever while the plugin's own runtime copy is v7. Observed in reDeploy:

$ /orchestrator:sync
  up to date: .claude/scripts/arm-loop.sh already v6      # against plugin 0.3.0, whose scripts/ copy is v7

This isn't cosmetic. v7 added --stop-after-days (issue #95), which writes .claude/state/loop-arming.json — the file loop-tick.sh reads to decide whether the loop has passed its self-disarm horizon. A consumer stamped at v6 arms a loop whose tick script (resolved from the plugin cache, so v7) expects state the v6 arming script never writes.

Changes

  • templates/arm-loop.sh := scripts/arm-loop.sh — now byte-identical at v7, executable bit preserved.
  • New .claude/scripts/managed-template-parity.test.sh — for every templates/ file with a same-named scripts/ twin, asserts byte-identity and matching executable bit, so this can't silently recur. Auto-discovered by checks.sh do_test() (.claude/scripts/*.test.sh), so no self/ changes were needed (per CONTRIBUTING's "what NOT to touch").

Verified the guard actually guards: it exits non-zero on the drifted tree and zero on the fixed one.

Gates

GATES_FILE=self/gates.json bash .claude/scripts/gate.sh <gate>:

  • build ✅ (incl. hooks-parity, JSON/adapter shape, packaging-exclusion)
  • lint
  • test ⚠️ — 4 pre-existing failures in this sandbox: cockpit.test.sh, loop-census.test.sh, loop-tick.test.sh, pr-feedback.test.sh (all bind ports / need network). I ran self/checks.sh test on pristine main and on this branch and got identical failure sets, so this PR neither causes nor fixes them. The new test passes.

One question for you

No version bump in this PR. release.sh (issue #176) owns plugin.json / marketplace.json versioning as part of a milestone-gated cut, so this fix reaches installed consumers on the next release. But CONTRIBUTING.md → "What NOT to touch" still says a managed-file change must bump plugin.json's version in the same PR. That guidance predates release.sh and now conflicts with it. I left the bump out rather than collide with the release driver — happy to add it, or to send a separate doc PR reconciling the two, whichever you prefer.

Not in this PR (found alongside, both need a design call from you)

  1. Consumer-side hooks double-run. skills/setup/templates/settings.json declares PostToolUse(lint), Stop(test_affected) and PreToolUse(guard-git-add) — all three of which hooks/hooks.json also registers. A freshly-onboarded repo therefore runs each twice per turn; in reDeploy that meant two concurrent pnpm -r build into the same dist/, surfacing as a racy Stop hook error: No stderr output. The #140 hooks-parity check covers reCode's own settings.json vs hooks.json, not the template, so it doesn't catch this. I did not touch it — the fix depends on whether the template's hooks are meant as a plugin-disabled fallback.
  2. Post-Consumer repos carry stale vendored .claude/scripts that shadow the fresh plugin cache — manage them or stop vendoring #134 templates still assume a repo-local .claude/scripts/. templates/gates.yml:48 and templates/action.yml:57 run bash .claude/scripts/gate.sh, and templates/gates.json's worktree _note says "Run via .claude/scripts/worktree.sh" — but Consumer repos carry stale vendored .claude/scripts that shadow the fresh plugin cache — manage them or stop vendoring #134 removed the vendoring that populated that directory, and CI runners have no plugin cache. In reDeploy this meant worktree.sh was never present at all: nothing ever copied it and no mechanism ever would.

Happy to file both as backlog issues if you'd rather track them that way.

🤖 Generated with Claude Code

…rift

arm-loop.sh lives twice: .claude/scripts/arm-loop.sh (what runs from the
installed plugin cache) and .claude/skills/setup/templates/arm-loop.sh (what
scaffold.sh writes into a consumer repo and sync.sh re-stamps from). Nothing
kept them in sync — release.sh does not copy one onto the other and no check
compared them — so they drifted: scripts/ was v7 while the template was still
v6.

Consequence downstream: sync.sh stamps consumers from the TEMPLATE, so every
already-onboarded repo is reported "up to date" at v6 forever while the
plugin's own runtime copy is v7. Observed in reDeploy, where /orchestrator:sync
printed "up to date: .claude/scripts/arm-loop.sh already v6" against a v7
plugin.

The skew is not cosmetic. v7 added --stop-after-days (issue #95), which writes
.claude/state/loop-arming.json — the file loop-tick.sh reads to decide whether
the loop has passed its self-disarm horizon. A consumer stamped at v6 arms a
loop whose tick script (resolved from the plugin cache, so v7) expects state
the v6 arming script never writes.

Changes:
- templates/arm-loop.sh := scripts/arm-loop.sh (now byte-identical, v7,
  executable bit preserved).
- New .claude/scripts/managed-template-parity.test.sh: for every templates/
  file with a same-named scripts/ twin, assert byte-identity and matching
  executable bit, so this cannot silently recur. Auto-discovered by
  checks.sh do_test() (.claude/scripts/*.test.sh) — no self/ changes needed.
  Verified it fails on the drifted tree and passes on the fixed one.

No version bump here: release.sh owns plugin.json/marketplace.json versioning
as part of a milestone-gated cut, so the fix reaches installed consumers on the
next release. (CONTRIBUTING.md still says to bump plugin.json in the same PR as
a managed-file change — that predates release.sh and now conflicts; flagged in
the PR body rather than acted on unilaterally.)

Gates: build + lint pass. test has 4 pre-existing failures in this sandbox
(cockpit, loop-census, loop-tick, pr-feedback — all network/port-bound);
verified byte-identical failure sets on pristine main and on this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robercano-ghbot robercano-ghbot added module:harness Orchestrator machinery under .claude needs-human Loop escalated: attempt budget exhausted, manual triage required labels Aug 6, 2026
@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): sync arm-loop.sh setup template to v7 + guard against drift (not yet reviewed)

@robercano-ghbot robercano-ghbot added claude-ci-fixing In-flight guard: an automated CI-fix pass is addressing this PR and removed needs-human Loop escalated: attempt budget exhausted, manual triage required labels Aug 6, 2026
@robercano-ghbot robercano-ghbot added claude-ci-fixing In-flight guard: an automated CI-fix pass is addressing this PR and removed claude-ci-fixing In-flight guard: an automated CI-fix pass is addressing this PR labels Aug 6, 2026
@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

CI on this PR was failing due to a GitHub Actions platform-wide outage (confirmed via githubstatus.com: "Partial System Outage", major incident starting 2026-08-06 17:02 UTC) — every failing job died at the "Getting action download info" setup step with Service Unavailable/Internal Server Error, before any repo code ran. No code change was needed. Re-ran the failed jobs (gh run rerun --failed) after the outage cleared; all checks (build, lint, typecheck, test, coverage, security, self/build, self/lint, self/test) are now green on the current head commit 2b3dc267.

@robercano-ghbot robercano-ghbot added needs-human Loop escalated: attempt budget exhausted, manual triage required and removed claude-ci-fixing In-flight guard: an automated CI-fix pass is addressing this PR labels Aug 6, 2026
@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): sync arm-loop.sh setup template to v7 + guard against drift (not yet reviewed)

@robercano-ghbot robercano-ghbot removed the needs-human Loop escalated: attempt budget exhausted, manual triage required label Aug 6, 2026
@robercano-ghbot
robercano-ghbot merged commit 135c9f2 into main Aug 6, 2026
32 of 54 checks passed
@robercano-ghbot
robercano-ghbot deleted the fix/arm-loop-template-parity branch August 6, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module:harness Orchestrator machinery under .claude

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants