Repository navigation
Fix a dropped morpheme ID when a zero-width rule wraps one ending at the same node - #500
Open
johnml1135 wants to merge 2 commits into
Open
johnml1135 wants to merge 2 commits into
johnml1135 wants to merge 2 commits into
Conversation
johnml1135
force-pushed
the
fix/signature-drops-id-under-identity-rule
branch
from
September 25, 2026 19:12
b15073b to
96d6b7f
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## fix-506-directional-boundaries #500 +/- ##
===============================================================
Coverage 74.62% 74.62%
===============================================================
Files 453 453
Lines 38345 38345
Branches 5285 5285
===============================================================
Hits 28614 28614
Misses 8568 8568
Partials 1163 1163 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
johnml1135
force-pushed
the
fix/signature-drops-id-under-identity-rule
branch
from
September 25, 2026 22:54
96d6b7f to
5aa7b39
Compare
johnml1135
force-pushed
the
fix/signature-drops-id-under-identity-rule
branch
from
October 23, 2026 11:09
5aa7b39 to
157c031
Compare
This comment has been minimized.
This comment has been minimized.
This was referenced Oct 23, 2026
johnml1135
added a commit
that referenced
this pull request
Oct 24, 2026
Pin full parse multiplicity and application histories from combined Machine #500 and #556 in three derivatives of the #480 truncation grammar. Update fixture-derived coverage, interaction ledgers and their audit pins. The original grammar is unchanged. The complete expectations intentionally remain red on the conformance branch until both engine fixes are applied.
This was referenced Oct 24, 2026
johnml1135
force-pushed
the
fix/signature-drops-id-under-identity-rule
branch
from
October 26, 2026 11:50
157c031 to
857313b
Compare
johnml1135
added a commit
that referenced
this pull request
Oct 26, 2026
Pin full parse multiplicity and application histories from combined Machine #500 and #556 in three derivatives of the #480 truncation grammar. Update fixture-derived coverage, interaction ledgers and their audit pins. The original grammar is unchanged. The complete expectations intentionally remain red on the conformance branch until both engine fixes are applied.
…the same node In SynthesisAffixProcessAllomorphRuleSpec.ApplyRhs, a zero-width rule's fallback "no new output morphs" marking claimed the shared final shape node before the loop that re-marks the wrapped rule's own morph, so the wrapped rule's morpheme ID could be overwritten or ordered ahead of the outer rule's. Move the fallback marking after that loop so the wrapped allomorph keeps its ID and the outer rule's ID sorts after it. Adds IdentityRuleSignatureMorphDropTests with two deterministic controls and one regression that retries fresh language loads. Measured over 100 fresh loads: with the fix, the correct signature is reached 41/100 times; with the fix reverted, 0/100 -- confirmed by reverting the production change and rerunning. The remaining gap under the fix is a separate, unfixed ordering defect (tracked in #506); this PR does not make output deterministic for every ordering, only reachable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
johnml1135
changed the base branch from
master
to
fix-506-directional-boundaries
October 29, 2026 18:45
johnml1135
force-pushed
the
fix/signature-drops-id-under-identity-rule
branch
from
October 29, 2026 18:46
857313b to
b86120f
Compare
johnml1135
force-pushed
the
fix-506-directional-boundaries
branch
from
October 29, 2026 18:46
579b2ef to
41f319f
Compare
| [TestFixture] | ||
| public class IdentityRuleSignatureMorphDropTests | ||
| { | ||
| private const string GrammarXml = """ |
Contributor
There was a problem hiding this comment.
FYI: F5. GrammarXml and WriteTempGrammar (line 99) use "grammar" for the HermitCrab configuration. AGENTS.md reserves that word and asks for Language or Stratum instead, e.g. LanguageXml and WriteTempLanguage.
Contributor
Public API, target frameworks, packages, and Findings: F1 withdrawn; F2 addressed; F3 addressed; F4 addressed; F5 new. Reviewed at f531fb1 |
jtmaxwell3
approved these changes
Oct 30, 2026
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.
Start here:
src/SIL.Machine.Morphology.HermitCrab/MorphologicalRules/SynthesisAffixProcessAllomorphRuleSpec.cs,ApplyRhs: one block of code moved below a loop.Status: stacked on #556 — merge in order #556 → #500 → #480 → #578.
Status: open since 2026-09-14. An automated review (
claude) asks for changes: marking the last shape node after the loop moves that node from the wrapped morph to the zero-width rule, so the wrapped morph loses its last segment (F1); thefenostest passes if any one of 100 loads is right (F2); and test comments point at code absent from this repo (F3, F4). No CI check is red (claude-reviewwas skipped;code-review/reviewableis pending).When a zero-width rule (such as a copy-only
CopyFromInput) wraps another rule's affix and both mark the same trailing shape node, the wrapped morpheme ID was dropped.ApplyRhsnow marks the zero-width rule's last node after the loop that re-marks wrapped input morphs, so the wrapped ID sticks and the outer rule's ID sorts after it.Reviewers arrive asking whether the regression test is deterministic. It is not: the fix makes the correct signature reachable in 41 of 100 fresh language loads in an earlier measurement, and 0 of 100 with the fix reverted. The rest trace to a separate, unfixed ordering defect (#506, open; #556 addresses its tie-boundary mechanism and is open). The question worth your time is F1: does the node move cost the wrapped morph its last segment in a case the tests do not cover?
Where to look:
ApplyRhs: theoutputNewMorph == nullmarking now runs after the loop. Pinned only by the tests below.IdentityRuleSignatureMorphDropTests: controlsFen_BareRootControl_IdentityWrapsRootDirectly_StableAndCorrectandFeno_NoIdentityRuleApplies_StableAndCorrectare deterministic.Fenos_IdentityWrapsOutermost_IsFlakyPendingASeparateOrderingDefectretries up to 100 fresh loads and passes on the first correct signature.Not here: the ordering defect behind #506, which keeps the regression from passing on every attempt.
Verification: build, the HermitCrab tests,
csharpierand the comment-hygiene script passed when the PR was opened; counts are not recomputed here and nothing was rerun for this description.Next: author to answer F1 (with a test, or a reason the lost segment is harmless), then re-request review.
Reading this a year from now -- start here
ApplyRhsmarks morphs on the output shape in two places: a fallback for rules with no new output morphs (truncation and zero-width rules), and a loop that re-marks each input morph the rule wraps. When a zero-width rule's own affix and an inner wrapped rule's affix end at the same trailing shape node, whichever call runs second keeps that node's morpheme ID. The fallback used to run first, so the outer rule's ID could overwrite or precede the wrapped rule's. Moving it after the loop makes the wrapped rule's ID stick and the outer rule's ID sort after it, matching the orderIdentityRuleSignatureMorphDropTestsexpects.Decisions, and why
The
fenostest retries up to 100 fresh loads and passes on the first correct signature. Measured earlier: 41/100 correct with the fix, 0/100 with it reverted. Asserting every attempt would be red even with the fix; a single assertion would be flaky. Retry-until-first-success is the one assertion the data supports, and it goes red with the fix reverted. The cost is that it stays green if the fix works only once in 100 (F2).Paths not taken
An earlier comment blamed
BidirList's unseeded skip-list levels. The source does not support that: same-range annotations tie-break onAnnotation.ListID, a call-order counter. The claim was removed.Deferred
Making every fresh parse deterministic needs the ordering defect in #506 fixed first. Whether #556 is enough is not established; the cause of the per-run variation is not yet identified.
Surprising findings
An earlier revision reported "five green repetitions; suite 575 passed, one skipped, zero failed" and a seed experiment claiming 12/12 repeatability versus three unseeded outputs, attributed to forcing a fixed seed on
BidirList'sRandom. Those numbers were not reproduced and the causal claim did not hold against the source; the 41/100 and 0/100 counts replace them.🤖 Generated with Claude Code
This change is