Skip to content

Make Steps 6 and 7 safe to re-run under overwrite mode - #175

Merged
dmccoystephenson merged 2 commits into
mainfrom
fix/overwrite-mode-idempotent
Nov 6, 2026
Merged

dmccoystephenson merged 2 commits into
mainfrom
fix/overwrite-mode-idempotent

Conversation

@dmccoystephenson

@dmccoystephenson dmccoystephenson commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Summary

Overwrite mode is documented as "idempotently re-asserting the repo and registry entry" (Step 1 and README.md:57), but the commands in Steps 6 and 7 failed or duplicated work on a second run. The documented behavior is kept and the commands are brought into line with it.

  • Step 6, repo: the repo's visibility is checked with gh repo view before anything is pushed. A missing repo is created, a private one is reused, and a public one stops the run, so a generated skill cannot be published to a same-named public repo.
  • Step 6, remote: git remote add is run only when no origin exists. This deviates from the add-or-set-url form suggested in Overwrite mode is documented as idempotent, but Steps 6 and 7 are not #172, because set-url would rewrite the remote of a skill repo that was transferred. The skill repo for this project was moved that way.
  • Steps 4, 6, and 7, repo identity: the existing origin is resolved into <skill-repo>, which is used for the visibility check, the labels, and the catalog row. SKILL_REPO_OWNER in Step 4 follows the same remote, so a transferred skill repo is not pointed back at its old owner.
  • Step 6, commit: Regenerate <slug>-dev-loop skill is used under MODE=overwrite, and the MODE=fresh message is unchanged. generated-at differs on every run, so it is ignored when deciding whether the skill changed. If nothing else changed, the committed file is restored and no commit is made. This comparison does not use git diff -I, which requires git 2.30 and is not available in the 2.25.1 used by this dispatch environment.
  • Step 6, push: a rejected push is now stopped on and reported, and force-pushing is ruled out. This case is reachable when a skill directory has no git history but the remote does.
  • Step 6, labels: --force is passed to gh label create.
  • Step 7: an existing catalog row is replaced in place instead of being duplicated, and an unchanged catalog no longer fails the commit.
  • Step 4 (create-dev-loop.md half of Step 4 and CLAUDE.md still place the version comments at the top of the generated skill #173): the TEMPLATE_VERSION row now says "directly below the H1 heading" instead of "at the top". The CLAUDE.md:53 half of that issue is untouched because editing CLAUDE.md requires separate authorization, so Step 4 and CLAUDE.md still place the version comments at the top of the generated skill #173 stays open.

Closes #172

gardener interface: where the skill is written, what it is named, and what Step 6 creates are all unchanged. MODE=fresh against a repo that does not exist produces the same repo, remote, commit message, and labels as before, so this is not a breaking change for gardener. The new stop on a public repo replaces a case in which gh repo create already failed.

Retrofit: none is needed. Steps 4, 6, and 7 run at generation time and their text does not reach generated skills.

Research grounding

No RESEARCH.md finding applies. This corrects a mismatch between documented and prescribed behavior, with no empirical claim behind it, so no Implementations entry is added.

Doc sync check

  • README.md's "What it does" Step list still matches create-dev-loop.md's Steps 1:1
  • Every {{placeholder}} added or changed has a corresponding Step 4 substitution-table row (none were added or changed; <skill-repo> is an execution-time value, like <slug>)

Test plan

Nothing automated covers Steps 6 and 7, so a green doc-consistency job says nothing about these commands. None of the five CLAUDE.md checklist items was exercised. In particular:

  • A replay of the Step 6 git commands against a local bare repo was written but not run, since the dispatch's permission rules refused it. The git behavior in this PR therefore rests on the documented behavior of git.
  • gh label create --force was taken from the gh manual. gh label create --help was refused in this dispatch, as it was when Overwrite mode is documented as idempotent, but Steps 6 and 7 are not #172 was filed.
  • git branch -m main when already on main, which Step 6 now reaches on a re-run, was not tested either. A probe of it was refused.
  • The timestamp-insensitive comparison was not run. A read-only probe of it was refused.
  • The three outcomes of gh repo view --json isPrivate were not observed.

The overwrite run should confirm those points, including a stop against a public repo. A second overwrite with no change in between should then produce no new commit, no duplicate catalog row, and a clean working tree in the skill directory.

Issues not picked this cycle

A Stage A sweep of the non-template docs was also performed this cycle. RESEARCH.md ship dates were checked against mergedAt and matched, and no new drift was found in README.md, CONTRIBUTING.md, SECURITY.md, or the GitHub templates. The labels used by the issue templates could not be checked, since gh label list was refused.

This PR description was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).

🤖 Generated with Claude Code


drafted by Claude on behalf of Daniel Stephenson

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dmccoystephenson

Copy link
Copy Markdown
Member Author

Self-review rubric (head b88cdeb). This comment is not an independent review; it was produced by the session that authored the PR.

Universal items:

