Repository navigation
apply(): refuse tagged keys, NaN equals NaN, refuse NFD look-alikes (#749) - #759
Merged
Merged
Conversation
…lisation look-alikes A tagged key (!foo a: 1, !!str a: 1, !!float 1: a) made every operation raise TypeError/KeyError; it is now refused with a reason. .nan blocked every edit of its file with a misleading reason; NaN now equals NaN and can be written. An NFD key was shadowed by an added NFC look-alike; it is now refused. The fuzz covers tagged, complex, .nan and NFD keys. Limits section states each choice; unsetting a list's last item is pinned (not reproducible). Fixes #749 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ith a true reason Fix round 1 of #759. _loaded_tagged_key checked isinstance(x, set), but ruamel loads a CommentedSet (an abc.Set), and !!pairs loads as (key, value) tuples, so a tagged key there reached the post-check and was refused with an untrue reason. Walk every container a key can load into; one parametrised test lists them. The reason no longer says 'no path can name it' (untrue for ReplaceBody). Limits state the normalisation guard's scope (NFC canonical equivalence, keys). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #749 (items 1, 2, 4, 5; item 3 stated exactly in Limits; item 6 left).
apply()raises onlyOperationRefusedError, with a true reason, on any input. No caller yet.Groom check, riskiest assumption first. The ticket said every tagged key raises
TypeError/KeyError. Confirmed on dev, plus a third case it did not name:!!float 1: aloads as float 1.0 in ruamel but reads as int 1 plain (KeyErroron path1).!!int 1: ais not a problem (ruamel loads int 1). Item 5 (a list's last item drops the comments between items) did not reproduce on ~16000 generated layouts; it is pinned as a control, not fixed.Choices (stated in the module's Limits)
_has_tagged_key(node tag vs plain reading:!!float 1) and_loaded_tagged_key(what ruamel loaded:!!str x)._scalar_eq), as value, key or list item; and the old "cannot write NaN" refusal went with it (.nanis now emitted)._lookup); the file's spelling, and a file holding both spellings, are edited exactly.Covers (every operation x every place a key sits):
_parseis the one entry for all ops, so tagged keys are refused there for Set, Append, Remove, Unset, AddSubkey and ReplaceBody (_EVERY_OP); at top level, nested, in a list item, in a flow map. NFD refusal is in_lookup, which_model_applycalls first for every segment of every op. NaN is invalues_equal,_exact,_key_matchesand_same_keys.Evidence
16 red - 0 import-only - 0 unexpected pass - 0 n/a - 12 control._scalar_eq,.nanemit each turn a named test red.test_malformed_operations_raise_only_operation_refusednow has tagged, complex,.nanand NFD texts and path pieces (6000 iterations);TypeErroron dev, green here.test-affected --runon the tree before the last docs/test-mark commit: 667 passed. An earlier local pre-push run on the final tree went over 2h under load and was stopped; the push that landed was not preceded by a completed local run. CI is the authority.Hallway notes:
feedback/2026-10-05-749-apply-tagged-keys.md.🤖 Generated with Claude Code
Worker report (2026-10-06)
Pushed: fad35de == origin/fix/749-apply-tagged-keys. 1 commit, rebased on dev 7d75837 (#744 splitter; no private span helper).
Closes: #749 items 1, 2, 4, 5. Item 3 is stated as a measured limit. Item 6 (independent oracle in CI) is left.
Evidence: verify-red
16 red · 0 import-only · 0 unexpected pass · 0 n/a · 12 control. test-affected-n 4: 667 passed, on the tree before the last commit (controls and docs only). No completed local run on the pushed SHA; CI is the check.Guards (each removed alone turns its named test red):
_has_tagged_key,_loaded_tagged_key, the Unicode-normalisation guard in_lookup, NaN in_scalar_eq,.nanemission in_emit_float.Learned: the groom's tagged-key list was incomplete.
!!float 1:loads as 1.0 but reads plain as int 1, a KeyError.!!str xis indistinguishable fromxat node level, hence two guards. Item 5 (comment loss) did not reproduce over about 16k generated layouts, so it is pinned as a control. Item 3's widen loss is narrower than the ticket says.Captured in: the
test_a_tagged_key_*,test_a_nan_*and normalisation tests; the Limits section of the module docstring;feedback/2026-10-05-749-apply-tagged-keys.md.Unsure: (1) refusing EVERY operation, ReplaceBody included, on a file with a tagged key; (2) the conservative node guard also refuses
!!int "1"; (3) the NaN wording in Limits.Left: item 6; no local run on the final SHA.
Tokens: 199k (subagent total).
Fix round 1 (2026-10-06): every unnameable key, any container, a true reason
Pushed: 8f7b1c5 (one commit on fad35de). test_file_operations.py at -n 4: 265 passed. verify-red not run for this round; CI is the authority.
_loaded_tagged_keywalkscollections.abc.Set(ruamel loads!!setasCommentedSet) and!!pairstuples._has_tagged_keydocstring now cites cases the guard does catch (!!float 1,!!int "1",!foo,!!binary)._KEY_CONTAINERShas 16 cases (top-level, nested and flow mappings, list items, set members in flow and block form,!!omap,!!pairs, custom-tagged, a map under a set), each run against Set, new-key Set, Unset and ReplaceBody. Each loaded-guard branch, removed alone, turns a named case red.Learned: the first pass enumerated key positions the worker could think of, not the types ruamel can load. Probing each tag listed them in one script. Captured in: the
_KEY_CONTAINERStest, Limits, feedback Friction 5.Left: apply(): body-only writes on frontmatter Pyrite cannot model (tagged/complex/duplicate keys) #760, B6 P1 apply(): limits to close before P3 wires it in (tagged keys, .nan, widen scope, NFD keys) #749 item 6 (independent oracle in CI), CI on 8f7b1c5.
Tokens: 213k (subagent total, cumulative).
Conductor review (2026-10-08)
The delta cold read of round 1 (8f7b1c5) says land.
!!setand!!pairstagged keys are now refused as "tagged key" for every operation, ReplaceBody included. Plain sets, omaps and pairs stay editable. It found no false refusals across 26 common frontmatter forms and the 17 SHAPES files, and no bytes changed outside the named spans. CI is green: test (3.12), verify-red, gate.Known limits, all fail-safe, tracked in #769: a tagged key next to its plain twin is reported as a duplicate key; a tag inside a set member's value is invisible (ruamel discards it); the body-write wording on the other refusals; a test assertion pinned to old wording. Body-only writes on frontmatter Pyrite cannot model are tracked in #760.