You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two WP 5.1 checks have now shipped carrying a defect of one shape: §4 specifies an input envelope and a verdict table, but not the grammar the verdict ranges over, so the implementer invents one and the frozen fixture pack pins the invention.
Both were found after the code and its frozen fixtures existed, which is the expensive moment. #96 was then found by reading §4 against the seed before #25 built anything — the same class, a fraction of the cost.
This issue is the result of applying that same read to every remaining unbuilt check: #26, #27, #28, #29. It records ten findings. Nothing here is discovered by running code; all of it is settled by deciding.
F1 — No row-correspondence rule. (Highest severity: this is the #91 hole verbatim, on the check's central condition.)
fail reads "Any byte of an existing row changed." Deciding which head row is a given base row requires a pairing rule, and §4 states none. The two available readings disagree on the case the check exists for:
Pairing
A single row inserted mid-table
By index
Every row below it re-indexes → reads as mass modification → fail
By key (e.g. the Version cell)
Reads as an append landing out of order → warn
Both are defensible. An implementer must choose, and the fixture pack will pin the choice.
F2 — No version-ordering rule.
warn requires "a version that sorts below its predecessor." Nothing in the repository orders versions, and the one landed precedent runs the other way: scripts/validators/loose-pointer-drift.js compares by exact string equality after stripping one leading v and deliberately never orders. So v1.10 against v1.9 resolves however the implementer guesses — semver or lexical, with opposite results.
F3 — The table shape reaches a governed project through no channel.
options.table_heading defaults to "Appendix — Revision Record", and the warn condition needs a Version column and a Date column. That shape is stated only in CONTRIBUTING.md — "columns | Version | Date | Change |" — which is this repository's contributor documentation and is not shipped to anyone who installs the plugin. skills/cadence-method/scaffold/ contains constitution.md, directives.md, gate-tiers.json, manifest.json, and registrations.md, and no governed-document template; references/gate-checks.md states the append-only rule with no table shape. The check's defaults therefore encode a convention consumers are never told.
F4 — #28's body over-claims relative to the sheet.
The issue requires failing on rows "modified, deleted, or reordered"; §4's fail covers only a byte change to an existing row. Deletion and reordering cannot be detected at all without F1's identity rule. Whichever way F1 resolves, the two texts must be reconciled.
F5 — It re-implements a landed, fixture-pinned check, which §2 forbids in terms.
Its fail includes "a quotation whose evidence class names a date that the tag does not carry." Landed evidence-tag-grammar (#20) already fails "a class whose required date or parameter is missing or malformed", reading the same seeded references.evidence_classes. §2 states: "Nothing else in the repository re-implements a shipped check: a second, unfixtured implementation is exactly the divergence R-2 names."
This needs a scoping decision, not deletion by default: the section heading claims "pairing, attribution, and dating only", so quotation-scoped dating may be deliberate — but then the overlap with evidence-tag-grammar's broader claim scan must be recorded as deliberate rather than left to collide.
F6 — "Attribution" is defined nowhere in the repository.
fail fires on "a quotation with no attribution"; warn on "an attribution that names a source the artifact does not otherwise cite", which additionally needs a citation grammar and a name-matching rule. A repository-wide search finds the word only in prose about what a green gate proves (method §9, AC-9.4, SKILL.md, this sheet's own §8). No syntax, no position rule, no worked example. This is the purest instance of the #78/#91 class in the sweep.
F7 — A verdict depends on an input the section gives it no way to fail on.
Deciding "a date wherever its evidence class requires one" requires the seeded evidence-class reference, and §2 says a missing required key produces a skip. evidence-tag-grammar carries skipped: unavailable for exactly that condition. quotation-symmetry's table has four verdict rows and no unavailable, so a missing or unparseable reference has no legal verdict. Resolving F5 resolves this; if the dating clause stays, the fifth row is required (and §3's matrix cell moves from 4 rows to 5).
F8 — skipped: not-applicable fires on a declaration mechanism that does not exist.
The condition is "The artifact declares no derived render" — the switch deciding whether the check runs at all. No declaration mechanism is defined anywhere: outside this sheet, the only mention of a derived render is AC-9.2's parenthetical. Meanwhile the input shape receives options.render_path from the caller, leaving it ambiguous whether the artifact declares anything at all.
The manifest row is the natural home, so this should be folded into #96's schema decision rather than decided twice.
F9 — The producer comparison is undefined, and the normalization deletes its input.
warn fires when "the committed render's recorded producer differs from the version preflight resolved."text-extract-v1 explicitly drops producer metadata, so the producer must be read on a separate path the sheet does not describe; and "differs" is undefined between a PDF Producer string and a preflight record of shape {binary, version}. Low severity — it only separates warn from pass — but it is a verdict resting on an unstated comparison.
F10a — A direct internal contradiction, already propagated into the issue.
The section's opening states the severity-to-verdict mapping is "pinned in the adapter, not inherited from the tool, so a tool upgrade cannot change a verdict without a recorded change (R-2)." The input shape places it in options.severity_map, caller-supplied — where any caller may flip "warning": "fail" to "warn" and change a verdict with no recorded change, which is exactly what the R-2 rationale claims is prevented.
#29 carries both readings in one body: its acceptance criteria say "pinned in options.severity_map", while its own correction note says "pinned in the adapter." One of the two is wrong and the issue cannot be built until it is settled.
F10b — The diagnostic vocabulary is implicitly bound to a tool the sheet declines to name.
The default map's keys — error | warning | info | style — are one specific linter's severity names, in a §5 that binds shell-lint as a role precisely so no binary enters by the side door. The normalized diagnostic shape the adapter hands the validator (path, line, code, severity) is undefined, so #30 and #29 have no contract between them.
What the sweep found clean
Recorded so a later reader knows these were checked rather than skipped:
§3's completeness matrix is accurate for all five unbuilt checks — option counts, verdict-row counts, edge-case bullet counts, and fixture counts each match their section. (F7 would move quotation-symmetry from 4 rows to 5 if the dating clause is kept.)
render-fidelity's text-extract-v1 is the best-specified rule set in §4: ordered, complete, and fixture-pinnable as written.
The quotation-symmetry method divergence — method §291 places it as a Draft-zone advisory lint, this sheet makes it a Candidate-gate blocking check — is already recorded at the section head and is carried by AC-9.2. Deliberate, not drift.
Why this is a decision rather than an implementer's judgment
Every finding above sits on a verdict condition. An implementer handed any one of them must invent a rule, and the frozen fixture pack shipped alongside then pins the invention as though it were specified — which is precisely how #78 and #91 became expensive. F1 is the sharpest case: the two readings disagree on a mid-table insertion, which is the realistic FR-12 violation, so the check would be pinned to a behaviour nobody chose on the case it exists for.
None of the five is built yet. The whole set can be settled for the cost of reading and deciding.
Requested change
Amend docs/validator-spec-sheet.md §4 so that each finding above is answered in terms a second implementer could reproduce without reading a script, and reconcile #26, #28, and #29 with the result. Specifically:
State the revision-row correspondence rule (F1) — index-paired or key-paired, with the key named if key-paired — and state the expected verdict for a mid-table insertion.
State the version-ordering rule (F2), or rewrite the warn condition to need no ordering. If ordering is adopted, say explicitly how it relates to loose-pointer-drift's equality-only comparison, so two checks do not treat version tokens incompatibly.
Give the revision-table shape a home a governed project actually receives (F3) — a scaffold template, a runtime reference, or an explicit statement that the shape is supplied per project through options and the defaults are this repository's own.
Settle the quotation-symmetry / evidence-tag-grammar boundary (F5) — drop the evidence-class dating clause, or keep it scoped to quotations and record the overlap as deliberate.
Define an attribution (F6) — its syntax, its position relative to the quotation it attributes, and the rule matching it against the artifact's other citations for the warn.
Add quotation-symmetry's skipped: unavailable row if the dating clause is kept (F7), and update §3's matrix cell.
Re-opening any of the six landed checks or their frozen fixture packs.
Re-litigating the recorded quotation-symmetry method divergence.
Sequencing
Before #26, #28, and #29. After any of them, that check's decision has a fixture pack voting against changing it — the position #78 and #91 are in now. #27 is additionally blocked on #30 regardless, and its F8 travels with #96.
The three findings that block a build outright are F1, F5, and F10a; the rest can land in the same amendment without gating anything further.
Acceptance criteria
§4's revision-row-immutability section states the row-correspondence rule and the expected verdict for a mid-table insertion.
The version-ordering question is answered — a rule stated, or the warn condition rewritten to need none — and its relationship to loose-pointer-drift's equality-only comparison is stated either way.
The revision-table shape is reachable by a governed project, or the sheet records that it is supplied per project and the defaults are this repository's own.
The method governs the sheet (D-4). docs/reference/source/ is read-only.
Introduce no identifier without defining it in the authority document in the same change (FR-10). This issue introduces none; an amendment that needs one must carry its definition.
Any decision must leave the six landed checks and their frozen fixture packs valid. F2 in particular touches a surface loose-pointer-drift already pinned.
No new external tool without an NFR-3 entry, a pinned version, and a preflight check, in one change (NFR-1, NFR-3). F10b specifies an interface shape only and binds nothing.
Work package: WP 1.3 correction (WP 5.1 follow-up) · Phase: 5.0 · Traces: FR-8, FR-12, FR-18, NFR-3, NFR-6, R-2, AC-9.2, AC-9.4, AC-12.3, AC-13.1, US-12, US-13 · Precedes: #26 (
quotation-symmetry), #28 (revision-row-immutability), #29 (tooling-shell-lint) · Related: #96 (the same class, for #25), #30 (role bindings), #27 (render-fidelity) · Owner document:docs/validator-spec-sheet.md§4Problem statement
Two WP 5.1 checks have now shipped carrying a defect of one shape: §4 specifies an input envelope and a verdict table, but not the grammar the verdict ranges over, so the implementer invents one and the frozen fixture pack pins the invention.
Both were found after the code and its frozen fixtures existed, which is the expensive moment. #96 was then found by reading §4 against the seed before #25 built anything — the same class, a fraction of the cost.
This issue is the result of applying that same read to every remaining unbuilt check: #26, #27, #28, #29. It records ten findings. Nothing here is discovered by running code; all of it is settled by deciding.
Findings
revision-row-immutability(#28)F1 — No row-correspondence rule. (Highest severity: this is the #91 hole verbatim, on the check's central condition.)
failreads "Any byte of an existing row changed." Deciding which head row is a given base row requires a pairing rule, and §4 states none. The two available readings disagree on the case the check exists for:failVersioncell)warnBoth are defensible. An implementer must choose, and the fixture pack will pin the choice.
F2 — No version-ordering rule.
warnrequires "a version that sorts below its predecessor." Nothing in the repository orders versions, and the one landed precedent runs the other way:scripts/validators/loose-pointer-drift.jscompares by exact string equality after stripping one leadingvand deliberately never orders. Sov1.10againstv1.9resolves however the implementer guesses — semver or lexical, with opposite results.F3 — The table shape reaches a governed project through no channel.
options.table_headingdefaults to"Appendix — Revision Record", and thewarncondition needs aVersioncolumn and aDatecolumn. That shape is stated only inCONTRIBUTING.md— "columns| Version | Date | Change |" — which is this repository's contributor documentation and is not shipped to anyone who installs the plugin.skills/cadence-method/scaffold/containsconstitution.md,directives.md,gate-tiers.json,manifest.json, andregistrations.md, and no governed-document template;references/gate-checks.mdstates the append-only rule with no table shape. The check's defaults therefore encode a convention consumers are never told.F4 — #28's body over-claims relative to the sheet.
The issue requires failing on rows "modified, deleted, or reordered"; §4's
failcovers only a byte change to an existing row. Deletion and reordering cannot be detected at all without F1's identity rule. Whichever way F1 resolves, the two texts must be reconciled.quotation-symmetry(#26)F5 — It re-implements a landed, fixture-pinned check, which §2 forbids in terms.
Its
failincludes "a quotation whose evidence class names a date that the tag does not carry." Landedevidence-tag-grammar(#20) already fails "a class whose required date or parameter is missing or malformed", reading the same seededreferences.evidence_classes. §2 states: "Nothing else in the repository re-implements a shipped check: a second, unfixtured implementation is exactly the divergence R-2 names."This needs a scoping decision, not deletion by default: the section heading claims "pairing, attribution, and dating only", so quotation-scoped dating may be deliberate — but then the overlap with
evidence-tag-grammar's broader claim scan must be recorded as deliberate rather than left to collide.F6 — "Attribution" is defined nowhere in the repository.
failfires on "a quotation with no attribution";warnon "an attribution that names a source the artifact does not otherwise cite", which additionally needs a citation grammar and a name-matching rule. A repository-wide search finds the word only in prose about what a green gate proves (method §9, AC-9.4, SKILL.md, this sheet's own §8). No syntax, no position rule, no worked example. This is the purest instance of the #78/#91 class in the sweep.F7 — A verdict depends on an input the section gives it no way to fail on.
Deciding "a date wherever its evidence class requires one" requires the seeded evidence-class reference, and §2 says a missing required key produces a skip.
evidence-tag-grammarcarriesskipped: unavailablefor exactly that condition.quotation-symmetry's table has four verdict rows and nounavailable, so a missing or unparseable reference has no legal verdict. Resolving F5 resolves this; if the dating clause stays, the fifth row is required (and §3's matrix cell moves from 4 rows to 5).render-fidelity(#27)F8 —
skipped: not-applicablefires on a declaration mechanism that does not exist.The condition is "The artifact declares no derived render" — the switch deciding whether the check runs at all. No declaration mechanism is defined anywhere: outside this sheet, the only mention of a derived render is AC-9.2's parenthetical. Meanwhile the input shape receives
options.render_pathfrom the caller, leaving it ambiguous whether the artifact declares anything at all.The manifest row is the natural home, so this should be folded into #96's schema decision rather than decided twice.
F9 — The producer comparison is undefined, and the normalization deletes its input.
warnfires when "the committed render's recorded producer differs from the version preflight resolved."text-extract-v1explicitly drops producer metadata, so the producer must be read on a separate path the sheet does not describe; and "differs" is undefined between a PDFProducerstring and a preflight record of shape{binary, version}. Low severity — it only separateswarnfrompass— but it is a verdict resting on an unstated comparison.tooling-shell-lint(#29)F10a — A direct internal contradiction, already propagated into the issue.
The section's opening states the severity-to-verdict mapping is "pinned in the adapter, not inherited from the tool, so a tool upgrade cannot change a verdict without a recorded change (R-2)." The input shape places it in
options.severity_map, caller-supplied — where any caller may flip"warning": "fail"to"warn"and change a verdict with no recorded change, which is exactly what the R-2 rationale claims is prevented.#29 carries both readings in one body: its acceptance criteria say "pinned in
options.severity_map", while its own correction note says "pinned in the adapter." One of the two is wrong and the issue cannot be built until it is settled.F10b — The diagnostic vocabulary is implicitly bound to a tool the sheet declines to name.
The default map's keys —
error | warning | info | style— are one specific linter's severity names, in a §5 that binds shell-lint as a role precisely so no binary enters by the side door. The normalized diagnostic shape the adapter hands the validator (path, line, code, severity) is undefined, so #30 and #29 have no contract between them.What the sweep found clean
Recorded so a later reader knows these were checked rather than skipped:
quotation-symmetryfrom 4 rows to 5 if the dating clause is kept.)render-fidelity'stext-extract-v1is the best-specified rule set in §4: ordered, complete, and fixture-pinnable as written.Why this is a decision rather than an implementer's judgment
Every finding above sits on a verdict condition. An implementer handed any one of them must invent a rule, and the frozen fixture pack shipped alongside then pins the invention as though it were specified — which is precisely how #78 and #91 became expensive. F1 is the sharpest case: the two readings disagree on a mid-table insertion, which is the realistic FR-12 violation, so the check would be pinned to a behaviour nobody chose on the case it exists for.
None of the five is built yet. The whole set can be settled for the cost of reading and deciding.
Requested change
Amend
docs/validator-spec-sheet.md§4 so that each finding above is answered in terms a second implementer could reproduce without reading a script, and reconcile #26, #28, and #29 with the result. Specifically:warncondition to need no ordering. If ordering is adopted, say explicitly how it relates toloose-pointer-drift's equality-only comparison, so two checks do not treat version tokens incompatibly.optionsand the defaults are this repository's own.fail(F4).quotation-symmetry/evidence-tag-grammarboundary (F5) — drop the evidence-class dating clause, or keep it scoped to quotations and record the overlap as deliberate.warn.quotation-symmetry'sskipped: unavailablerow if the dating clause is kept (F7), and update §3's matrix cell.render-fidelity'sskipped: not-applicablecondition.Non-goals
documents[]row schema and artifact identity key. That is WP 5.1 follow-up · Define the manifest document-row schema and artifact identity before #25 builds manifest-registry-consistency #96; only F8 is added to it here.Sequencing
Before #26, #28, and #29. After any of them, that check's decision has a fixture pack voting against changing it — the position #78 and #91 are in now. #27 is additionally blocked on #30 regardless, and its F8 travels with #96.
The three findings that block a build outright are F1, F5, and F10a; the rest can land in the same amendment without gating anything further.
Acceptance criteria
revision-row-immutabilitysection states the row-correspondence rule and the expected verdict for a mid-table insertion.warncondition rewritten to need none — and its relationship toloose-pointer-drift's equality-only comparison is stated either way.failconditions.quotation-symmetry/evidence-tag-grammarboundary is settled, and any retained overlap is recorded as deliberate with its reason.warnneeds.quotation-symmetry's verdict rows and §3's matrix cell agree, whichever way F5 and F7 resolve.render-fidelity'sskipped: not-applicablecondition names a declaration mechanism that exists, or points at WP 5.1 follow-up · Define the manifest document-row schema and artifact identity before #25 builds manifest-registry-consistency #96's decision.text-extract-v1drops it, and what "differs" means against a preflight record.Constraints
docs/validator-spec-sheet.mdis not a governed document — its preamble states it carries no metadata table and no revision record — so no Revision Record row is required for editing it. (Triage note, unchanged from WP 5.1 follow-up · Define the manifest document-row schema and artifact identity before #25 builds manifest-registry-consistency #96: WP 1.3 · validator-spec-sheet — define the loose-pointer grammar §4 never states #91's acceptance criteria ask for one on this same file; that criterion is inconsistent with the sheet's preamble and is worth correcting there.)docs/reference/source/is read-only.loose-pointer-driftalready pinned.