Files
msd-core/docs/contributing/response-language-coverage.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

5.0 KiB

Response-language coverage

Every workflow file must instruct the model to honour response_language in the prose a user reads. npm run lint:response-language (chained into npm run lint:ci) enforces it across the whole catalog. This page is the how-to and the rationale; the mechanics live in scripts/lint-response-language-coverage.cjs and its suite, tests/response-language-coverage.test.cjs. The shipped requirements are REQ-LANG-01..04 in docs/features/response-language-config.md.

The problem this gate exists for

A directive worded around questions, prompts, and explanations covers the answer and leaves the running commentary in English. The user then reads a translated answer wrapped in English status updates, progress notes, and findings — which is the defect #2529 reports, not a stylistic preference. Before this gate, 44 workflows carried exactly that wording and the older lint certified it as coverage, so the gate was legitimising the bug it was meant to catch.

Hence the discriminator: a directive counts only if it names the narration class. Naming means the word narration or the phrase between tool calls. Enumerating members of the class — status updates, progress notes, findings — without naming the class does not satisfy it, because the enumeration reads as a closed list and the class is open (REQ-LANG-04).

The four coverage forms

Form What it looks like When it applies
Shared reference @~/.claude/msd-core/references/response-language-directive.md on its own line The file is loaded eagerly — a top-level workflow. Preferred: one place to maintain the wording for the 42 files that take it.
Own inline directive One line carrying the directive in the file's own words The file already has one, or its prose needs local phrasing. Must pass all four predicates (below).
Pinned inline directive The canonical line, byte for byte A lazily-loaded mode/step/template that cannot prove inheritance.
Inherited nothing in the file itself A fragment whose parent workflow dispatches it from a read/execute context and is itself covered.

Which form to use

Answer in this order:

  1. Is the file loaded eagerly? Take the shared reference. An @-line is expanded when the file is loaded, so this is the cheapest correct answer for a top-level workflow.
  2. Is it a fragment under <workflow>/{modes,steps,templates}/? Then check whether <workflow>.md dispatches this exact path from a read/execute context and is itself covered. The catalog writes that stub two ways — rooted at msd-core/workflows/, or relative to the catalog — and either one counts; a path with no read/execute/run verb ahead of it on the same line is a mention, not a dispatch, and proves nothing. If both hold, the fragment inherits — add nothing. The parent's directive is already in the loaded context by the time the fragment is read, so a second copy buys no coverage and gives the wording somewhere to drift.
  3. Otherwise the fragment carries the pinned line, and its path joins EXACT_INLINE_DIRECTIVE_WORKFLOWS in the lint. Do not reach for the @-reference here: an @-line inside a file that is itself read later is inert — it is text at that point, not an import.

Rule 2 decides the set in rule 3, and the suite enforces the boundary in both directions: a pinned path that would have inherited fails a pinned workflow is one that could not have inherited instead.

The pinned line

Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.

Byte for byte, on its own line. A pinned file may also switch to the shared reference if it ever becomes eagerly loaded — that is strictly better and the lint accepts it.

What an inline directive must contain

A single line must satisfy four independent predicates:

  1. the token response_language,
  2. an action verb — apply, use, present, translate, …,
  3. a user-output noun — prose, output, questions, findings, …,
  4. the narration class — narration or between tool calls.

All four on one line. The check is textual, not semantic: it reads vocabulary, not polarity.

When the lint reds

Message What to do
N workflow(s) have no response-language coverage Pick a form from the table above for each listed path.
N shared directive reference(s) no longer carry an actionable directive The reference itself was weakened. Fix the reference — one edit re-covers every file that imports it.
cannot read the workflow directory / no workflow files found under Discovery failed. The lint fails closed on purpose: a run that inspected zero workflows cannot establish coverage.

Run it locally before pushing:

npm run lint:response-language