Files
msd-core/docs/features/reachable-lint-rules-and-non-destructive-quick-task-append.md
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

52 lines
3.4 KiB
Markdown

---
id: 3951
title: Reachable Lint Rules and a Non-Destructive Quick-Task Append
group: v1.7.0 Features
---
**Purpose:** Make two ESLint rules cover the code they were written to govern, and stop
`quick-tasks-append` from overwriting curated `progress.*` values on a body-only write.
**What changed:**
- **`local/no-adhoc-markdown-parsing` reaches its whole registered surface.** The rule short-circuited
unless a file's path matched a flat `src/*.cts` pattern, so it **self-gated on its own filename**.
Two consequences: 28 `.cts` files in `src/` subdirectories sat inside the `src/**/*.cts` glob it was
registered on and were silently skipped, and the rule could not be extended by configuration at all —
widening the glob alone left it inert. Both halves now move together, and a test pins that the gate
and the registration agree in *both* directions.
- **The rule now also covers `tests/**` and `scripts/**`**, which surfaced **80 hand-rolled markdown
parses across 43 test files**. Seventy are routed through the existing `markdown-sectionizer` and
`markdown-table` seams; ten are suppressed with a stated reason (six of those are a shell-pipe
detector whose regex merely resembles a table).
- **`local/no-adhoc-regex-escape` sees property access.** Its unsafe-`new RegExp` arm examined only
bare identifiers, so `new RegExp(obj['key'])` — the shape runtime data actually arrives in — was
invisible. That is why it never fired on a known ReDoS. It now inspects `MemberExpression`, with an
exemption keyed strictly on the property being `source` (18 safe sites), plus provenance exemptions
for `_SOURCE` constants reached through a required module (3 sites).
- **`quick-tasks-append` can write the canonical row.** Optional `--quick-id`, `--slug` and
`--directory` let a caller that has a real quick task emit the same row `/msd-quick` renders. Omit
them — as `fast.md` does, having neither an id nor a directory — and the row is byte-identical to
before.
- **A body-only append no longer re-derives progress.** The route was the only body-only STATE.md
writer not passing `{ resync: false }`, so appending one row triggered a full re-derive of the
disk-derived `progress.*` frontmatter and replaced curated values. Reproduced: a project with two
real phase directories and a curated `total_phases: 25` collapsed to `2` on append.
**Found by the widening:** `tests/config-field-docs.test.cjs` asserted that
`workflow.subagent_timeout`'s documented default is not `600` — but read the **Type** column instead
of **Default**, so it compared `'number'` against `'600'` and could never fail. The guard against
regressing to the old seconds-based default had been inert. It is now row-scoped and real.
**Known limits:**
- #3426 and #3239 are **not** closed by this. Their hand-rolled scans in
`tests/package-legitimacy-gate.test.cjs` are built from line filters and `split('|')`, not the
regex-literal fingerprints this rule detects — measured at zero violations even with the gate
bypassed. They need new detectors, which is a separate design.
- The 10 suppressions are suppressions, not fixes. Each names why the raw markdown text is the
subject of that assertion.
- The `src/` subdirectory hole was **latent** — zero violations existed there when it was fixed. It is
closed because "no violations today" is not a property that keeps holding, not because it was
hiding anything.