Repository navigation
config: reconcile ADR 0061 and ADR 0064 on the invalid-value rule and the two YAML-subset parsers #7104
Copy link
Copy link
Open
Labels
needs-triageNot yet classified. Floor until a type and one priority tier are set.Not yet classified. Floor until a type and one priority tier are set.
Description
Summary
The repository has two YAML-subset parsers with different grammars: lib/yaml-subset.mjs (strict) and lib/yaml-subset.awk (accepts flow mappings and document markers). The owner chose yaml-subset.mjs's grammar as the only grammar on 2026-10-12 and confirmed it on 2026-10-20 (decision comment). This issue makes the awk parser match it, in this order:
- Rewrite every flow mapping in
docs/conventions/*.yamlin block style (all of them are indocs/conventions/pr-pipeline.yaml: themodelsblock and theissue-dimensionsblock). - Make
lib/yaml-subset.awkreject flow mappings and document markers (---,...), aslib/yaml-subset.mjsdoes. - Switch
lib/setup-apply.mjsto importlib/yaml-subset.mjsinstead of spawning awk.
Step 1 goes first because scripts/check-convention-yaml.sh parses every convention file with the awk parser, so step 2 fails that lint while any flow mapping remains.
Current behavior
Verified against main (419f77d).
lib/yaml-subset.mjs:87throwsflow mapping ({...}) is outside the subset; use block style.lib/yaml-subset.mjs:171throwsdocument markers are outside the subset.lib/yaml-subset.mjs:209throws on a duplicate key. Flow sequences of scalars are accepted (:91,:99).lib/yaml-subset.awkdocuments and implements flow mappings (header at:6,flow()at:121, mapping branch at:168-192) and skips---,...and%lines (:20,:261).- Duplicate keys:
lib/yaml-subset.awk:43fails them (fix(lib): strict parse-concern-value reports a duplicate key as a parse error #8175), but only under-v STRICT=1.lib/parse-concern-value.sh:108passes STRICT.lib/setup-apply.mjs:432andscripts/check-convention-yaml.sh:86run awk without it. lib/setup-apply.mjs:431-432(flatten) spawnsawk -f <parser>and reads its tab-separated records. Its callers are at:485,:771,:778and:821.lib/yaml-subset-awk.test.sh:35asserts that a flow mapping parses (a duplicate in it fails under STRICT), and:38asserts that a---marker is accepted.- Flow mappings in
docs/conventions/*.yaml(found withgrep -nE ': \{'; no file has a line starting---or...):docs/conventions/pr-pipeline.yaml:343-347, the fivemodels.profilesentries (standard,review,pr-review,triage,summary).docs/conventions/pr-pipeline.yaml:366,:369,:372, theoptions:maps underissue-dimensions.fields(size, complexity, uncertainty), with quoted numeric keys.docs/conventions/pr-pipeline.yaml:376,:378, thesmallandmediumentries underissue-dimensions.sizes.code-metrics.yaml,source-control.yamlandtesting.yamlhave none.
- Run through
lib/yaml-subset.mjs,pr-pipeline.yamlfails today at line 343 with the flow-mapping error. The block-style form of a quoted numeric key ("27053568": small) parses in mjs. - The decision comment of 2026-10-20 names only
:343-347. Lines:366-378are also flow mappings, and the block-style rewrite has to cover them too or the lint fails. - The 2026-10-12 decision's first part (the invalid-value rule) is done by ADR 0075 and is out of scope here.
Desired behavior
docs/conventions/pr-pipeline.yamlholds the same values in block style. Every mapping that was written{ k: v, ... }becomes one key per line.lib/yaml-subset.awkfails with an error record, as the mjs parser does, on a flow mapping (a value starting{) and on a---or...document marker line. Its header comment and the plugin copies generated byscripts/sync-shared-copies.shmatch.lib/yaml-subset-awk.test.shasserts the rejections in place of the flow-mapping and marker acceptances at:35and:38.lib/setup-apply.mjsimportslib/yaml-subset.mjsand builds its records from the parsed object. It does not spawn awk. The records keep the shapeflattenreturns today (path,top,nested,value), with scalar values as strings, so the validation and read-back callers need no change.lib/parse-concern-value.shand the other bash readers keep using the awk parser.
Acceptance criteria
- No file under
docs/conventionsuses a flow mapping or a document marker. docs/conventions/pr-pipeline.yamlparses withlib/yaml-subset.mjs, and every value it held before is unchanged.lib/yaml-subset.awkreports an error record form: {k: 1}and for a---line, and still reads flow sequences of scalars.lib/yaml-subset-awk.test.shhas cases for the flow-mapping rejection and the document-marker rejection.lib/setup-apply.mjsdoes not callspawnSync("awk", ...)and importsyaml-subset.mjs.- The PR's CI runs
scripts/check-convention-yaml.shand it passes. - The PR's CI runs the
lib/yaml-subsettests (mjs and awk) andlib/setup-apply.test.sh, and they pass. - The generated plugin copies of
yaml-subset.awkequallib/yaml-subset.awk(scripts/sync-shared-copies.shleaves no diff). - The PR carries a changelog fragment or version bump for each plugin whose copy changed, as the repository requires (
scripts/check-changelog-fragments.sh --checkpasses).
Out of scope
- The invalid-value rule (ADR 0075 did it).
- Making
scripts/check-convention-yaml.shandlib/setup-apply.mjsfail duplicate keys through awk (the mjs parser rejects them without STRICT, sosetup-apply.mjsgains the check from the switch; the lint keeps its awk call). - Retiring
yaml_subset.py(refactor(user-experience): read team config through lib/config-cascade.mjs #7027). - A shared fixture corpus for both suites (the 2026-10-12 plan listed it; the 2026-10-20 scope does not).
- Reading consumer repos'
docs/conventions/*.yaml; a consumer file with flow mappings fails after step 2 and needs the same rewrite.
Merging: a human merges this PR (lib/** path).
Related
- Origin: #7009 (merge of main brought both parsers together)
- Decision: comment of 2026-10-20, which keeps the 2026-10-12 decision for Q2
- feat(conventions): one setup lifecycle for where plugins store team conventions and settings #6594
- refactor(user-experience): read team config through lib/config-cascade.mjs #7027
- lib/yaml-subset.awk keeps the first duplicate key where the CI parser rejects the file #7331
- #8175 (awk duplicate-key check)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
needs-triageNot yet classified. Floor until a type and one priority tier are set.Not yet classified. Floor until a type and one priority tier are set.
Type
Fields
No fields configured for Task.
Activity
github-actions commentedon Oct 11, 2026
Thanks for the report. Automated triage handed this issue to a maintainer.
Proposed work class: work-class: structural
Basis: automated intake triage; a maintainer confirms or changes it.
Automated triage. A maintainer reviews it.
kyle-sexton commentedon Oct 13, 2026
Decision recorded. The owner accepted the adjudicated recommendation on 2026-10-12.
Q1: adopt ADR 0064 D7 in both ADRs, stated per key: an invalid value is named by file, key and value and that key is dropped from that layer; a valid higher layer wins, otherwise the key's default; a lower layer's value is never used. Change lib/config-cascade.mjs to match. Q2: the grammars differ (verified this run), so pick lib/yaml-subset.mjs's stricter grammar as the one grammar: make lib/yaml-subset.awk reject flow mappings, document markers and duplicate keys, add one shared fixture corpus both suites run, and switch lib/setup-apply.mjs to import yaml-subset.mjs in the same change.
Why: D7 is the only invalid-value rule labeled an owner decision (ADR 0064:64-68, amended 2026-10-04 'user decisions'); ADR 0061's lower-layer line carries no ruling, and the owner's newest merged change on the subject (#7009, 2026-10-11T23:51Z, after #6976 at 04:38Z) brought the README and AGENTS.md 'in line with ADR 0064 D7' and filed #7104 instead of conceding, so precedence rule 2 decides for D7, and on main eleven plugin reference docs plus README:67-69 already implement it while only lib/config-cascade.mjs:16-18 and README:583 implement 0061. Claude Code's own settings handling (settings.md:607-608, managed-settings.md:350-364) skips the single bad entry and lets the rest of the stack merge for ordinary keys, which is a design precedent in a different system, not a fact this repo depends on; it does support per-key granularity and fail-closed handling of a constraining layer, which the recommendation adopts. The parser cross-run was re-executed on origin/main: awk accepts 'a: {b: 1}' (emits a.b=1), a '---' marker and a duplicate key (emits both records) where mjs errors on each by documented design, and mjs types scalars where awk emits strings, so the issue's 'if grammars match' branch is closed and one grammar must be chosen.
Precedence applied: Rule 2 (owner's newest explicit decision): D7 is the only dated owner ruling on invalid values and #7009, the owner's later merge, names it; #6976 merging ADR 0061 without naming D7 is flagged as possible course change, not proof. Rule 3 does not reverse it: 0061 is newer-dated but defers to #6594, and rule 2 outranks it. Rule 4 (upstream Claude Code settings docs) is cited, not a fact conflict: it describes a different system and informs only the per-key granularity. Researcher B's hybrid (fail closed only for declared restrictive keys) is an agent default (rule 5) no owner has ruled on and is not adopted.
Sources:
Next: One draft PR, Conventional Commits title, 'Closes #7104', Refs #6594, #7027, #7331. (1) Amend ADR 0061:54 to D7 wording and add a per-key clarification to ADR 0064 D7 ('drops that key from that layer'). (2) lib/config-cascade.mjs:16-18: an invalid leaf no longer lets the lower layer keep the key; resolve from a valid higher layer, else the default; update lib/config-cascade.test.mjs and .test.sh; regenerate plugins/user-interface/scripts/lib/config-cascade.mjs via scripts/sync-shared-copies.sh; note the user-interface behavior change in the PR body. (3) README: fix the user-interface row at :583 and reword rule 5 at :310-312 so 'as if that layer were absent' no longer implies lower-layer fallback. (4) lib/yaml-subset.awk: reject flow mappings, '---'/'...' markers and duplicate keys (folds #7331), regenerate the 42 plugin copies; add one shared fixture corpus consumed by lib/yaml-subset.test.mjs and lib/yaml-subset-awk.test.sh. (5) lib/setup-apply.mjs:237-243: import yaml-subset.mjs instead of spawning awk. Before merge, grep consumer repos' docs/conventions/*.yaml for '{' and '---' (none in this repo's four committed files). Open items for the PR, not the owner: the disable-list gap (an invalid *.disable list drops that layer's entries under either rule) is outside #7104 and worth a follow-up issue only if a reader acts on it; #7027 keeps ownership of retiring yaml_subset.py.
Researched by two independent agents (local evidence and upstream docs) and adjudicated by a third.
kyle-sexton commentedon Oct 20, 2026
Decision recorded. The owner answered in the Issue Triage session on 2026-10-20.
docs/conventions/pr-pipeline.yaml:343-347uses flow mappings (since feat(pr-pipeline): route lane models through a models block in pr-pipeline.yaml #7781) andscripts/check-convention-yaml.sh:54parses every convention file withlib/yaml-subset.awk? Options: (a) reverse to awk's grammar (teachyaml-subset.mjssingle-line flow mappings, add a shared fixture corpus, switchsetup-apply.mjsto import mjs); (b) keep the 2026-10-12 choice ofyaml-subset.mjs's stricter grammar, and first rewrite pr-pipeline.yaml'smodelsblock in block style; (c) keep two grammars, list each difference, and close config: reconcile ADR 0061 and ADR 0064 on the invalid-value rule and the two YAML-subset parsers #7104 as recorded. Recommended: (b).So: (b). The 2026-10-12 Q2 decision stands: one grammar,
yaml-subset.mjs's. The change first rewrites the flow mappings indocs/conventions/pr-pipeline.yaml'smodelsblock (:343-347) in block style, then makeslib/yaml-subset.awkreject flow mappings and document markers as the mjs parser does, and switchessetup-apply.mjs(:432) to import the mjs parser. Q1 is already done by ADR 0075. Paths are underlib/**, so a human merges the PR.