Skip to content

Trace HermitCrab failure reasons and template slot outcomes - #534

Open
johnml1135 wants to merge 10 commits into
masterfrom
fix/hc-trace-reasons
Open

johnml1135 wants to merge 10 commits into
masterfrom
fix/hc-trace-reasons

Conversation

@johnml1135

@johnml1135 johnml1135 commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Start here: src/SIL.Machine.Morphology.HermitCrab/IDetailedTraceManager.cs -- the opt-in interface, enums and PartialParseFailure; then TraceManager.cs for what Machine retains.

Status: open since 2026-10-01, targets master (no longer stacked on #480). CI green on this head: builds on ubuntu and windows, NuGet package, comment hygiene; the claude job is skipped.

Try A Word cannot show several facts HermitCrab already computes, because they never reach the trace or TraceManager discards them. This passes them through an optional IDetailedTraceManager and retains them in Machine's TraceManager, without rerunning any linguistic check: the first failed gate of an analysis affix rejection and its operand, template slot outcomes (applied, optional skipped, required unfilled), the cause of a partial parse, yielded-candidate counts per lexical lookup, compounding gates, the blocking lexical entry, and environment failures with all failed alternatives.

The unknown a reviewer arrives with is whether existing ITraceManager implementers break. They do not: ITraceManager gains no members, and LegacyTraceManagerTests record its plain callbacks, which match master. Compounding is the one place plain consumers could regress, so they receive only the productivity-restriction rejection with subrule index -1, as before.

Where to look:

  • Compounding: AnalysisCompoundingRule.cs and TraceManagerExtensions.cs keep plain managers on the old callback; detailed ones get the new gates.
  • Trace shape: a failed compounding subrule now appears in TraceManager's tree as a CompoundingRuleAnalysis node with subrule index i (rule-level rejection is -1); successful subrules stay MorphologicalRuleAnalysis.
  • Lookup bookkeeping: synthesis nodes stay attached to their lookup when inputs interleave; an interrupted lookup reports unknown, zero candidates is explicit.
  • Phonological non-unapplication stays reasonless on purpose, because that path computes no reason; a regression test checks none is invented.
  • TraceReasonTests carries the new facts; analyses are unchanged with tracing on or off, sequential or parallel.

Not here: the FieldWorks side (FwXmlTraceManager, FormatHCTrace.xsl; follow-up list below) and the conformance-suite commits for failure attribution, which move to #480 after this merges.

Stack and verification: no dependency; #480 follows this. Windows local checks and WSL HermitCrab tests passed at earlier heads of this branch and were not rerun at this head; ./local_check.sh was never run whole, and the full solution test suite has not passed on this tree (details under Evidence).

Next: approve, or name the callback shape you want changed.


Reading this a year from now -- start here

HermitCrab's analysis and synthesis rules already know why a candidate failed, but ITraceManager only said that it failed. Adding members to ITraceManager would force every implementer, FieldWorks included, to change, so the facts travel on a second interface (IDetailedTraceManager) that extension methods in TraceManagerExtensions call only when the manager implements it. Plain managers keep exactly the callbacks they had. The enum additions (TemplateSlotOutcome, PartialParseCause, new FailureReason values) keep existing values.

The conformance suite (#480) was deferred, so this PR was retargeted from stacking on it to master. Its two suite-side commits (failure-rule attribution crediting through Trace.Allomorph, and FieldWorks-producibility rows for the four new failure reasons) are held back and will be added to #480 after this merges.

Decisions, and why
  • Second interface rather than new ITraceManager members: existing implementations stay source- and behaviour-compatible.
  • Plain managers get only the productivity-restriction rejection from compounding, with subrule index -1. FieldWorks writes a trace node for every CompoundingRuleNotUnapplied call, so sending it the new gates would add reasonless failures to Try A Word.
  • Blocking already passes the replacement Word through the existing callback; Machine's trace now retains the blocking lexical entry from that Word's root allomorph (Trace.BlockingEntry). Environment failure already passes the allomorph and all failed alternatives; Machine's trace now retains both, along with the other failure operands (Trace.FailureObject).
  • Phonological non-unapplication stays reasonless; no reason is invented.
  • Slot reporting: optional slots can report both an applied and a skipped branch. Sequential and parallel analysis and synthesis are covered. Partial parses carry the cause: realizational feature mismatch, pending morphological rules (with the next rule, null when unknown or a compounding non-head), a non-final template applied last, or applicable templates not applied.
Evidence
  • TraceReasonTests (synthetic grammars) covers the facts above, interrupted and interleaved lookups, and analysis equivalence; LegacyTraceManagerTests records plain-manager callbacks, and its expectations were also run on origin/master at an earlier head and passed there.
  • At earlier heads of this branch: ./local_check.sh --agent-strict passed on Windows (full solution build and every test project); in WSL the HermitCrab test project, SIL.Machine.Tests and a HermitCrab.Tool Release build (0 warnings) passed; strict comment hygiene was clean. CSharpier was checked from a scratch install because the manifest's tool would not resolve there, so local_check.sh stopped at that step.
  • In WSL, ./local_check.sh and ./local_check.sh --agent-strict exited at the solution build because cmake is missing for SentencePiece; the standard rerun also reported MSBuild child-node shutdown errors. These local checks do not collect CI-equivalent coverage.
  • Not run at this head: ./local_check.sh as a whole, and the full solution test suite.
Deferred, and what would unblock it: FieldWorks follow-up (outside this PR)

File and line references are FieldWorks's tree as last read and were not rechecked here.

  • Implement IDetailedTraceManager in FwXmlTraceManager: the reason-bearing MorphologicalRuleNotUnapplied overload, TemplateSlotProcessed, and LexicalLookupCompleted. Serialize the new operands, branch outcomes and completed counts. Keep lookup/synthesis associations correct in LexicalLookup and SynthesizeWord when other trace nodes are inserted.
  • Implement Blocked to serialize the replacement Word's root entry. Extend CompoundingRuleNotUnapplied to handle each reason, not only productivity restrictions.
  • In Failed, serialize PartialParseFailure.Cause and its pending rule; for Environments, serialize each failed alternative alongside the supplied allomorph instead of passing the collection directly to XElement. NonFinalTemplateAppliedLast and ApplicableTemplatesNotApplied callbacks already distinguish those two template completion failures.
  • In MorphologicalRuleNotApplied, fix the prefixEnv/suffixEnv branches at FwXmlTraceManager.cs:299-302: they currently write env instead of their own values.
  • Update FormatHCTrace.xsl: ShowAnyFailure (environment branch near line 597, partial-parse branch near line 661) and ShowCompoundingRuleFailure (near line 1149) to show the detailed facts. Extend ShowTracePath (near line 1237), which selects synthesis children of LexLookupTrace but excludes the lookup node itself, to include empty lookup, slot and blocking events; adjust DetermineIfMoreToShow for the added nodes. Display unknown phonological causes as unknown.

🤖 Generated with Claude Code


This change is Reviewable

@codecov-commenter

codecov-commenter commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.72954% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.24%. Comparing base (c245476) to head (15ad1dd).

Files with missing lines Patch % Lines
...Crab/MorphologicalRules/AnalysisCompoundingRule.cs 88.23% 6 Missing ⚠️
.../SIL.Machine.Morphology.HermitCrab/TraceManager.cs 91.66% 3 Missing and 2 partials ⚠️
src/SIL.Machine.Morphology.HermitCrab/Word.cs 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #534      +/-   ##
==========================================
+ Coverage   74.57%   75.24%   +0.67%     
==========================================
  Files         453      455       +2     
  Lines       38342    38590     +248     
  Branches     5284     5326      +42     
==========================================
+ Hits        28593    29038     +445     
+ Misses       8583     8416     -167     
+ Partials     1166     1136      -30     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jtmaxwell3

Copy link
Copy Markdown
Collaborator

@johnml1135 Did you ask Beth about this? I'm worried that this will make it harder to find a needle in a haystack because the haystack will be so much bigger. It may also slow Try A Word down.

@johnml1135

Copy link
Copy Markdown
Collaborator Author

@jtmaxwell3 I measured both concerns, on a real Indonesian grammar exported from FLEx (70 wordforms, two compounding rules), comparing the merge-base with this branch.

Speed with tracing off (normal parsing): no measurable change. All 70 words give identical parses, and total time is 4.4 s on both, within 2%. Every new callback sits behind IsTracing; the only always-on addition is an integer counter per lexical-lookup candidate.

Trace size in Try A Word: you were right, and it was worse than the branch description said. FwXmlTraceManager implements only ITraceManager, and this branch was sending it CompoundingRuleNotUnapplied for every new compounding gate (stem limit, feature mismatches, non-head lookup, pattern). FieldWorks writes a node for each of those calls, and none of them would say why the rule failed. Over 40 of the words, that was 0 → 4,412 extra compounding-failure nodes in Try A Word, from the Machine bump alone. The affix-rule fallbacks don't reach the trace, because FwXmlTraceManager.MorphologicalRuleNotUnapplied is empty.

Fixed in 371ba39. ITraceManager-only consumers now get exactly the compounding callback they got before (the productivity restriction, with subrule index -1), and the new gates reach only IDetailedTraceManager. Re-measured on the same 40 words, every callback FieldWorks records now matches the merge-base, and a new test pins this. So updating Machine leaves Try A Word as it is. Whether to show any of the new facts, and how to keep the trace readable, is a decision for the FieldWorks follow-up.

I haven't timed parsing with tracing on beyond those 40 words.

Comment thread src/SIL.Machine.Morphology.HermitCrab/Morpher.cs
Comment thread src/SIL.Machine.Morphology.HermitCrab.Tool/ParseCommand.cs
Comment thread src/SIL.Machine.Morphology.HermitCrab/TraceManagerExtensions.cs Outdated
@claude

This comment has been minimized.

johnml1135 added a commit that referenced this pull request Oct 14, 2026
The suite added Trace.FailureAllomorph so FailureRuleAttributor could credit
an affix rule whose allomorph failed an environment or co-occurrence check.
That is an engine API change riding in a test-suite PR, and #534 adds the
same fact as Trace.Allomorph. Drop it here; the attribution returns with
#534. No generated ledger changes: coverage.csv and rules.csv regenerate
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@johnml1135
johnml1135 force-pushed the fix/hc-trace-reasons branch from 371ba39 to 9124922 Compare October 14, 2026 20:41
@johnml1135
johnml1135 changed the base branch from master to integrate-conformance-framework October 14, 2026 20:41
Comment thread src/SIL.Machine.Morphology.HermitCrab.Conformance/FailureRuleAttributor.cs Outdated
Comment thread src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs
@claude

This comment has been minimized.

@claude

This comment has been minimized.

johnml1135 added a commit that referenced this pull request Oct 15, 2026
The suite added Trace.FailureAllomorph so FailureRuleAttributor could credit
an affix rule whose allomorph failed an environment or co-occurrence check.
That is an engine API change riding in a test-suite PR, and #534 adds the
same fact as Trace.Allomorph. Drop it here; the attribution returns with
#534. No generated ledger changes: coverage.csv and rules.csv regenerate
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@johnml1135
johnml1135 force-pushed the integrate-conformance-framework branch from 3a63132 to df2cf21 Compare October 15, 2026 21:21
@johnml1135
johnml1135 force-pushed the fix/hc-trace-reasons branch from 928d7fa to 54393fd Compare October 16, 2026 13:19
@johnml1135
johnml1135 changed the base branch from integrate-conformance-framework to master October 16, 2026 13:19
Comment thread src/SIL.Machine.Morphology.HermitCrab/Word.cs
@claude

This comment has been minimized.

@johnml1135
johnml1135 force-pushed the fix/hc-trace-reasons branch from 54393fd to 9bcdcd5 Compare October 20, 2026 23:43
@claude

This comment has been minimized.

@claude

claude Bot commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Verdict: approve. This push rebased onto 2f70c04 and added 610c8d6, which fixes F11. No new findings, and every finding is now closed.

  1. Most important: nothing open. F11 (AnalysisCompoundingRule.cs:91) is addressed: a plain ITraceManager no longer pays for a clone whose trace call is dropped.
  2. Counts: Critical 0, Important 0, Low 0 open. F1-F4, F6-F8, F10 and F11 are addressed; F5 and F9 are withdrawn.
  3. Ran: /code-review high 534 on the whole PR, because the rebase rewrote history. It returned 7 items. One repeats F5, which is settled. The other six were weighed last round and are still not posted: the Required trace carrying outWord, template partial-parse causes going only to the built-in TraceManager, the duplicated is IDetailedTraceManager dispatch, the duplicated slot-outcome block, OptionalSkipped volume, and the CurrentTrace line in the clone (the author showed Clone already copies it). dotnet test tests/SIL.Machine.Morphology.HermitCrab.Tests -c Release filtered to TraceReasonTests and LegacyTraceManagerTests at the merge commit: 67 passed, 0 failed. gh pr checks 534: comment hygiene (advisory) passed; both Build jobs and claude-review are pending.
  4. Not verified: CI build and test results are still pending. The strict comment-hygiene.ps1 scan was not run here; the new F11 comment line is 117 columns, within the 120 limit. FieldWorks behavior rests on the author's measurement comment.

Public API: the PR adds IDetailedTraceManager, PartialParseFailure, TemplateSlotOutcome, PartialParseCause, four FailureReason values, TraceType.TemplateSlotAnalysis/TemplateSlotSynthesis and new Trace properties. TraceManager now implements IDetailedTraceManager, and its compounding trace shape changes by design (F5). Target framework and package: none. sillsdev/machine.py parity: None verified.

Findings: F1 addressed, F2 addressed, F3 addressed, F4 addressed, F5 withdrawn, F6 addressed, F7 addressed, F8 addressed, F9 withdrawn, F10 addressed, F11 addressed.

Reviewed at 610c8d6

johnml1135 added a commit that referenced this pull request Oct 22, 2026
The suite added Trace.FailureAllomorph so FailureRuleAttributor could credit
an affix rule whose allomorph failed an environment or co-occurrence check.
That is an engine API change riding in a test-suite PR, and #534 adds the
same fact as Trace.Allomorph. Drop it here; the attribution returns with
#534. No generated ledger changes: coverage.csv and rules.csv regenerate
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
johnml1135 added a commit that referenced this pull request Oct 22, 2026
The suite added Trace.FailureAllomorph so FailureRuleAttributor could credit
an affix rule whose allomorph failed an environment or co-occurrence check.
That is an engine API change riding in a test-suite PR, and #534 adds the
same fact as Trace.Allomorph. Drop it here; the attribution returns with
#534. No generated ledger changes: coverage.csv and rules.csv regenerate
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@johnml1135
johnml1135 force-pushed the fix/hc-trace-reasons branch from 610c8d6 to fc92b76 Compare October 23, 2026 11:09
@jtmaxwell3

Copy link
Copy Markdown
Collaborator

@johnml1135: Have you asked Beth about this? I'm worried that they new, detailed trace will provide too much information for the user to find analyses that failed but should have succeeded (e.g. find the needle in the haystack). Have any users reported that TryAWord doesn't provide enough information?

@johnml1135
johnml1135 force-pushed the fix/hc-trace-reasons branch from fc92b76 to bc97db6 Compare October 26, 2026 11:50
johnml1135 added a commit that referenced this pull request Oct 26, 2026
The suite added Trace.FailureAllomorph so FailureRuleAttributor could credit
an affix rule whose allomorph failed an environment or co-occurrence check.
That is an engine API change riding in a test-suite PR, and #534 adds the
same fact as Trace.Allomorph. Drop it here; the attribution returns with
#534. No generated ledger changes: coverage.csv and rules.csv regenerate
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
johnml1135 and others added 10 commits October 28, 2026 21:43
Add optional detailed trace callbacks for analysis rejections, slot branches,
and completed lexical lookup counts. Retain failure operands, blocking entries,
and partial-parse causes in TraceManager without replaying linguistic checks.

Preserve the ITraceManager member contract and verify legacy callbacks,
parallel slot outcomes, interrupted lookups, and morphological analyses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ITraceManager implementations previously received CompoundingRuleNotUnapplied only for
the productivity-restriction rejection, with subrule index -1. This branch had sent them
every new compounding gate as well. FieldWorks writes a trace node for each call, so
Try A Word would have gained a reasonless failure node per rejected compound analysis.

They now receive exactly the original call. Detailed consumers still get every gate with
its subrule index.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ting rejection callbacks unchanged

Records the rejection callbacks (name, subrule index, input identity, reason, failure object type) a manager
implementing only ITraceManager receives across affix, realizational, compounding and partial-parse scenarios.
The expected sequences equal what origin/master produces; nine of them fail at this head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… compounding subrule yields no word

Detailed managers still receive the specific Pattern or gate reason; a manager implementing only ITraceManager again
gets the three-argument callback with the input at subrule-loop exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…jections and the per-word Required rejection

ITraceManager implementations receive only the Pattern rejection through the extension, and affix subrules report
them at loop exit with the input, as before; the gates and the Required rejection reach IDetailedTraceManager only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…IDetailedTraceManager

A manager implementing only ITraceManager receives a null failure object for PartialParse at all three raise sites, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tCrab tool

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the present tense

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unknown, including a compound non-head

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A failed NonHeadRequired check cloned the word for the trace even when
the trace manager was a plain ITraceManager, which drops that reason.
Clone only for an IDetailedTraceManager, so Try A Word's tracing cost
stays where it was on master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@johnml1135
johnml1135 force-pushed the fix/hc-trace-reasons branch from bc97db6 to 15ad1dd Compare October 29, 2026 11:09
@claude

claude Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

No new findings. Reviewed at 15ad1dd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants