Repository navigation
HermitCrab: keep final-template pruning on when only lexical entries are partial - #553
johnml1135 wants to merge 4 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #553 +/- ##
==========================================
+ Coverage 74.57% 74.73% +0.16%
==========================================
Files 453 453
Lines 38342 38342
Branches 5284 5284
==========================================
+ Hits 28593 28656 +63
+ Misses 8583 8532 -51
+ Partials 1166 1154 -12 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This comment has been minimized.
This comment has been minimized.
57a3b7e to
f1ac77e
Compare
PR #553 shows ignoring partial lexical entries in the final-template prune guard is safe, so Sena gets the prune once it merges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
|
I think that you can remove Morpher.IsPartial in the code and in the comments, since it is superceded by Morpher.HasPartialRules. |
The analysis-side final-template prune (491) was switched off whenever Morpher.IsPartial was true, and IsPartial counts partial lexical entries. Grammars with partial entries but no partial rules therefore never pruned. A partial entry cannot make the prune lose a parse. A word takes its partiality from its root, but SynthesisAffixTemplatesRule applies no template to a word whose root morpheme is partial, so a derivation that unapplies a final template can never end at a partial root. Partial rules differ: they make a word partial after the template has applied, which lets a non-partial rule follow the final template, so they still disable the prune. Add Morpher.HasPartialRules and read it in the two analysis guards. IsPartial keeps its meaning. Lexical-pattern guesses were already excluded from IsPartial and pruned. Closes #551 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The summary claimed a derivation that unapplies a final template can never end at a partial root. SynthesisAffixTemplatesRule.Apply calls ChooseInflectionalStem before the root check, so a partial root can take a template through a non-partial family relative. State the contract and why the prune stays sound. The test left the partial "sab" entry in the shared Language; remove it in a finally block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing reads it now that the analysis-side final-template checks use HasPartialRules. The three test preconditions assert GetPartialMorphemes() directly. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
f1ac77e to
b507a89
Compare
Done in b507a89: I removed |
This comment has been minimized.
This comment has been minimized.
The removed reasoning claimed a substituted family relative is always non-partial, which blocking can contradict. The contract alone is accurate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| /// <summary> | ||
| /// A Morpher is partial if any of the elements are partial. | ||
| /// True if any morpheme other than a <see cref="LexEntry"/> is partial. Analysis may prune a final | ||
| /// template that follows a non-template rule only when this is false. |
There was a problem hiding this comment.
FYI: F7. The summary says analysis prunes "only when this is false", but it also prunes when this is true and AlwaysEnforceFinalTemplates is set (AnalysisAffixTemplateRule.cs:47, AnalysisAffixProcessRule.cs:83). Consider "only when this is false or AlwaysEnforceFinalTemplates is set".
Public API: Findings: F1 addressed, F2 addressed, F3 addressed, F4 withdrawn (FieldWorks does not read Reviewed at 69edb79 |
Start here:
src/SIL.Machine.Morphology.HermitCrab/Morpher.cs,HasPartialRules(and its doc comment): the contract the other edits follow.Status: open since 2026-10-23. The reviewer's reply on the
IsPartialremoval (FieldWorks does not read it, nothing further needed) is in. Two review notes on test coverage (F5, F6: the analysis-sideAlwaysEnforceFinalTemplatesoverride, and thePruneDisagreeingCopiesTestsfalsecase) are still open for the author. CI has no red checks (theclaude-reviewjob was skipped).Closes #551. The final-template prune from #491 (merged) is no longer skipped when only lexical entries are partial.
Morpher.HasPartialRulesis true only if a partial morpheme is not aLexEntry, andAnalysisAffixTemplateRuleandAnalysisAffixProcessRuleread it in place ofMorpher.IsPartial, which is removed.Reviewers arrive asking whether a partial root could license a derivation the prune rejects. It cannot:
SynthesisAffixTemplatesRuleskips every template when the root allomorph's morpheme is partial. A partial root with a non-partialLexFamilyrelative can still take a template, with the relative as root, but that word is non-partial, so a following non-partial rule is blocked either way. Partial rules are different: they make the word partial after the root, so they keep disabling the prune.Where to look:
Morpher.HasPartialRules: the!(morpheme is LexEntry)filter overGetPartialMorphemes().AffixTemplateTests.PartialLexicalEntryDoesNotDisableEarlyPruningOfFinalTemplate: prune fires at trace depth 2 with a partial entry and no partial rule,sabandsabvparse,sabdandsabdvdo not; with a partial rulesagdvstill parses as32 PAST NOM. It fails with the old guard (depth 6 instead of 2).Morpher.IsPartialis gone and nothing in the library read it; FieldWorks does not.Not here: no fixture exercises
ChooseInflectionalStemsubstitution (traced by reading only); lexical-pattern guesses were already excluded from the partial-morpheme set.Verification:
./local_check.sh --agent-strictpassed before the rebase onto master. After the rebase and theIsPartialremoval onlyAffixTemplateTestsandPruneDisagreeingCopiesTestswere rerun (46/46). Not rerun: the full strict gate on the final head.Next: author to decide on F5 and F6, then approve.
Reading this a year from now -- start here
Prune is the early rejection, during analysis, of a final template followed by a non-partial rule. #551 suspected that ignoring partial entries was unsound. The argument that it is sound is under "Decisions, and why"; the conformance evidence is under "Evidence". #480 (open) carries the fixture.
Decisions, and why
Wordcopiesentry.IsPartial) or from a partial rule. Synthesis lets a non-partial rule follow a final template when the input word is partial (SynthesisAffixProcessRule.cs:67). Templates never apply to a partial root, so a partial entry cannot reach that case.ChooseInflectionalStemruns before the partial-root check, so the nuance above holds; theHasPartialRulesdoc comment states it.IsPartialwas removed because nothing reads it once both analysis guards useHasPartialRules. The three test preconditions that used it assertGetPartialMorphemes()directly.Surprising findings
Word.CheckBlocking, which swaps in a partial family relative that a non-partial rule may follow. The output should match analysing the relative directly as a root, so no parse is expected to be lost. Unverified.Deferred
AlwaysEnforceFinalTemplateson, to cover the analysis-side override (for example at the end of the new test).PruneDisagreeingCopiesTestsfixture, so thefalsecase tests copy-pruning with the final-template prune off.Evidence
conformance/edge-cases/final-template-partial-rooton Add a conformance suite for HermitCrab, with its adequacy argument #480 (integrate-conformance-frameworkat fa8d9b2) has partial roots in a lower stratum and in the template's own stratum. Every final-template string on a partial root has no analysis, with non-partial controls../local_check.sh --agent-strictpassed before the rebase;AffixTemplateTestsandPruneDisagreeingCopiesTests46/46 after.🤖 Generated with Claude Code
This change is