fix: decide .github per file so templates stop shipping broken automation - #122
Merged
Merged
Conversation
…tomation `MIND_RULES` mapped `.github/*` to KEEP_SUB, which only replaces PyAutoLabs with YOURORG. Everything else passed through verbatim, so the public template arrived carrying instance automation that cannot run in the org it was spawned for — 13 failing runs in PyAutoMind-template. Owner substitution does not help: YOURORG is a literal placeholder, so the template's own spawn_drift run failed with `repository 'https://github.com/YOURORG/PyAutoMind/' not found`. Anything that clones or queries a sibling repo is broken on arrival, secrets or not. Adopts the fresh-repo invariant (spec rule 9): a workflow shipped into a template must be able to succeed on a freshly-spawned repo with no secrets and no sibling repos. Only lifecycle_drift.yml clears it — empirically the one green workflow in the template's history. - 9a lifecycle_drift.yml KEEP (self-contained, no owner reference at all) - 9b spawn_drift.yml SPECIAL:unscheduled — kept, `schedule:` stripped so it never auto-fails on an org with no *-template repos; dispatch + PR remain. Fails loudly if the trigger ever disappears upstream, so the rule cannot rot into a silent no-op. - 9c morning_status, morning_health, arxiv_papers, .github/scripts/** DROP - 9d everything else NO catch-all — UNMATCHED by design 9d is the part that matters most. A catch-all is fail-OPEN: a workflow added to Mind later rides it into the template with whatever schedule and secrets it has. The tripwire test caught exactly that against an earlier draft of this change that kept the fallback, so the fallback is gone — a new .github file now fails the run and gets an explicit human decision, like every other new file class. MEMORY_RULES gets the same treatment. validate.yml is self-contained and still ships (byte-identical, so no Memory drift), but its catch-all is closed too — leaving one fail-open door while shutting the other is a half-fix. Refs #121 Co-Authored-By: Claude Opus 5 <[email protected]>
The first draft matched any line starting with `schedule:`, so a `schedule:`
line inside a `run: |` shell block was rewritten into comments — silently
mangling the script. Found by stress-testing the transform against awkward YAML
rather than by the happy-path test, which passed throughout.
The strip now tracks the top-level `on:` mapping and only removes a direct
child of it. Flow style (`on: {schedule: ...}`) still fails loudly rather than
being guessed at, as does a workflow with no schedule at all.
Tests cover the run-block false positive, quoted `on` keys (YAML 1.1 coerces
bare `on` to True, so some repos quote it), comments inside the block, and CRLF.
Refs #121
Co-Authored-By: Claude Opus 5 <[email protected]>
Codex review findings, all verified against the real transform before fixing. 1. `pip install pytest` only, but the contract tests import PyYAML. setup-python gives a clean interpreter, so this would have failed at COLLECTION on the next CI run — the whole suite, not one test. Declares pyyaml. 2. `unscheduled_workflow_body()` deleted `on.workflow_call.inputs.schedule`, a legitimate input rather than a trigger: it matched `schedule:` at any depth under `on:`. Now matches only a DIRECT child of the top-level `on:` mapping. 3. Same function emitted INVALID YAML when a comment sat at the same indent as `schedule:` — block consumption stopped early and orphaned the `- cron` line. Blanks and comments are now consumed only when deeper content follows, so a comment introducing the NEXT key still travels with that key. 4. Memory's fail-closed rule was untested — every workflow fixture drove generate_mind. Adds test_memory_github_is_also_fail_closed, control-tested by reverting the rule to a catch-all and confirming it fails. 5. The docstring claimed byte-for-byte preservation, which is false: splitlines discards line terminators and the rejoin normalises CRLF to LF. Says so now. Also corrects the spec, which overclaimed. It said shipped workflows "must be able to succeed" and mandated a test asserting no `YOURORG/` reference — but rule 9b deliberately ships spawn_drift.yml, which clones `<owner>/*-template` and so fails on manual dispatch until the org publishes templates. The rule being protected is "nothing fails UNATTENDED", not "every human-invoked path succeeds"; asserting no `YOURORG/` would forbid shipping the generator at all. The invariant now states both conditions precisely and records what it does not require, so the next reader does not "fix" the gap by breaking rule 9b. Generated output is byte-identical to before these fixes — the shipped .github tree and spawn_drift triggers/jobs are unchanged. Refs #121 Co-Authored-By: Claude Opus 5 <[email protected]>
Jammy2211
pushed a commit
that referenced
this pull request
Aug 4, 2026
Jammy2211
added a commit
that referenced
this pull request
Aug 14, 2026
Jammy2211
added a commit
that referenced
this pull request
Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #121.
Overview
MIND_RULESmapped.github/*toKEEP_SUB, which only replacesPyAutoLabswithYOURORG. Everything else passed through verbatim, so the public template arrived carrying instance automation that cannot run in the org it was spawned for — 13 failing runs inPyAutoMind-template.Owner substitution does not help.
YOURORGis a literal placeholder, so the template's ownspawn_driftrun failed withrepository 'https://github.com/YOURORG/PyAutoMind/' not found. Anything cloning or querying a sibling repo is broken on arrival, secrets or not.The rule
Two conditions: no unattended trigger it cannot satisfy, and no configured secret (
GITHUB_TOKENis auto-provided and allowed). Evidence-backed by the template's own run history —lifecycle_drift.ymlis the one green workflow, and it is the one that clears the bar.lifecycle_drift.ymlspawn_drift.ymlschedule:stripped — generic machinery, but a fresh org has no*-templatereposmorning_status,morning_health,arxiv_papers,.github/scripts/**.githubMEMORY_RULESgets the same treatment; itsvalidate.ymlis self-contained and still ships byte-identical, so no Memory drift.9d is the part that matters
A catch-all is fail-open: a workflow added to Mind later rides it into the template with whatever schedule and secrets it has. The tripwire test caught exactly that against an earlier draft of this change that kept the fallback — so the fallback is gone. A new
.githubfile now fails the run and gets an explicit human decision, like every other new file class.Found by testing, not by reading
Three defects in the schedule-strip, each fixed and pinned:
schedule:line inside arun: |shell block was rewritten into comments, silently mangling the script;on.workflow_call.inputs.schedule— a legitimate input, not a trigger — was deleted, because the match was "anywhere underon:" rather than "direct child ofon:";schedule:ended block consumption early, orphaning the- cronline and emitting invalid YAML.Flow style (
on: {schedule: ...}) and a workflow with no schedule both fail loudly rather than being guessed at, so the rule cannot rot into a silent no-op.Independent review (Codex)
Five findings, all verified against the real transform before fixing. Two were the YAML defects above. Also:
pip install pytestonly, but the contract tests import PyYAML.setup-pythongives a clean interpreter, so this would have failed at collection on the next CI run — the whole suite, not one test.generate_mind. Now covered, and control-tested by reverting the rule and confirming the test fails.YOURORG/reference — but rule 9b deliberately shipsspawn_drift.yml, which clones<owner>/*-templateand will fail on manual dispatch until the org publishes templates. The rule being protected is "nothing fails unattended", not "every human-invoked path succeeds"; asserting noYOURORG/would forbid shipping the generator at all. The invariant now states both conditions precisely and records what it does not require, so the next reader does not "fix" the gap by breaking 9b.Verification
.githubtree andspawn_drifttriggers/jobs are unchanged.--checkpreview: 7 drifts on the Mind template (4 removals, the schedule-stripped workflow, the 2 files changed here), MemoryOK.API Changes
None.
spawn.pyis a repo-local generator with no importers outside this repo. New helperunscheduled_workflow_body(); no signature changes to existing functions.Ship notes
Heart YELLOW at ship time (score 70,
red_reasons: []) on a subset of the reason set the human acknowledged earlier today: workspace validation not passing, and tenant-firewall manifest drift. Neither relates to this change.Post-merge: re-run
/spawn --applyto publish, then confirm the template'spyauto-morning-health/pyauto-update-digest/pyauto-arxiv-papersworkflows are gone rather than merely disabled.🤖 Generated with Claude Code