Skip to content

standardize-repo: update mode's guarded recipe ships as prose, not as a runnable asset #420

Description

@evanharmon1

Invariant

Executable procedure in the standardize-repo skill ships as an executable
asset
. Where a mode's steps are load-bearing shell — ordering, fail-closed
guards, frozen object IDs — the operator runs a shipped script rather than
lifting fenced blocks out of prose into files of their own.

mode-update.md is the exception, and it is the largest body of shell in the
skill.

Current violation (observed 2026-08-11)

ai/skills/repo/standardize-repo/references/mode-update.md:

total lines 3,494
fenced sh/bash lines 1,882 (54% of the file)
fenced blocks 31
longest single block 1,196 lines
invocations of a shipped asset 5 (diff-template.sh ×2, verify-applied.sh ×1, shepherd's check-codex-cloud-review.sh ×2)

The skill does ship assets — diff-template.sh (80 KB),
verify-applied.sh (107 KB), detect-project-type.sh,
template-owned-files.txt. What is missing is the guarded update procedure
itself: §1 preparation and the read-only offline clone, the non-adoption
rehearsal, §2 apply / reconcile / promote, and the rollback. Those exist only
as prose the operator must transcribe into files before anything can run.

A 1,196-line fenced block is a program. It defines shell functions
(run_guarded_copier, guarded_checkout_id, nonadoption_*), maintains state
across steps in $GUARDED_STATE, and freezes Git object IDs that later steps
re-compare — none of which survives being pasted one block at a time.

This is specific to update mode, not a house style:

mode fenced shell lines
mode-update.md 1,882
mode-new-repo.md 168
mode-adopt-existing.md 87
mode-audit.md 13

Why it costs correctness, not just effort

The document is aware of this. It warns that its blocks "are written to survive
bash -eu", that they "get lifted piecemeal", that LC_ALL=C must be pinned
"per command, never a one-time export at the top of a section" — all of which
are mitigations for transcription, and all of which assume the operator
performs it faithfully.

Transcription is where defects enter. In one session updating three consumer
repos to v4.27.0 (#413 and siblings), the operator hand-transcribed §1/§2 into
scripts and introduced two parsing bugs of their own while doing adjacent §6
work — one of which reported 41 labels as about to be overwritten when the true
answer was zero. Neither bug was in the skill; both were in the copy. A shipped
runner removes that entire class, and test-skills.sh-style fixtures could
then exercise it.

Verify

S=ai/skills/repo/standardize-repo
awk '/^```(sh|bash)$/{b++;inb=1;n=0;next}
     /^```$/{if(inb){t+=n; if(n>max)max=n}; inb=0}
     inb{n++}
     END{printf "blocks=%d shell_lines=%d longest_block=%d\n", b, t, max}' \
  "$S/references/mode-update.md"
ls "$S/assets/"
grep -oE 'assets/[a-z-]+\.sh' "$S/references/mode-update.md" | sort -u

Output means: a large shell_lines / longest_block alongside an
assets/ listing that contains no update-mode runner means the recipe is still
prose and the violation stands. It is resolved when the guarded procedure is
invoked from assets/ and the fenced blocks shrink to the calls plus the
decisions an operator must make (the reviewed-answer choices, the conflict
adjudication) — which are genuinely prose and should stay that way.

Acceptance criteria

  • The guarded update procedure ships as one or more executables under
    assets/, covering at minimum §1 preparation + offline clone, the
    non-adoption rehearsal, and §2 apply / reconcile / promote.
  • mode-update.md invokes them instead of inlining them; what remains
    fenced is the operator's decisions, not the mechanism.
  • The rollback path is included, since it is the step where a mistranscribed
    guard is most destructive.
  • The runner is exercised by fixtures in the same style as the existing
    skills tests, so the recipe has regression coverage it cannot have today.
  • The reviewed-answer stop-and-review contract is preserved: the runner
    still refuses to proceed while any __REVIEW_REQUIRED__ sentinel stands,
    rather than defaulting them.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    layer:logicBusiness rules, handlers, calculationneeds-triageAwaiting triagetech-debtTechnical debt

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions