Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

## Why

Reproduced 2026-09-24 against a real, shared GitHub repo (`ExopenGitHub/portal`):
Reproduced 2026-09-24 against a real, shared GitHub repo (`example-org/other-repo`):

```
$ specsync -repo ExopenGitHub/portal https://github.com/ExopenGitHub/portal/issues/4304 -dry-run
$ specsync -repo example-org/other-repo https://github.com/example-org/other-repo/issues/12 -dry-run
```

Intent: pull/inspect a single issue. Actual result: specsync ran a full **live**
`sync` of every local OpenSpec change under the current directory (`~/dev/specsync`'s
`sync` of every local OpenSpec change under the current directory (this repo's
own ~80-item internal backlog) and created all of them as real issues on
`ExopenGitHub/portal` — a repo those changes have nothing to do with. `-dry-run` had
`example-org/other-repo` — a repo those changes have nothing to do with. `-dry-run` had
no effect whatsoever; every issue was actually created. Cleanup required manually
deleting issues #4370–#4450.
deleting the stray issues.

Two independent defects compounded:

Expand Down Expand Up @@ -63,7 +63,7 @@ successful bulk sync.
- **Print an unmissable pre-flight summary before any real (non-dry-run) write.**
Every real `sync` run should state, before doing anything: the resolved target
repo, the resolved spec-source directory, and the number of changes about to be
synced (`target: ExopenGitHub/portal — spec source: ~/dev/specsync/openspec (81
synced (`target: example-org/other-repo — spec source: ./openspec (81
changes) — 0 already linked, 81 new`). A human skimming this line would have
caught "81 new" against a repo they'd only ever pushed one issue to.
- **Regression test reproducing this incident's exact shape**: `specsync -repo
Expand Down Expand Up @@ -104,7 +104,7 @@ successful bulk sync.
positives that make the new guard itself untrustworthy.
- **Does the shadowed-flag scan need to know each flag's arity** (boolean vs
value-consuming) to correctly identify "the first non-flag token"? Yes — e.g.
`-repo ExopenGitHub/portal` is two tokens for one flag; the scan must walk the
`-repo example-org/other-repo` is two tokens for one flag; the scan must walk the
`FlagSet`'s registered flags (via `fs.VisitAll`) to know which names consume a
following value, mirroring how `flag.Parse` itself walks arguments, or it will
misidentify a flag's value token as "the first positional."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Tasks: reject-unconsumed-cli-args

Task 1 is the exact defect that caused the 2026-09-24 incident (81 live issues
created on `ExopenGitHub/portal` from an unrelated invocation). Task 2 is the
created on `example-org/other-repo` from an unrelated invocation). Task 2 is the
independent, more general defect that made `-dry-run` silently do nothing. Task 5
is the regression test proving both are actually fixed.

Expand All @@ -11,7 +11,7 @@ is the regression test proving both are actually fixed.
no legitimate positional arguments: `runSync`, `runAudit`, `runAuditTasks`,
`runValidate`, `runArchive`, `runIdeas`, `runIdea` (idea text is the one
expected positional — special-case it), and any others found during the
audit. Reproduced 2026-09-24: `specsync -repo ExopenGitHub/portal
audit. Reproduced 2026-09-24: `specsync -repo example-org/other-repo
<issue-url> -dry-run` silently ignored the URL as a stray argument, left
`-change` unset (meaning "sync everything"), and proceeded as a live full
sync.
Expand Down
Loading