Summary
scripts/ci/archive-old-specs.js processes archive candidates one at a time and starts remote/worktree mutations before validating the whole batch. If a later date-named directory is not a valid Zest spec (for example, it lacks spec.md) or zest-dev dump otherwise fails, earlier archive Issues have already been created and earlier directories have been removed in the ephemeral checkout, but the workflow exits before the PR step.
The next scheduled run checks out the unchanged default branch, finds the already-created archive Issues, removes those directories again locally, reaches the same invalid candidate, and fails again. Because selection is limited to the earliest ten directories, that candidate can permanently wedge archival and starve newer specs.
Reproduction
- Add two directories older than the archive cutoff:
specs/change/20260101-valid/spec.md
specs/change/20260102-runbook/notes.md with no spec.md
- Run the archive workflow/script with no existing archive PR.
- Observe that the valid spec gets an archive Issue and is removed locally.
- Observe that
zest-dev dump 20260102-runbook fails with Issue Spec Representation requires spec.md.
- The workflow stops before creating a PR.
- Run it again and observe the same blocker; the previously created Issue remains as a partial side effect.
Expected behavior
The archive job should validate the complete selected batch before creating Issues or deleting directories. If any candidate is invalid, it should fail with the offending path and leave both GitHub and the working tree untouched.
The candidate contract should also explicitly define how date-named non-Spec directories are handled: either exclude them deliberately, or reject them during preflight without partial side effects.
Suggested acceptance coverage
- A mixed valid/invalid batch causes no archive Issue creation and no directory deletion.
- The error names the invalid candidate and missing requirement.
- A failed candidate cannot indefinitely starve otherwise valid later specs without a clear remediation path.
- Existing archive Issues remain recoverable into one removal PR once the batch is valid.
- Validation exercises the public CLI behavior, ideally with
zest-dev dump --dry-run, before any remote mutation.
Summary
scripts/ci/archive-old-specs.jsprocesses archive candidates one at a time and starts remote/worktree mutations before validating the whole batch. If a later date-named directory is not a valid Zest spec (for example, it lacksspec.md) orzest-dev dumpotherwise fails, earlier archive Issues have already been created and earlier directories have been removed in the ephemeral checkout, but the workflow exits before the PR step.The next scheduled run checks out the unchanged default branch, finds the already-created archive Issues, removes those directories again locally, reaches the same invalid candidate, and fails again. Because selection is limited to the earliest ten directories, that candidate can permanently wedge archival and starve newer specs.
Reproduction
specs/change/20260101-valid/spec.mdspecs/change/20260102-runbook/notes.mdwith nospec.mdzest-dev dump 20260102-runbookfails withIssue Spec Representation requires spec.md.Expected behavior
The archive job should validate the complete selected batch before creating Issues or deleting directories. If any candidate is invalid, it should fail with the offending path and leave both GitHub and the working tree untouched.
The candidate contract should also explicitly define how date-named non-Spec directories are handled: either exclude them deliberately, or reject them during preflight without partial side effects.
Suggested acceptance coverage
zest-dev dump --dry-run, before any remote mutation.