Skip to content

fix: decide .github per file so templates stop shipping broken automation - #122

Merged
Jammy2211 merged 3 commits into
mainfrom
feature/spawn-github-instance-automation
Aug 4, 2026
Merged

fix: decide .github per file so templates stop shipping broken automation#122
Jammy2211 merged 3 commits into
mainfrom
feature/spawn-github-instance-automation

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Closes #121.

Overview

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 cloning or querying a sibling repo is broken on arrival, secrets or not.

The rule

No workflow shipped into a template may fail unattended on a freshly-spawned repo.

Two conditions: no unattended trigger it cannot satisfy, and no configured secret (GITHUB_TOKEN is auto-provided and allowed). Evidence-backed by the template's own run history — lifecycle_drift.yml is the one green workflow, and it is the one that clears the bar.

rule file action
9a lifecycle_drift.yml KEEP — self-contained, no owner reference at all
9b spawn_drift.yml keep, schedule: stripped — generic machinery, but a fresh org has no *-template repos
9c morning_status, morning_health, arxiv_papers, .github/scripts/** DROP — sibling repo lists, organ workflow names, org secrets, strong-lensing vocabulary
9d anything else under .github no catch-all — UNMATCHED by design

MEMORY_RULES gets the same treatment; its validate.yml is 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 .github file 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:

  • a schedule: line inside a run: | 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 under on:" rather than "direct child of on:";
  • a comment at the same indent as schedule: ended block consumption early, orphaning the - cron line 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 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.
  • Memory's fail-closed rule was untested — every workflow fixture drove generate_mind. Now covered, and control-tested by reverting the rule and confirming the test fails.
  • The spec 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 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 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 9b.

Verification

  • 72 tests pass. Generated output is byte-identical before and after the review fixes — the shipped .github tree and spawn_drift triggers/jobs are unchanged.
  • Post-merge --check preview: 7 drifts on the Mind template (4 removals, the schedule-stripped workflow, the 2 files changed here), Memory OK.

API Changes

None. spawn.py is a repo-local generator with no importers outside this repo. New helper unscheduled_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 --apply to publish, then confirm the template's pyauto-morning-health / pyauto-update-digest / pyauto-arxiv-papers workflows are gone rather than merely disabled.

🤖 Generated with Claude Code

Jammy2211 and others added 3 commits August 4, 2026 19:14
…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 Jammy2211 added the pending-release Awaiting coordinated release label Aug 4, 2026
@Jammy2211
Jammy2211 merged commit cb04acf into main Aug 4, 2026
2 checks passed
@Jammy2211
Jammy2211 deleted the feature/spawn-github-instance-automation branch August 4, 2026 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release Awaiting coordinated release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: spawn's blanket .github/** rule ships broken instance automation

1 participant