Repository navigation
Description
Lane: openreposhape-5 (openRepoShape-5)
Found by this lane's adversarial review of #213's fix as F3 and F4, two edges of the flow-mapping reader that the fix did not touch. Pre-existing on main 54aa69a, and the same on fix/yaml-flow-escaped-quote 86ffe66 (PR #244) and fix/adopt-plan-linebreak-names a02240a (PR #247). Latent: no writer in this repository emits a flow mapping with an explicit key or an empty value (see Reach).
What is wrong, two ways.
- An explicit key in a flow mapping is read as a key. The block reader refuses
?by name, and the reader's header lists explicit keys as REFUSED, "an invented meaning in a validator is a wrong answer with a confident tone"._refuse_unsupported(scripts/repo_shape.py:418) runs only on block lines (called at :533)._split_key_flow(:322) has no such check, so in a flow mapping? a: bis the literal key? a. - An empty value in a flow mapping is refused as a flow collection.
_flow_value(:299-301) is_flow(text) if text[:1] in "[{" else _scalar(text), and for the empty string''[:1] in "[{"is True ('' in "[{"is True for any string), so_flow('')runs and raisesnot a flow collection: ''. The block twina:reads{'a': None}, and so does YAML.
SHAPE=<openRepoShape checkout>
SHAPE=$SHAPE python3 - <<'PY'
import os, sys
sys.path.insert(0, os.environ["SHAPE"] + "/scripts")
from repo_shape import parse_yaml, YamlError
def read(text):
try:
return repr(parse_yaml(text))
except YamlError as exc:
return f"YamlError: {exc}"
for text in ("k: {? a: b}\n", # F3: an explicit key in a flow mapping
"k:\n ? a\n : b\n", # the same construct in a block: refused
"k: {a: }\n", # F4: an empty value in a flow mapping
"k: {a:}\n",
"k: {a: , b: 1}\n",
"k:\n a:\n b: 1\n"): # the block twin of F4: a null value reads fine
print(f"{text!r:24} ->", read(text))
PYObserved on main 54aa69a (the same on 86ffe66 and on a02240a):
'k: {? a: b}\n' -> {'k': {'? a': 'b'}}
'k:\n ? a\n : b\n' -> YamlError: line 2: explicit keys are not supported
'k: {a: }\n' -> YamlError: not a flow collection: ''
'k: {a:}\n' -> YamlError: not a flow collection: ''
'k: {a: , b: 1}\n' -> YamlError: not a flow collection: ''
'k:\n a:\n b: 1\n' -> {'k': {'a': None, 'b': 1}}
PyYAML 6.0.3 reads k: {? a: b} as {'k': {'a': 'b'}} and each of the three empty-value rows with 'a': None ({'a': None, 'b': 1} for the third). Row 1 is a wrong answer with no refusal: the reader's own rule, applied in a block, would have raised. Rows 3 to 5 are refusals of valid YAML, with a message that names an empty string a person never wrote.
Expected. ? a: b in a flow mapping is refused as the block form is, explicit keys are not supported, since the reader declines to invent a meaning for it; the refusal sits where both forms meet, not only on block lines. {a: }, {a:} and {a: , b: 1} read {'a': None} and {'a': None, 'b': 1}: _flow_value treats an empty value as null (_scalar('') already returns None), and the [{ test asks whether the text OPENS a flow collection (text[:1] in ("[", "{"), or text.startswith(("[", "{"))), which an empty string does not. A test pins the rows above.
Reach. Nothing writes either form. The four flow writers emit sequences of bare words (adopt-project.py pins and allow_empty_legs, scripts/shape_materialize.py also_matches and referent_chain) and members: [] / paths: []; no writer emits a flow mapping with a key or value. So it shows only on a file a person edits or another tool writes, a flow mapping such as naming: {form: } left half-filled in project.yaml. None of the 14 tracked YAML files holds a flow mapping other than a template placeholder (git ls-files '*.yaml' '*.yml', searched for : {, - { and a line opening ? ).
Adjacent and not part of this issue, from the same review: empty flow ITEMS are dropped silently ([,] reads [], [a, , b] reads ['a', 'b'], where YAML refuses the second) and [k: v] reads as the one string k: v; both are older and untouched by the fix. They are listed so the reader's next differential check covers them.
Found by. handoffs/openRepoShape/attachments/lane-openRepoShape-5/review213-report.md in opensoft/brett-wip (F3 and F4). Re-run on main 54aa69a, 86ffe66 and a02240a for this issue.
Not claimed.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 11, 2026
CLAIMED — lane openRepoShape-5, session e62c2fd7-176d-429d-89fb-0653dd08ad5f@Eagle, 2026-10-11T21:45:38Z, for #252
Logged in
lanes/log/openRepoShape-5.mdat7effddbcf0fe7250075f257f5a2457d28db8ca0e.The three reads (lane-collision-protocol Rule 1):
scripts/repo_shape.py: a block scalar's record carries its key and it…
scaffold-project.py: a `--referent-chain` link between the first and …
Merge origin/main (eb6df75) into fix/yaml-quote-boundaries (#249, #250)
repo_shape.py: a quote opens a quoted scalar only where one begins an…
Merge origin/main (5751460: #214 via #246, #217 via #230, #209 via #218…
Merge origin/main 60588d5 into fix/adopt-root-kept-symlinks: #214, #217…
Merge origin/main (6d8d88b: #249 and #250 via #284, #204 via #227, #203…
Merge origin/main (5751460, #212 via #223) into fix/adopt-late-failur…
Merge origin/main (c3f4987) into fix/adopt-plan-quote-yaml-keywords
repo_shape.py: a plain scalar opening with an indicator, an empty flo…
repo_shape.py strips only YAML's space and tab, so a value a Unicode …