3 Commits

Author SHA1 Message Date
Jakub Zych
a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00
Tom Boucher
779f67cb11 fix(#4378): mint collision-free SEED-YYMMDD-xxx seed ids instead of a shared count (#4754)
* test(#4378): regression tests for collision-free seed ids

* fix(#4378): mint collision-free SEED-YYMMDD-xxx ids, not a shared count

plant-seed derived the next seed id from 'ls .planning/seeds/SEED-*.md | wc -l'.
.planning/seeds/ is shared but each worktree only sees what has merged, so two
workstreams planting before either merges computed the same id and git merged
both files silently.

The id is now the local date plus a 3-char random base36 suffix -- the shape
.planning/quick/ already uses -- computed from knowledge one worktree has alone,
with a same-day regen guard. deriveSeedIdentity learns the new canonical grammar
alongside legacy SEED-NNN (whose parsing never changes), the --enrich parser and
the filename-prefix fallback keep the full new-format id, and the docs that
state the filename shape move to it.

The prefix fallback previously truncated any non-pure-numeric id at
'SEED-<digits>' -- the same one-id-two-answers ambiguity the issue reports,
reproduced one level down.

* fix(#4378): harden seed id generation per adversarial review

- parse-idea: anchor the --enrich extractor to the flag and capture the
  complete id, uppercase-tolerant; a leftmost 'SEED-[0-9]+' truncated an
  uppercase or malformed suffix to its date and enriched an arbitrary
  same-day seed via head -1. Ambiguous and unmatched targets now fail
  closed instead.
- generate-seed-id: tolerate the expected SIGPIPE under pipefail, abort
  loudly when the suffix cannot be drawn (an empty suffix would collapse
  every seed's id to the bare date), and run the same-day regen guard as
  a find existence test (the 'ls <glob>' shape trips the #3409 drift
  guard and degenerates under a stray nullglob).
- deriveSeedIdentity: document the theoretical legacy/new grammar
  ambiguity (6-digit counter + 3-char base36 slug, no frontmatter).
- changeset: state the residual same-day collision bound instead of
  implying zero.

Emitted-Drift-Ack-Growth: plant-seed.md — the counting step became hardened date+random generation with explicit failure modes; growth is the failure handling, not duplicated logic

* fix(#4378): address standards and spec review findings

- tests: move the allow-test-rule marker to its suppression site (the
  file-header placement was inert per CONTRIBUTING site-scoping); add
  width-boundary coverage (5/7-digit dates, 2/4-char suffixes pin the
  documented branch behavior); add a writer-to-reader parity property
  that parses the mint widths out of the shipped workflow so the two
  grammar owners cannot drift; cover uppercase ids end-to-end in the
  reader.
- plant-seed.md: draw/retry restructured as one loop with a loud
  terminal failure; SEED_SUFX renamed SEED_SUFFIX; regen guard drops
  the redundant head -1; the ambiguity error no longer advises an
  impossible 'complete id' for duplicate legacy ids.
- commands.cts: refresh the cmdListSeeds comment still describing
  SEED-NNN as the only canonical form.
- changeset: drop the audit claim the spec axis showed to be an
  overstatement (audit's id display is filename-derived, pre-existing).
- remove a stray untracked artifact file swept into the tree.

* test(#4378): correct boundary expectations to the module's real branch behavior

The first matrix run on the boundary tests caught my hand-trace of the
regex branches, not a module defect: the slug regex's alternation
backtracks to the legacy branch whenever the canonical branch cannot
complete (so the slug is the remainder after the legacy numeric
prefix), and the 7-digit case fails the canonical branch at its 7th
digit before the dash. Pin the verified values.

* docs(#4378): backfill changeset PR number

* fix(#4378): audit seed identity uses the canonical grammar

Review of this PR found the audit surface publishing a fused filename
stem (SEED-081-region for SEED-081-region.md) where list-seeds reports
the canonical id -- one id, two answers across surfaces, the same
ambiguity class the issue files. scanSeeds now derives identity through
the SAME deriveSeedIdentity the list-seeds gate uses (frontmatter id,
then filename id-prefix, then stem), and audit-open acknowledge
resolves --seed-id by scanning for the derived identity, falling back
to the literal stem so callers scripted against pre-canonical output
keep working. Roll-in per the fix-inline rule: found during this PR's
review, same seed-identity seam.

RED probe: pre-fix audit published seed_id SEED-081-region-becomes /
slug 081-region-becomes for a legacy seeded file; post-fix SEED-081 /
region-becomes, matching list-seeds.

* test(#4378): probe timeout uses the class norm after windows-lane timeout

The windows conformance shard failed its bounded sh -c probes at the
local 5000ms bound (cold sh.exe spawn under shard load) while the
identical code passed this PR's two earlier windows waves. The probe
now uses PROBE_TIMEOUT_MS from the class-norm module instead of a local
override, per the helpers/timeouts.cjs convention.

---------

Co-authored-by: sim <sim@local>
2026-09-15 11:41:29 -04:00
Joe
e12a2abfd8 feat(#441): add /gsd-capture --list-seeds for seed listing and audit (#722)
* feat(#441): add /gsd-capture --list-seeds for seed listing and audit

Seeds (.planning/seeds/SEED-NNN-slug.md) could only be created (--seed),
enriched (--enrich), or auto-surfaced at /gsd-new-milestone. There was no way
to browse or audit parked seeds on demand. This adds a read-only listing,
following the established --list → workflow pattern (per the approved scope on

- gsd-tools `list-seeds [status]` (cmdListSeeds in src/commands.cts): scans the
  seeds dir, returns { count, seeds[], summary } JSON with each seed's id,
  slug, status, scope, trigger_when, planted, title. Optional case-insensitive
  status filter. User-controlled content is sanitized (sanitizeForDisplay) and
  every path validated (requireSafePath); read-only. Independent of
  audit.scanSeeds, which only returns unimplemented seeds for the milestone surface.
- /gsd-capture --list-seeds routes to a new read-only list-seeds workflow that
  renders the seed table.

Closes #441

* chore(#441): point changeset fragment at PR #722

* test(#441): allowlist list-seeds test in prompt-injection scan

The test asserts that list-seeds neutralizes injection payloads
(<system>, [INST]) embedded in seed content, so the fixtures legitimately
contain those patterns — same as the sibling security tests already on the
allowlist.

* fix(#441): use canonical /gsd:capture colon form in list-seeds workflow

Claude-facing source (commands/, agents/, gsd-core/workflows/, ...) must use
the /gsd:<cmd> colon form per ADR/CONTEXT.md; the hyphen /gsd-<cmd> form is
retired there (enforced by bug-2543-gsd-slash-namespace.test.cjs). The new
list-seeds workflow used the hyphen form.

* docs(#441): sync help full.md + INVENTORY for --list-seeds

Adds the --list-seeds entry to the help reference (help/modes/full.md, per
bug-2954 argument-hint↔help parity) and registers the new list-seeds workflow
in docs/INVENTORY.md (88→89) and the generated INVENTORY-MANIFEST.json.

* docs(#441): add --list-seeds how-to + drop phantom statuses

Addresses CHANGES_REQUESTED on PR #722 (two documentation blockers):

- USER-GUIDE.md Seeds section (how-to): extend the task to cover
  auditing parked seeds on demand via --list-seeds, including the
  status filter — kept task-oriented per Diataxis how-to mode.
- CLI-TOOLS.md (reference): drop phantom statuses implemented|rejected
  from the list-seeds filter vocabulary; the system only produces
  dormant|active|triggered (src/audit.cts scanSeeds). Reference must
  be factually accurate and complete.

* fix(#441): guard non-scalar status frontmatter in cmdListSeeds

A seed with a bare `status:` line (extractFrontmatter yields {}) or a
`status: [a, b]` value (yields an array) crashed the whole audit list:
`(fm.status || 'dormant').toLowerCase()` throws a TypeError on a non-string.
Coerce every frontmatter read through a `fmStr` helper (mirrors the existing
`typeof fm.id === 'string'` guard), so a non-scalar status falls back to
dormant and non-scalar scope/trigger_when/title can no longer leak a raw
array/object into the JSON contract. Title is now capped symmetrically.

Adds regression coverage for empty and array `status:` and non-scalar fields.

Refs #441

* docs(#441): align list-seeds workflow status vocabulary

The load_seeds step listed `implemented` as an example status filter, but the
real seed vocabulary is dormant|active|triggered (src/audit.cts scanSeeds);
`implemented` has no producer. Matches the earlier CLI-TOOLS.md correction.

Refs #441

* refactor(#441): extract pure deriveSeedIdentity; match raw status in list-seeds

Pull the seed_id/slug derivation out of cmdListSeeds into a pure, exported
deriveSeedIdentity(stem, rawFmId) so the parsing contract can be property-tested
in-process (review minor #1). No behavior change.

Filter comparison now matches the raw lowercased status (both sides already
normalized) instead of sanitizeForDisplay(status); sanitization is for output,
not matching (review nit #3).

* test(#441): add fast-check property coverage and count=1 boundary for list-seeds

Adds tests/list-seeds.property.test.cjs with four fast-check properties over
deriveSeedIdentity (never-throws, string-only contract, canonical id->seed_id/slug
invariant, filename-prefix fallback) per RULESET.TESTS.property-based-testing
(review minor #1).

Adds an N==1 status-filter boundary case to list-seeds.test.cjs (review minor #2).

* chore(#441): sync runtime launcher snippet into list-seeds workflow

Propagate the current _runtime-launcher.snippet.sh (with non-Claude
runtime home probes) into the new list-seeds.md workflow via
scripts/sync-runtime-launcher.cjs, satisfying bug-891 (E) propagation.

* test(#441): record list-seeds.md in workflow size baseline (#1074)

---------

Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
2026-06-22 00:59:41 -04:00