From 8156f9151d61c38b421bc9de5391bdc64a9aabd8 Mon Sep 17 00:00:00 2001 From: AndreasS Date: Mon, 5 Oct 2026 09:13:54 +0200 Subject: [PATCH 1/2] fix(#179): restore topology command dispatch and fix stale soon badges Closes #179 --- cmd/specsync/main.go | 6 +++-- .../restore-topology-dispatch/proposal.md | 26 +++++++++++++++++++ .../restore-topology-dispatch/tasks.md | 2 ++ site/features.json | 12 +++------ 4 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 openspec/changes/restore-topology-dispatch/proposal.md create mode 100644 openspec/changes/restore-topology-dispatch/tasks.md diff --git a/cmd/specsync/main.go b/cmd/specsync/main.go index 6315e7e..4f12561 100644 --- a/cmd/specsync/main.go +++ b/cmd/specsync/main.go @@ -33,7 +33,7 @@ var knownSubcommands = map[string]bool{ "sync": true, "audit": true, "audit-tasks": true, "validate": true, "spinoff": true, "pr-body": true, "verify": true, "agent-help": true, "doctor": true, "idea": true, "ideas": true, "archive": true, - "epic": true, "adopt": true, + "epic": true, "adopt": true, "topology": true, } // knownConfusions maps a word someone might reach for by habit (e.g. git's @@ -94,7 +94,7 @@ func deprecatedSlugFlag(args []string) error { func main() { cmd, rest, err := resolveSubcommand(os.Args[1:]) if err != nil { - fmt.Fprintf(os.Stderr, "specsync: %v\n\nRun with no subcommand (optionally with flags) to sync, or use one of: pull, adopt, link, scan, trace, release-plan, changelog, install-skill, changes, set-stage, set-priority, note, audit, audit-tasks, validate, spinoff, pr-body, verify, idea, ideas, archive, epic\n", err) + fmt.Fprintf(os.Stderr, "specsync: %v\n\nRun with no subcommand (optionally with flags) to sync, or use one of: pull, adopt, link, scan, trace, release-plan, changelog, install-skill, changes, set-stage, set-priority, note, audit, audit-tasks, validate, spinoff, pr-body, verify, idea, ideas, archive, epic, topology\n", err) os.Exit(2) } @@ -151,6 +151,8 @@ func main() { runArchive(rest) case "epic": runEpic(rest) + case "topology": + runTopology(rest) default: runSync(rest) } diff --git a/openspec/changes/restore-topology-dispatch/proposal.md b/openspec/changes/restore-topology-dispatch/proposal.md new file mode 100644 index 0000000..44ea6e3 --- /dev/null +++ b/openspec/changes/restore-topology-dispatch/proposal.md @@ -0,0 +1,26 @@ +# Restore the topology command and fix stale "soon" badges on the site + +## Why +PR #174 (store support) was rebased from a branch that predated two pieces of +already-shipped work: the `topology` subcommand's dispatch wiring in +`cmd/specsync/main.go`, and the "See who's already working what" feature card +on specsync.se. The flat-diff reapplication silently dropped the `topology` +case from `knownSubcommands` and the `main()` switch, so `specsync topology` +now fails with "unknown subcommand" even though `runTopology` and all its +tests are still present and working. + +Separately, while reviewing the site after that merge: three feature cards +(design notes overflow #139, topology #168, adopt #160) still carry a "soon" +badge even though all three shipped weeks ago. + +## What Changes +- Restore `"topology": true` in `knownSubcommands`, the `case "topology": + runTopology(rest)` dispatch arm, and `topology` in the subcommand list + printed on an unknown-subcommand error. +- Drop the stale `"status": "soon"` / `"issue"` fields from the three + already-shipped feature cards in `site/features.json`. + +## Impact +- Affected code: `cmd/specsync/main.go`, `site/features.json` +- No spec delta: restores previously-specified, previously-tested behavior + that regressed in a merge; doesn't change any contract. diff --git a/openspec/changes/restore-topology-dispatch/tasks.md b/openspec/changes/restore-topology-dispatch/tasks.md new file mode 100644 index 0000000..fa5feec --- /dev/null +++ b/openspec/changes/restore-topology-dispatch/tasks.md @@ -0,0 +1,2 @@ +- [x] Restore topology to knownSubcommands and the dispatch switch +- [x] Drop stale soon/issue fields from the three shipped feature cards diff --git a/site/features.json b/site/features.json index 2e03a9a..3dee950 100644 --- a/site/features.json +++ b/site/features.json @@ -9,9 +9,7 @@ "group": "plan", "icon": "flow", "title": "Design notes survive the worktree", - "body": "A design.md renders as ## Design notes in the synced issue, so decisions made while planning aren't lost if the local worktree is force-removed. Oversized notes overflow to a linked issue comment instead of getting truncated.", - "status": "soon", - "issue": 139 + "body": "A design.md renders as ## Design notes in the synced issue, so decisions made while planning aren't lost if the local worktree is force-removed. Oversized notes overflow to a linked issue comment instead of getting truncated." }, { "group": "plan", @@ -23,9 +21,7 @@ "group": "plan", "icon": "flow", "title": "See who's already working what", - "body": "specsync topology joins every change with its tracker issue, git branch, and worktree across coordinated stores — a read-only check before an agent starts, so it doesn't duplicate work already in flight.", - "status": "soon", - "issue": 168 + "body": "specsync topology joins every change with its tracker issue, git branch, and worktree across coordinated stores — a read-only check before an agent starts, so it doesn't duplicate work already in flight." }, { "group": "plan", @@ -49,9 +45,7 @@ "group": "collaborate", "icon": "idempotent", "title": "Adopt an existing issue", - "body": "specsync adopt -issue 3691 -change my-change binds a change and an issue that already exist independently, writing the ref cache before touching the issue body so the link holds immediately instead of racing search indexing.", - "status": "soon", - "issue": 160 + "body": "specsync adopt -issue 3691 -change my-change binds a change and an issue that already exist independently, writing the ref cache before touching the issue body so the link holds immediately instead of racing search indexing." }, { "group": "collaborate", From 330bf29fb5aec35e1dad10afdc581fb20955abd5 Mon Sep 17 00:00:00 2001 From: AndreasS Date: Mon, 5 Oct 2026 09:17:14 +0200 Subject: [PATCH 2/2] docs(#181): trim low-value feature cards from the landing page Closes #181 --- .../trim-feature-card-sprawl/proposal.md | 25 +++++++++++++++++++ .../changes/trim-feature-card-sprawl/tasks.md | 1 + site/features.json | 20 +-------------- 3 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 openspec/changes/trim-feature-card-sprawl/proposal.md create mode 100644 openspec/changes/trim-feature-card-sprawl/tasks.md diff --git a/openspec/changes/trim-feature-card-sprawl/proposal.md b/openspec/changes/trim-feature-card-sprawl/proposal.md new file mode 100644 index 0000000..54ec624 --- /dev/null +++ b/openspec/changes/trim-feature-card-sprawl/proposal.md @@ -0,0 +1,25 @@ +# Trim low-value feature cards from the landing page + +## Why +site/features.json has grown to one card per shipped PR rather than curated +visitor-facing messaging. Several entries describe internal implementation +details or flag-behavior nuances that read as changelog entries rather than +reasons to try the tool: + +- "Explicit repo resolution" and "Per-repository board" — resolution + precedence order (`-repo` flag → `gh repo set-default` → `origin`, etc.): + reference-doc material, and "Per-repository board" duplicated "Projects + board sync" right above it. +- "No label noise by default" — a specific PR's behavior change (labels + opt-in via `-labels`), not a feature a new visitor evaluates on. + +## What Changes +- Remove "Explicit repo resolution", "Per-repository board", and "No label + noise by default". +- Retitle "Collapsed by default" → "A clean issue, not a wall of text" to + lead with the visible benefit instead of the implementation mechanism. +- Already-shipped features keep full documentation in README.md; this only + trims the landing page's card list. + +## Impact +- Affected: site/features.json only. No code or behavior change. diff --git a/openspec/changes/trim-feature-card-sprawl/tasks.md b/openspec/changes/trim-feature-card-sprawl/tasks.md new file mode 100644 index 0000000..4b00c4b --- /dev/null +++ b/openspec/changes/trim-feature-card-sprawl/tasks.md @@ -0,0 +1 @@ +- [x] Remove the three low-value cards, retitle one for benefit-first framing diff --git a/site/features.json b/site/features.json index 3dee950..b7df384 100644 --- a/site/features.json +++ b/site/features.json @@ -83,18 +83,6 @@ "title": "Archive audit", "body": "specsync audit cross-references archived changes against GitHub PRs to find archived-but-unmerged work. Add -mark-shipped to record the final lifecycle step." }, - { - "group": "collaborate", - "icon": "idempotent", - "title": "Explicit repo resolution", - "body": "specsync resolves the target repository deterministically: -repo flag → gh repo set-default → origin. Fork-parent writes are refused by default; use -repo to override." - }, - { - "group": "collaborate", - "icon": "board", - "title": "Per-repository board", - "body": "Board resolution per-repository: -project flag → openspec/specsync.yml → no board. No global default; each repo syncs only to its own declared board." - }, { "group": "collaborate", "icon": "idempotent", @@ -128,13 +116,7 @@ { "group": "collaborate", "icon": "state", - "title": "Collapsed by default", + "title": "A clean issue, not a wall of text", "body": "A synced issue shows title and task checklist first — Proposal, Original ask, and Discoveries render inside collapsed <details> blocks, one click away, nothing removed." - }, - { - "group": "collaborate", - "icon": "idempotent", - "title": "No label noise by default", - "body": "specsync and stage:<stage> labels are opt-in via -labels — neither is read back by specsync itself, so they aren't added unless you actually want native-label filtering." } ]