Repo-specific items:

  • Placeholder parity: PASS — no placeholder was added or changed, and check_docs.py passed. That check covers only the forward direction.
  • README Step parity: PASS — no Step was added, removed, or renamed.
  • Fence escaping: PASS (not applicable) — all edits sit after the template's closing fence, where fences are not escaped.
  • Phase numbering: PASS — the generated-skill template was not touched.
  • Version comments: PASS — the header is unchanged, and the Step 4 row now agrees with it.
  • Research grounding: PASS — the PR body states that no finding applies.
  • No back-ported specifics: PASS — no repo-specific command, name, or prefix was introduced.
  • gardener interface: PASS — paths, names, and what Step 6 creates are unchanged, and the PR body says so.
  • Retrofit note: PASS (not applicable) — no rule was promoted, and the changed text does not reach generated skills.
  • Behavioral validation: FAIL — marked UNVERIFIED in the PR body, so no auto-merge.

Points for the maintainer's review, none of which were changed:

  • create-dev-loop.md:691 — gh repo view failing for any reason, including a network error, falls through to gh repo create. That command fails loudly if the repo exists, so the failure mode is safe but the error may be misleading.
  • create-dev-loop.md:691 — MODE=fresh against an existing remote repo now continues past this line and stops at the push rejection instead. The stop is later but the outcome is the same.
  • create-dev-loop.md:752 — the Step 7 commit message stays Add <slug>-dev-loop skill even when a row was replaced. This was left alone to keep the fence simple.

Summary: the change reads correctly and CI is green, but the two FAIL items hold it for a real overwrite run, so it is not being merged by this dispatch.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The existing-repository check can publish sensitive generated content to a public repo, while overwrite runs can misdirect repository references and create unwanted timestamp-only commits.

3 open issues
What changed in this PR

This PR updates the skill generator’s repository and catalog setup to support repeated overwrite runs without recreating existing resources.

Changes:

  • Guard repository and remote creation, update existing labels, and stop on rejected pushes without force-pushing.
  • Replace existing catalog rows and skip commits when staged content is unchanged.
  • Clarify that template-version metadata belongs directly below the generated skill’s H1 heading.
File Description
create-dev-loop.md Adds rerun guards to Steps 6–7 and clarifies metadata placement in Step 4.

Review effort: Balanced

Comment thread create-dev-loop.md Outdated
Comment on lines +691 to +692
gh repo view "$(gh api user -q .login)/<slug>-dev-loop" >/dev/null 2>&1 || \
gh repo create <slug>-dev-loop --private --description "Autonomous dev loop skill for {{PROJECT_NAME}}"
Comment thread create-dev-loop.md Outdated
Comment on lines +701 to +702
git remote get-url origin >/dev/null 2>&1 || \
git remote add origin https://github.com/$(gh api user -q .login)/<slug>-dev-loop.git
Comment thread create-dev-loop.md Outdated
git remote add origin https://github.com/$(gh api user -q .login)/<slug>-dev-loop.git
git add <slug>-dev-loop.md
git commit -m "Initial commit: <slug>-dev-loop skill"
git diff --cached --quiet || git commit -m "<commit message for this MODE>"
…nd 7

Stop when an existing skill repo is public, use the existing origin's
owner and name for labels, the catalog row, and SKILL_REPO_OWNER, and
ignore the generated-at comment when deciding whether a regenerated
skill changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dmccoystephenson

Copy link
Copy Markdown
Member Author

The three Copilot findings on b88cdeb were assessed against the source and all were found valid. All three were fixed in 81882b6. The findings were read from the review summary, because the inline-comment API call was refused in this dispatch (#135), so their titles were used and their line anchors were not seen.

  • create-dev-loop.md:704 — "Verify existing dev-loop repository is private before pushing": fixed. The earlier gh repo view || guard removed the failure that gh repo create used to give on an existing repo, so a skill could have been pushed to a public repo of the same name. Visibility is now read first, and false stops the run without pushing or changing visibility.
  • create-dev-loop.md:699 — "Use the existing remote's owner and name consistently": fixed. origin was preserved, but labels, the Step 7 row, and SKILL_REPO_OWNER still used gh api user. All of them now follow the existing remote, through <skill-repo> in Steps 6 and 7.
  • create-dev-loop.md:721 — "Ignore generation timestamp when checking for no-op replay": fixed. The empty-diff check could never pass, since generated-at changes on every run. The comparison now excludes that line, and on a match the committed file is restored so that the update-mode uncommitted-changes check is not tripped later. git diff -I was avoided because it requires git 2.30 and 2.25.1 is in use here.

The self-review rubric was not re-run, as Phase 4 caps it at one pass. Its earlier maintainer note on gh repo view failures still applies, now as an explicit case in Step 6. Its note on MODE=fresh against an existing repo also still applies, except that a public repo now stops at the visibility check.

CI passed on 81882b6, along with python3 scripts/check_docs.py and 42 unit tests locally, but none of those execute Steps 6 and 7. Tests-fix and Behavioral validation therefore stay FAIL, and the PR stays held for a real overwrite run. The remaining checks are listed in the PR description.

This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Overwrite mode is documented as idempotent, but Steps 6 and 7 are not

2 participants