Skip to content

Move the anchor attribute in ANCH(n)/REC(n), not just its values; release 0.5.1 - #9

Merged
shigarov merged 1 commit into
mainfrom
fix/anch-named-attributes
Aug 26, 2026
Merged

Move the anchor attribute in ANCH(n)/REC(n), not just its values; release 0.5.1#9
shigarov merged 1 commit into
mainfrom
fix/anch-named-attributes

Conversation

@shigarov

Copy link
Copy Markdown
Contributor

Port of the jRegTab 0.5.1 fix (a092102, merged in 43c1fa9) — reference
implementation AnchorAttributeAtPosition.java.

The bug

apply_anchor_at_position (src/spec.rs) permuted only the record
values while the schema kept its original order. With anonymous $a_i names
(position == name) that is invisible, but with named attributes — the ones
AVP produces from a header row — the attribute-value binding broke: the column
carrying the anchor's name received another attribute's values.

Reported case: <ANCH(4)> over a Dato,Tid,Eksamen,Fagkode,Lokaler,Klasse
header came out as Lokaler,Dato,Tid,… with every value shifted.

The fix

The transformation now moves the anchor attribute — name together with its
values — so every record keeps its pairs and only the schema order changes,
making it the special case of apply_schema_reordering it always was.

One rule for named and anonymous attributes alike: an anonymous name is no
longer reassigned positionally, it travels with its attribute, so $a_1..$a_4
under ANCH(2) reads $a_2, $a_3, $a_1, $a_4 while the values stay in the
same positions as before
. All ANCH/REC(n) task fixtures are header-less and
compare positionally — none was touched.

No change was needed in the RTL plumbing: <ANCH(n)>, inline REC(n) on an
atomic content specification and inline REC(n) inside a delimited one already
converge on the same Transformation. That is now pinned by a test rather than
left to inspection.

Tests

  • #[cfg(test)] mod tests in src/spec.rs (the file had none): named,
    anonymous, mixed and degenerate schemas, a negative position, and a regression
    check that value positions are unchanged.
  • tests/test_rtl_anchor_forms.py: the three forms must agree, and REC(n)
    under {','} yields one record per raw token (" C1.1" keeps its leading
    space — the 0.5.0 S_delim rule).
  • AnchorAttributeAtPosition added to test_api.py's transformation coverage.
  • Corpus re-pinned to jRegTab v0.5.1 (c126337) and synced byte-for-byte: the
    two new semantic cases anch_named_attrs and anch_named_inline_delim. Both
    set expectedHasHeader, which is what lets them see the bug at all.
cargo test --no-default-features    21 passed   (was 14)
pytest tests -q                   1925 passed   (was 1918)
tests/fixtures/                     untouched

Discriminating check: temporarily restoring the old return value fails 4 core
tests and 5 Python ones (both conformance cases included) while the regression
check stays green.

Docs and version

The ANCH(n) row in the settings table described an attribute-naming operation
that never existed; docs/rtl-reference.md now states what the transformation
does, including the anonymous-name rule and the fact that an inline REC(n) is
picked up anywhere in the pattern, delimited specifications included. Same
correction in the REC(n) operation row, atp.md, itm.md and api.md.

Version bumped to 0.5.1 across Cargo.toml, Cargo.lock, pyproject.toml,
__init__.py, README.md and docs/index.md. The README's differential note
still refers to the v0.5.0 run — that comparison was not repeated here.

Plan: plans/ANCH_MOVES_ATTRIBUTE.md (and a new plans/INDEX.md).

🤖 Generated with Claude Code

…ease 0.5.1

apply_anchor_at_position permuted only the record values while the schema kept
its original order. With anonymous $a_i names (position == name) that is
invisible, but with named attributes -- the ones AVP produces from a header row
-- it broke the attribute-value binding: the column carrying the anchor's name
received another attribute's values. The reported case, <ANCH(4)> over a
Dato,Tid,Eksamen,Fagkode,Lokaler,Klasse header, came out as Lokaler,Dato,Tid,...
with every value shifted.

The transformation now moves the anchor attribute itself -- name together with
values -- so every record keeps its pairs and only the schema order changes,
which makes it the special case of apply_schema_reordering it always was. One
rule for named and anonymous attributes alike: an anonymous name is no longer
reassigned positionally, it travels with its attribute, so a schema $a_1..$a_4
under ANCH(2) reads $a_2, $a_3, $a_1, $a_4 while the values stay in the same
positions as before. All ANCH/REC(n) task fixtures are header-less and compare
positionally, so they are unaffected and none was touched.

Port of jRegTab 0.5.1 (a092102, merged in 43c1fa9); the reference implementation
is AnchorAttributeAtPosition.java.

No change was needed in the RTL plumbing: the settings prefix <ANCH(n)>, inline
REC(n) on an atomic content specification and inline REC(n) inside a delimited
one already converge on the same Transformation -- collect_rec_params descends
into delimited specs on the RTL path and actions_of reads d.atom.actions on the
ATP path. That is now pinned by a test rather than left to inspection.

Tests: a #[cfg(test)] module in src/spec.rs (the file had none) covering named,
anonymous, mixed and degenerate schemas, a negative position, and a regression
check that value positions are unchanged; tests/test_rtl_anchor_forms.py, where
the three forms must agree and REC(n) under {','} yields one record per raw
token (" C1.1" keeps its leading space -- the 0.5.0 S_delim rule);
AnchorAttributeAtPosition added to test_api.py's transformation coverage.
Temporarily restoring the old return value fails 4 core tests and 5 Python ones
while the regression check stays green.

Corpus re-pinned to jRegTab v0.5.1 (c126337) and synced byte-for-byte: the two
new semantic cases anch_named_attrs and anch_named_inline_delim. Both set
expectedHasHeader, which is what lets them see the bug at all -- every other
semantic case is header-less and positional.

Docs: the ANCH(n) row in the settings table described an attribute-naming
operation that never existed ("use position n in the first record as the
attribute name"); rtl-reference.md now states what the transformation does,
including the anonymous-name rule and the fact that an inline REC(n) is picked
up anywhere in the pattern, delimited specifications included. Same correction
in the REC(n) operation row, atp.md, itm.md and api.md.

Release 0.5.1: version bumped in Cargo.toml, Cargo.lock, pyproject.toml,
__init__.py, README.md and docs/index.md. The README's differential note still
refers to the v0.5.0 run -- that comparison was not repeated here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shigarov
shigarov merged commit 0eb6ea5 into main Aug 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant