HermitCrab: Word.ExpandAlternatives discards Unify's success flag and can null the realizational FS
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 29
- Forks
- 17
- Avg merge
- 3d 2h
- Merged PRs (30d)
- 8
Description
Summary
Word.ExpandAlternatives (Word.cs:469-476, master a4b29742; last touched by #493 52d069f8) replays a realizational feature-structure delta onto each merged alternative like this:
if (!_realizationalFS.ValueEquals(Source._realizationalFS))
{
FeatureStruct diff = _realizationalFS.Clone();
diff.Subtract(Source._realizationalFS);
FeatureStruct newFS;
alternative._realizationalFS.Unify(diff, out newFS); // bool return discarded
alternative._realizationalFS = newFS;
}
...
alternative.Freeze();
FeatureStruct.Unify(FeatureStruct, out FeatureStruct) (FeatureStruct.cs:864-891) sets output = null and returns false when the two structures do not unify. The return value is not checked, so on a failed unify alternative._realizationalFS becomes null, and the very next statement that matters, alternative.Freeze() → Word.FreezeImpl (Word.cs:611) _realizationalFS.Freeze(), throws NullReferenceException. Nothing between the assignment and the freeze can intercept it.
When can the unify fail?
Only when two analyses merged as equivalent by AnalysisStratumRule.MergeEquivalentAnalyses (#493) later diverge in their realizational features in a way that conflicts with the delta accumulated since the merge point. Merge equivalence is keyed on shape, morphs and the realizational FS at the merge point (Word.cs:636-639), so a conflict needs the delta applied after the merge to contradict a value one alternative already carried. We have not constructed a grammar that does this; every oracle-verified fixture in the conformance suite (44 upstream, 38 staged in PanGloss) unifies cleanly here. So this is a reproduced latent defect (the null assignment is unconditional and the crash path is deterministic once reached), not yet a reproduced runtime failure.
What PanGloss does today
PanGloss's port (pg-rules/src/word.rs::expand_alternatives) keeps the alternative's previous realizational FS when the unify fails instead of nulling it. That is recorded as divergence 018 in PanGloss's ledger (docs/divergences/018-*.md) precisely because it is a silent difference from the oracle, and neither behaviour has been justified independently. This issue exists so the semantic contract is decided in HermitCrab rather than by the port.
Open question for the semantics
If an alternative's realizational FS cannot absorb the delta, what should happen? Three candidates:
- Drop the alternative. The delta describes what the current word's derivation asserted; an alternative that contradicts it is not a valid expansion. This is the option that follows from what
ExpandAlternativesis for. - Keep the alternative's prior FS (PanGloss's current behaviour). Preserves the alternative but reports realizational features that the derivation since the merge point did not actually produce.
- Keep the null and crash (current C# behaviour). Not a design, but it is what ships.
Our reading is that (1) is correct and (2) is the wrong fix, but this needs a discriminating grammar before anyone changes either engine.
Acceptance criteria
- A conformance fixture (synthetic, under
conformance/edge-cases/) whose words produce two merge-equivalent analyses with a later conflicting realizational delta, with expectations derived from an independent derivation rather than from either engine's current output. ExpandAlternativeschecksUnify's return and implements the chosen semantics; nonullis ever assigned to_realizationalFS.- Soundness: no analysis is emitted whose realizational FS was not produced by its own derivation. Recall: every analysis the pre-#493 unmerged search would have produced is still produced. Both checked by the fixture above, and separately from any performance measurement.
Related
- #493 (MergeEquivalentAnalyses) and #494 introduced the merge/expand pair this sits in; #505 tracks their remaining compatibility research; #506 tracks the zero-width identity instability in the same area.
- PanGloss ledger entry 018 will link this issue and record the fixture once one exists.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in Word.cs at ExpandAlternatives and Word.FreezeImpl, then inspect FeatureStruct.cs Unify and the merge logic referenced in AnalysisStratumRule.MergeEquivalentAnalyses. Add a synthetic fixture under conformance/edge-cases with an independently derived expected result, and use it to decide and verify the failure semantics, soundness, and recall criteria. Record the resulting fixture in PanGloss's docs/divergences/018-*.md.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100