diff --git a/.claude/skills/author-coverage-cell/SKILL.md b/.claude/skills/author-coverage-cell/SKILL.md new file mode 100644 index 000000000..3a405f889 --- /dev/null +++ b/.claude/skills/author-coverage-cell/SKILL.md @@ -0,0 +1,18 @@ +--- +name: author-coverage-cell +description: >- + Use when asked to cover, satisfy, witness, or close an obligation cell in the HermitCrab + conformance suite — anything of the form "cover cell X", "satisfy this dataflow obligation", + "add words so this chain is witnessed", "close a coverage gap", or when handed a cell id from + conformance/dataflow-obligations.tsv. Authors the minimal-pair words in an existing language + grammar and the claimed_cells entry that records the evidence, then verifies by severance rather + than by inspection. Does NOT author new grammars, new fixtures, or grammar.xml content — if the + construct is absent from every language grammar, this skill reports that and stops. +--- + +The authoritative instructions for this skill live with the fixtures, because they ship to whoever +receives `conformance/`. Read and follow: + +`conformance/skills/author-coverage-cell/SKILL.md` + +Do not follow a summary of it from memory; open the file. \ No newline at end of file diff --git a/.claude/skills/measure-authoring-quality/SKILL.md b/.claude/skills/measure-authoring-quality/SKILL.md new file mode 100644 index 000000000..1801d42e3 --- /dev/null +++ b/.claude/skills/measure-authoring-quality/SKILL.md @@ -0,0 +1,16 @@ +--- +name: measure-authoring-quality +description: >- + Use when asked to measure, score, or benchmark the conformance authoring harness — "how good is + the author skill", "what's our first-pass yield", "run the harness eval", "measure before and + after a skill revision". Runs a batch of obligation cells through author-coverage-cell without + intervention, scores first-pass yield against the production gate, and attributes every failure to + a class. Produces a run record; changes no skill and fixes no fixture. +--- + +The authoritative instructions for this skill live with the fixtures, because they ship to whoever +receives `conformance/`. Read and follow: + +`conformance/skills/measure-authoring-quality/SKILL.md` + +Do not follow a summary of it from memory; open the file. \ No newline at end of file diff --git a/.claude/skills/review-coverage-claim/SKILL.md b/.claude/skills/review-coverage-claim/SKILL.md new file mode 100644 index 000000000..a24235d4e --- /dev/null +++ b/.claude/skills/review-coverage-claim/SKILL.md @@ -0,0 +1,16 @@ +--- +name: review-coverage-claim +description: >- + Use when asked to review, verify, certify, or check a coverage claim in the HermitCrab conformance + suite — "review this claimed_cells entry", "does this word really demonstrate that cell", "check + the role attribution", or when handed an evidence card from conformance/evidence-cards/. Judges + ONLY role attribution: whether the word occupies the cell it claims. Never sets a status, never + edits a claim, never edits a grammar or an expectation. Declining is a valid outcome. +--- + +The authoritative instructions for this skill live with the fixtures, because they ship to whoever +receives `conformance/`. Read and follow: + +`conformance/skills/review-coverage-claim/SKILL.md` + +Do not follow a summary of it from memory; open the file. \ No newline at end of file diff --git a/.claude/skills/revise-coverage-harness/SKILL.md b/.claude/skills/revise-coverage-harness/SKILL.md new file mode 100644 index 000000000..bf3f6acc7 --- /dev/null +++ b/.claude/skills/revise-coverage-harness/SKILL.md @@ -0,0 +1,16 @@ +--- +name: revise-coverage-harness +description: >- + Use when asked to improve, revise, or fix the conformance authoring harness after a measurement — + "first-pass yield is low, fix the skill", "most failures are not-minimal-pair, revise the + instructions", "improve the harness based on the run record". Consumes a measurement run record, + diagnoses which instruction produced the dominant failure class, and revises exactly one thing. + Never revises without a measurement, and never touches the golden set. +--- + +The authoritative instructions for this skill live with the fixtures, because they ship to whoever +receives `conformance/`. Read and follow: + +`conformance/skills/revise-coverage-harness/SKILL.md` + +Do not follow a summary of it from memory; open the file. \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5b3fa788..518576d89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ jobs: uses: actions/setup-dotnet@v5 with: dotnet-version: | + 10.0.303 10.0.x - name: Restore dotnet tools @@ -64,6 +65,14 @@ jobs: run: dotnet build --no-restore -c Release - name: Test run: dotnet test --verbosity normal --collect:"Xplat Code Coverage" + # The semantic-coverage audit is gated by TheCheckedInCatalogMapsEveryRealSurfaceExactlyOnce + # under dotnet test, not here. That test can express what this CLI cannot: the catalog is + # deliberately an incomplete proposal backlog, so unclassified-mapping is the expected state + # rather than a regression, and the test pins it as the only diagnostic class allowed. + - name: Run conformance fixtures + run: dotnet run --no-build -c Release --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance + - name: Check coarse construct parity + run: python conformance/parity-check.py - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 env: @@ -81,6 +90,7 @@ jobs: uses: actions/setup-dotnet@v5 with: dotnet-version: | + 10.0.303 10.0.x - uses: actions/download-artifact@v7 diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml new file mode 100644 index 000000000..19de20537 --- /dev/null +++ b/.github/workflows/conformance.yml @@ -0,0 +1,71 @@ +name: Conformance + +on: + push: + branches: + - "**" + paths: + - "conformance/**" + - "src/SIL.Machine.Morphology.HermitCrab*/**" + pull_request: + paths: + - "conformance/**" + - "src/SIL.Machine.Morphology.HermitCrab*/**" + +jobs: + conformance: + name: Conformance suite + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.303 + 10.0.x + + - name: Restore dependencies + run: dotnet restore src/SIL.Machine.Morphology.HermitCrab.Conformance/SIL.Machine.Morphology.HermitCrab.Conformance.csproj + + # Gate (a): every fixture's declared parses/rejections must match what the C# oracle + # actually produces (self-check mode runs the reference engine in-process against every + # words.yaml, including budget_ms pathological fixtures). + - name: Run conformance self-check + run: >- + dotnet run --no-restore --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- + --fixtures conformance --include-pathological + + # Gate (b): --coverage-report (re)writes coverage.csv/rules.csv, which the next step checks + # for staleness, and prints any dead rules (rules exercised by zero words) to stdout. NOTE: + # on this branch, RunCoverageReport's caller in Program.cs unconditionally returns 0 -- + # it does not fail the build when dead rules are found, unlike the upstream branch this + # workflow was ported from. Making this step's own exit code the dead-rule gate would + # require changing Program.cs's dispatch, which is out of scope for this port; until that + # lands, dead rules are visible in this step's log but do not fail CI. `if: always()` so this + # still runs (and reports its own true status) even if the self-check step above failed. + - name: Run coverage report + if: always() + run: >- + dotnet run --no-restore --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- + --fixtures conformance --coverage-report + + # Gate (c): the checked-in coverage.csv/rules.csv must already reflect the fixtures as they + # stand -- generated so nobody needs to remember to refresh them, but that only holds if + # forgetting to refresh them is a CI failure. Runs after the coverage-report step (which just + # regenerated both) and `if: always()` for the same reason as above: a dead rule and a stale + # index are two different failures and must not collapse into one. + # + # conformance/fixtures.csv is intentionally NOT checked here: on this branch nothing + # regenerates it (--coverage-report only writes coverage.csv/rules.csv), so a freshness check + # against it would never catch drift -- it is a one-time snapshot from when it was ported, not + # a generated artifact. + - name: Verify generated coverage files are fresh + if: always() + run: | + if ! git diff --exit-code -- conformance/coverage.csv conformance/rules.csv; then + echo "::error::conformance/coverage.csv or rules.csv is stale relative to the fixtures (diff above). Run 'dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --coverage-report' locally and commit the result." + exit 1 + fi diff --git a/.github/workflows/counterfactual-coverage.yml b/.github/workflows/counterfactual-coverage.yml new file mode 100644 index 000000000..e86a73636 --- /dev/null +++ b/.github/workflows/counterfactual-coverage.yml @@ -0,0 +1,36 @@ +# The counterfactual sweep re-parses every conformance fixture once per grammar-observable surface with +# that surface neutralized, so it costs minutes rather than seconds. It runs on demand and weekly rather +# than per push; the cheap coverage ledger and fixture gates stay in the main CI job. +name: Counterfactual coverage + +on: + workflow_dispatch: + schedule: + - cron: "0 6 * * 1" + +jobs: + counterfactual: + name: Recompute counterfactual evidence + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.303 + 10.0.x + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore -c Release + + - name: Recompute and compare the evidence ledger + run: dotnet run --no-build -c Release --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --counterfactual --repository-root . + + - name: Run the explicit counterfactual tests + run: dotnet test tests/SIL.Machine.Morphology.HermitCrab.Tests/SIL.Machine.Morphology.HermitCrab.Tests.csproj -c Release --filter "TestCategory=Counterfactual" diff --git a/.gitignore b/.gitignore index af6b4a93c..559695986 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,12 @@ tests/SIL.Machine.Tests/Corpora/TestData/usfm/target/* tests/SIL.Machine.Tests/Corpora/TestData/project/* tests/SIL.Machine.Tests/Corpora/TestData/pretranslations.json .idea + +# Claude Code conversation exports +20??-??-??-*.txt + +# Agent scratch: test result dumps, captured logs, throwaway SDK/CLI state +.tmp/ + +# Local pre-PR review artifacts, never committed +.review/ diff --git a/Machine.sln b/Machine.sln index 0d91d2dac..eb4ead14e 100644 --- a/Machine.sln +++ b/Machine.sln @@ -45,6 +45,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SIL.Machine.Tokenization.Se EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SIL.Machine.Tokenization.SentencePiece.Tests", "tests\SIL.Machine.Tokenization.SentencePiece.Tests\SIL.Machine.Tokenization.SentencePiece.Tests.csproj", "{AB5F75C1-64B7-4E0F-A4B5-B14EB16E6DDC}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SIL.Machine.Morphology.HermitCrab.Conformance", "src\SIL.Machine.Morphology.HermitCrab.Conformance\SIL.Machine.Morphology.HermitCrab.Conformance.csproj", "{8E40C2C5-F4C5-4A41-B78A-10A43FCF0CE3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -99,6 +101,10 @@ Global {AB5F75C1-64B7-4E0F-A4B5-B14EB16E6DDC}.Debug|Any CPU.Build.0 = Debug|Any CPU {AB5F75C1-64B7-4E0F-A4B5-B14EB16E6DDC}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB5F75C1-64B7-4E0F-A4B5-B14EB16E6DDC}.Release|Any CPU.Build.0 = Release|Any CPU + {8E40C2C5-F4C5-4A41-B78A-10A43FCF0CE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E40C2C5-F4C5-4A41-B78A-10A43FCF0CE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E40C2C5-F4C5-4A41-B78A-10A43FCF0CE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E40C2C5-F4C5-4A41-B78A-10A43FCF0CE3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -116,6 +122,7 @@ Global {0BBEED18-3CC1-4BA6-8E11-603A5D2DEDC9} = {31B4F5EB-E148-4A51-84B5-B90BB8F38AD3} {09135223-6285-4268-BFA3-147BDB5B663B} = {31B4F5EB-E148-4A51-84B5-B90BB8F38AD3} {AB5F75C1-64B7-4E0F-A4B5-B14EB16E6DDC} = {66246A1C-8D45-40FB-A660-C58577122CA7} + {8E40C2C5-F4C5-4A41-B78A-10A43FCF0CE3} = {31B4F5EB-E148-4A51-84B5-B90BB8F38AD3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9F18C25E-E140-43C3-B177-D562E1628370} diff --git a/conformance/HermitCrabInput.dtd b/conformance/HermitCrabInput.dtd new file mode 100644 index 000000000..2b20bb0cf --- /dev/null +++ b/conformance/HermitCrabInput.dtd @@ -0,0 +1,618 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conformance/PROTOCOL.md b/conformance/PROTOCOL.md new file mode 100644 index 000000000..a893c60ac --- /dev/null +++ b/conformance/PROTOCOL.md @@ -0,0 +1,362 @@ +# The morphological parser conformance adapter protocol + +This document specifies, precisely enough that a third party should not need to read any engine's +source (or this repo's), what it takes for **any** morphological/phonological parser to become +testable against the fixtures under `conformance/`. The protocol is engine-agnostic: nothing here, +or in a fixture's own files, requires Machine's build, layout, or C# — only a way to run the engine +under test as a command and produce a plain TSV file. + +`SIL.Machine.Morphology.HermitCrab`'s C# implementation is this suite's **founding oracle**: every +fixture's ground truth was generated by running it, and its own `BatchCommand.cs` +(`src/SIL.Machine.Morphology.HermitCrab.Tool/BatchCommand.cs`) is where this contract's TSV format +and signature algorithm were first implemented — but HermitCrab is not a privileged consumer of the +protocol, just its first implementer (the Rust port's own CLI independently arrived at the same +3-arg `batch` contract). Any engine, for any language, implementing section 1 below is equally +conformant. + +## 1. The canonical adapter contract + +A conforming engine adapter is a single executable command: + +``` + batch [--start N] +``` + +- `` — the engine's grammar input for this fixture. For the reference representation this + is `grammar.xml` (`HermitCrabInput` XML); see section 6 for engines that cannot consume it + directly. +- `` — one word per line, blank lines ignored; shared verbatim across every engine under + test for a given fixture (never engine-specific). +- `` — the file the adapter must write its results to, in the format specified in + section 2. +- `--start N` (optional) — 0-based line index to resume at, for crash recovery on long word lists. + An adapter that doesn't need resumability may ignore this flag or not implement it; the harness + only relies on it for its own optional resume behavior, never as a correctness requirement. + +This is exactly what `hc-rs batch ` already does, so the Rust +port is adapter-conformant today with zero wrapper code. See section 7 for the one C#-specific +wrinkle, and **section 8 before implementing an engine from scratch**: `grammar.xml` alone +under-specifies the ground truth, because several `Morpher` host-configuration values that are not +part of the grammar file were baked into every fixture's `expected.tsv`. + +## 2. The output format: a 5-column TSV + +Every line of `` has exactly 5 tab-separated columns: + +``` +idx word ms status signature +``` + +- **`idx`** — 0-based index of the word in `words.txt` (matches C#'s `BatchCommand.RunSequential` + loop variable `i`). +- **`word`** — the literal word string being parsed (echoed back, so the row is self-describing + without needing to cross-reference `words.txt` by line number). +- **`ms`** — elapsed wall-clock milliseconds for parsing this one word. **Not compared** by the + harness (see section 3) — timing is informational only and is expected to vary run to run and + engine to engine. +- **`status`** — one of: + - `ok` — the parse attempt completed (regardless of whether it found any analyses — zero + analyses is a legitimate `ok` result, not a failure; see the signature column). + - `SKIPPED` — the engine could not attempt the parse at all (C#'s only case today: + `InvalidShapeException`, i.e. the word contains a character outside the grammar's character + definition table). A `SKIPPED` row's signature is always `-`. +- **`signature`** — the order-independent, sorted, semicolon-joined signature of every distinct + analysis found (see section 3 for the exact algorithm), or the literal `-` if zero analyses were + found (this is the normal, correct representation of "this word does not parse under this + grammar" — a fixture's `expect_fail: true` words). + +### The `STARTED` sentinel line + +C#'s `BatchCommand` writes a sentinel line immediately before attempting each word, so a crashed +process can be resumed from the last line written: + +``` +idx word STARTED +``` + +(3 columns, not 5.) This is a crash-recovery convenience for engines that might crash mid-word on a +long corpus; **it carries no comparison meaning** and adapters are not required to emit it (`hc-rs` +deliberately does not — it buffers results and writes the final file in one shot). The harness's TSV +parser and comparison logic (section 4) skip any line that doesn't have the 5-column `ok`/`SKIPPED` +shape, so `STARTED` lines are silently ignored wherever they appear. + +### The crash convention: `expect_crash` + +A handful of fixtures (e.g. `edge-cases/simultaneous-epenthesis-cascade`, whose founding oracle run +hit an infinite-loop detector mid-word) pin a **crash** as their ground truth, not a signature. Such +a fixture's `expected.tsv` contains only a `STARTED` sentinel line for the word that crashed the +oracle — there is no real result row, because the oracle itself died first — and its fixture +metadata (`words.yaml` front matter) carries `expect_crash: true` to make that explicit rather than +leaving the harness to infer it from an empty `expected.tsv`. + +The harness's contract for an `expect_crash` fixture: + +- The engine under test is expected to **also** crash while loading the grammar or parsing the + word (not necessarily the same exception type or message — just fail rather than complete). That + counts as a **PASS**: reproducing the crash IS conforming to the ground truth. +- If the engine crashes but `expect_crash` is **not** set, that is a **FAIL** (an unexpected engine + crash), with the engine's diagnostics shown. +- If `expect_crash` **is** set but the engine returns normally (produces output instead of + crashing), that is a **FAIL** ("expected crash, engine produced output") — the engine no longer + reproduces the bug the fixture pins. +- A harness-level problem (bad `--adapter` command, the adapter process failing to start, a + timeout, or an adapter exiting 0 without producing its output file) is never treated as a crash + match, `expect_crash` or not — it is always a plain failure/error. + +Because a crash aborts a fixture's whole word loop, crash fixtures should keep `words.txt` to a +single word: there is nothing after the crash for the harness to compare, so additional words would +never actually be exercised. + +**What `expect_crash` actually pins, and the hazard that follows from it.** For +`edge-cases/simultaneous-epenthesis-cascade`, the crash is `InfiniteLoopException`, thrown by +`EpenthesisSynthesisRewriteSubruleSpec.ApplyRhs` +(`src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/EpenthesisSynthesisRewriteSubruleSpec.cs`, +around lines 32-33) the instant a shape being built during synthesis reaches exactly 256 nodes. This +is **not** one of the host-configuration knobs in section 8 — it is a hardcoded constant, not +exposed on `Morpher` or anywhere else, so there is no value a reimplementing engine can set to opt +out of it. Conformance on this fixture therefore requires the engine under test to independently hit +some runaway condition on the same input and fail rather than complete — not because failing is +correct, but because the founding oracle failed here and the fixture's ground truth is that failure. +An engine that instead detects and terminates the same unbounded epenthesis expansion cleanly (e.g. +by finding a correct, bounded analysis, or by cycle detection that recovers rather than crashing) is, +on its own merits, the more correct engine — and is **non-conformant** on this fixture per section +4's comparison rules, because "engine returns normally" is scored as a FAIL regardless of whether the +output would have been right. Treat this fixture as pinning an implementation limitation of the +founding oracle, not a linguistic fact about the grammar it exercises. + +## 3. The signature algorithm + +For a word that parses, each distinct result contributes one signature entry: + +``` +++...| +``` + +- The morpheme-ID chain is built by walking the word's allomorphs **in morph order** + (`Word.AllomorphsInMorphOrder`), taking each allomorph's owning morpheme's `Id`, joined with `+`. +- After the `|`, the surface shape is rendered via + `Shape.ToRegexString(word.Stratum.CharacterDefinitionTable, true)` — the same character-definition + table used to load the grammar, with boundary markers included (the trailing `true` argument). +- All of a word's distinct-analysis signature strings are then **sorted ordinally** + (`StringComparer.Ordinal`) and joined with `;`. This makes the signature **order-independent**: two + runs that find the same set of analyses in a different internal search order compare equal. It + does **not** dedupe — if an engine's search legitimately produces the same signature string twice + (a duplicate, not a distinct analysis), both occurrences appear; a divergence in duplicate *count* + for an otherwise-matching signature set is not automatically a pass, see section 4 for how the + harness handles this. +- If zero analyses are found, the signature is the literal string `-` (not an empty string). + +This is a direct transcription of `BatchCommand.BuildSignature` +(`src/SIL.Machine.Morphology.HermitCrab.Tool/BatchCommand.cs`); an adapter for a new engine +reproduces this string exactly, using that engine's own morpheme IDs and its own surface-shape +rendering, for its output to be diffable against `expected.tsv`. + +**Morpheme ID / gloss naming discipline**: because the signature format compares morpheme names +literally, any engine whose grammar representation assigns different IDs to the same morphemes +(e.g. a hand-authored non-XML grammar for a fixture, see section 6) must match `grammar.xml`'s IDs +exactly, or a real match will register as a false failure. + +**Multi-character segment representations render individually parenthesized.** A character +definition whose string representation is more than one character (e.g. a digraph segment like +`"ch"`) is wrapped in its own `(...)` in the shape half of a signature, unconditionally — this comes +straight from `HermitCrabExtensions.ToRegexString`'s `if (strRep.Length > 1) sb.Append("(")`, which +fires regardless of whether the segment is otherwise ambiguous. A word `"panucho"` in a grammar that +defines `"ch"` as one segment renders as `panu(ch)o`, not `panucho`. Easy to miss when hand-deriving +an expected signature — check a grammar's character definition table for multi-character +representations before trusting a hand-written signature (see +`conformance/languages/suffixing-evidential-adjacency-chain/words.yaml`'s authoring-discipline note for a case this +actually caught). + +**Guess-stem rendering (`Guesser`/`LexicalGuess`, pinned in G1).** A guessed root has no +distinguishing marker at all in the signature string: `Morpher.LexicalGuess` builds a throwaway +`LexEntry` whose `Id` (and `Gloss`) is set to the literal matched surface substring, so the guessed +root's morph-chain component in the signature is that substring itself, indistinguishable by string +alone from a real lexical entry that happened to share the same id (e.g. word `"foos"` with root +"foo" unknown but a lexical guess pattern `[Any]*` in scope, plus a real suffix rule PL="-s", yields +signature entries `foo+PL|foos` and — because the guess pattern is also tried against the +zero-affixes candidate — `foos|foos`; pinned executably in +`tests/SIL.Machine.Morphology.HermitCrab.Tests/GuesserSignatureTests.cs`). **Separately, and more +importantly for this suite: `BatchCommand` — the CLI `batch` subcommand every conformance adapter +and oracle invocation goes through — can never produce a guess-stem parse at all.** +`SignatureFormat.ParseOneWord` (what `BatchCommand.RunSequential` and the harness's own self-check +engine both call) invokes the 2-argument `Morpher.ParseWord(word, out trace)` overload, which +hardcodes `guessRoot: false`; no CLI command in `SIL.Machine.Morphology.HermitCrab.Tool` exposes the +3-argument, `guessRoot: true` overload at all. The harness's self-check mode works around this by +calling `Morpher.ParseWord` directly with `guessRoot: true` whenever a word declares a `guess: true` +parse (`src/SIL.Machine.Morphology.HermitCrab.Conformance/Runner.cs`) — but **adapter mode +cannot**: an external engine driven through the documented `batch` contract has no way to opt into +guessing, so a fixture with a `guess: true` word is self-check-only until `BatchCommand`/the adapter +contract gains an opt-in flag for it. Concretely: the harness's adapter-mode materialization **omits +any word carrying a `guess: true` parse** from the generated `words.txt`/`expected.tsv`, so such +words are asserted by self-check only and an adapter run neither sees them nor can falsely fail on +them. + +## 4. Comparison semantics (what "pass" means) + +The harness diffs an adapter's `` against a fixture's checked-in `expected.tsv` using +these rules: + +1. Only the `word`, `status`, and `signature` columns are compared. **`idx` and `ms` are ignored** + (row identity is keyed by `word`, not `idx`, so an adapter is free to reorder rows; `ms` is pure + timing noise). +2. Any line that isn't a well-formed 5-column `idx / word / ms / status / signature` row (in + particular, any `STARTED` sentinel line) is skipped entirely before comparison. +3. A signature is parsed into its `;`-separated set of `morph-chain|shape` entries and compared as a + **multiset** — reordering the entries within a signature string is not a failure (the algorithm + already sorts them, but a hand-edited or alternate-engine `expected.tsv` reordering is tolerated + defensively), but a genuine difference in the entries themselves, or in how many times a given + entry appears, **is** a failure. +4. A `status` mismatch (`ok` vs `SKIPPED`) is always a failure. +5. A missing or extra `word` row (present in one file, absent in the other) is a failure for that + word. + +Anything outside these rules — a real signature difference, a real status difference — is a +genuine conformance failure and is reported as such, per word, and rolled up per fixture. + +## 5. Capability profiles + +Not every engine implements every grammar-model construct HermitCrab supports (the motivating case +is XAmple, SIL's AMPLE-family morphotactic parser, which has no phonological-rule engine at all). +Two mechanisms make the suite serve engines of different scope without forking it: + +- **Engine capability declaration.** Whoever invokes the harness against an engine declares that + engine's supported capability set, e.g. `--capabilities phonology` for HermitCrab/`hc-rs`, or + `--capabilities ""` (empty) for a purely morphotactic engine. Self-check mode (running the live C# + oracle in-process) always implies full capability, `phonology` included. +- **Fixture capability requirement.** Every fixture's metadata (`words.yaml` front matter) carries a + `requires` array — today the only defined value is `phonology`, meaning "this fixture's + `grammar.xml` contains at least one `PhonologicalRule` or `MetathesisRule` element." An empty/absent + `requires` is pure morphotactics, runnable by any conforming engine. The harness mechanically + re-derives this list from `grammar.xml` on every run and FAILs the fixture (a metadata error, not + a conformance failure) if the checked-in `requires` disagrees, so this can never silently drift. + +The harness computes, for each fixture, whether the engine's declared capability set is a superset +of the fixture's `requires` list. If not, the fixture is **skipped** for that engine run — reported +as `SKIPPED`, distinct from both `PASS` and `FAIL`, so a capability-limited engine's run is never +scored as if it silently passed fixtures outside its scope. New capability values are added the same +way `phonology` was: name the vocabulary word, and mechanically derive it from the fixture's +`grammar.xml` (or other grammar representation) contents, never by hand-guessing from a directory +name. + +## 6. Per-engine grammar representation + +The adapter contract's first positional argument is *the engine's grammar input for the fixture*, +not necessarily `grammar.xml` itself. `grammar.xml` (`HermitCrabInput` XML) is the default and +reference representation — every fixture ships one, and it's what the C# oracle used to generate +`expected.tsv`. An engine that cannot consume that XML directly (XAmple's case: it consumes +AMPLE-style control/dictionary files) names an alternate, per-fixture grammar file or directory in +its own registration (e.g. a `grammar.xample/` directory living alongside `grammar.xml` in the +fixture, anticipating a future XAmple adapter). +`words.txt` and `expected.tsv` are always shared across every engine tested against a fixture: one +word list, one ground truth, regardless of how many different grammar representations exist for it. + +## 7. Aside: C#'s own reference tool needs a wrapper to conform + +`SIL.Machine.Morphology.HermitCrab.Tool` (`hc.dll`) does **not** implement section 1's contract +directly, because of a pre-existing CLI shape it inherited from HermitCrab.NET: grammar loading is a +*global* `Program.Main` option (`-i `), separate from and prior to dispatching any +subcommand, and its `batch` subcommand only takes 2 positional arguments +(` `), not 3. The normal invocation is: + +``` +hc.dll -i grammar.xml -s script.txt +``` + +where `script.txt` contains one line: `batch words.txt expected.tsv` (paths relative to the fixture +directory the tool is run from). This is a real, working invocation shape — every fixture's +`expected.tsv` in this suite was generated exactly this way — it is just not literally section 1's +single 3-positional-arg command. + +Two consequences: + +- **The harness's self-check mode does not shell out to `hc.dll` at all.** It calls the `Morpher` + API in-process (loading `grammar.xml` via `XmlLanguageLoader`, building a `Morpher`, and computing + the same signature algorithm as `BatchCommand.BuildSignature`, see section 3) — this sidesteps the + CLI-shape mismatch entirely, since self-check mode never needs a CLI contract in the first place. +- If anyone ever wants to point the harness's `--adapter` flag at `hc.dll` itself (to test + adapter-mode plumbing against a known-good reference, independent of self-check mode), `hc.dll` + needs a **one-line wrapper script** that (1) writes a temporary `script.txt` containing + `batch ` with the two paths substituted in, then (2) invokes + `hc.dll -i -s `. Not required by any current acceptance criteria + (self-check plus `--adapter` against `hc-rs` suffices), but straightforward if ever needed. + +## 8. Host configuration every fixture was generated under + +`grammar.xml` fully determines a grammar's rules, but it does not determine every input to the +parse. `Morpher` (`src/SIL.Machine.Morphology.HermitCrab/Morpher.cs`) has several settable +properties that change which analyses are found for the **same** grammar and word, and every one of +this suite's `expected.tsv` files was generated with `Morpher` left at its plain constructor +defaults: both `BatchCommand`'s host (`HCContext.Compile`, +`src/SIL.Machine.Morphology.HermitCrab.Tool/HCContext.cs`) and the harness's self-check runner +construct `new Morpher(traceManager, language)` and never assign any of the properties below. A +formalism-correct reimplementation that happens to pick different values for these will diverge from +`expected.tsv` on fixtures that exercise them, with nothing in `grammar.xml` to explain why. These +defaults are pinned executably against the constructor in +`tests/SIL.Machine.Morphology.HermitCrab.Tests/MorpherTests.cs` +(`Constructor_DefaultsMatchDocumentedProtocolDefaults`). + +- **`MaxStemCount` — default `2`.** Consumed in `AnalysisCompoundingRule.Apply` + (`src/SIL.Machine.Morphology.HermitCrab/MorphologicalRules/AnalysisCompoundingRule.cs`, around + line 45): once an in-progress analysis's non-head count would reach `MaxStemCount`, the compounding + rule refuses to unapply further, so no candidate with more stems is ever produced. **Observable + difference:** a grammar whose compounding rule can in principle chain three or more stems will only + ever be analyzed as a compound of at most `MaxStemCount` stems under the reference oracle; a + reimplementation using a higher value will find compound analyses of words this suite's + `expected.tsv` shows as unparsed or as parsed with fewer stems, and a lower value will miss + compound analyses this suite's `expected.tsv` shows as found. +- **`DeletionReapplications` — default `0`.** Consumed in `AnalysisRewriteRule.Apply`'s + `ReapplyType.Deletion` case + (`src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/AnalysisRewriteRule.cs`, around line + 159): a deletion phonological rule always unapplies (recovers a deleted segment) once; it is then + permitted to reapply and recover an additional consecutive deletion up to `DeletionReapplications` + more times before the loop stops. At the default `0`, exactly one deletion is ever recovered per + rule invocation — a surface form that resulted from **two or more** consecutive applications of the + same deletion rule cannot have all of them undone, so the fully-restored underlying form is never + reached and that analysis is absent from `expected.tsv`. **Observable difference:** raising this + value changes the analysis *candidate set itself* (not just performance) — it can surface additional + valid analyses for words with multiple consecutive deletion sites that the default value's + `expected.tsv` shows as not found, or as found via a different (shorter-recovery) analysis path. +- **`MaxAlternatives` — default `0`, meaning unlimited.** Every guard on this value + (`AnalysisStratumRule.Apply`, `RuleCascade`, `RuleBatch`) is written as `value > 0 && count > + value`, so `0` disables the check entirely rather than meaning "zero alternatives." When set to a + positive number and exceeded, the analyzer throws `MaxAlternativesExceededException` + (`src/SIL.Machine/Rules/MaxAlternativesExceededException.cs`) — and nothing between there and + `Morpher.ParseWord`/`AnalyzeWord` catches it, so it propagates out of the call entirely; there is no + code path that turns an exceeded limit into a truncated-but-usable result. **Observable + difference:** since every fixture was generated with this disabled, `expected.tsv` never reflects a + truncated search — a reimplementation must not impose an undocumented alternative cap of its own + (even one intended purely as a runaway guard) without expecting to diverge on any fixture whose + search happens to exceed it, and must not silently truncate where the reference oracle would have + thrown or continued. +- **`MergeEquivalentAnalyses` — default `true`.** Consumed in `AnalysisStratumRule.Apply` + (around line 133): while unapplying rules within one stratum, intermediate analyses that end up + with identical shapes are merged into one canonical `Word`, with the others recorded on its + `Alternatives` list instead of being carried forward independently into the next stratum's search. + Every merged alternative is expanded back out (`Word.ExpandAlternatives`) immediately before + lexical lookup and synthesis (see the doc comment at `Morpher.cs` lines 86-89), so this is designed + to prune redundant search state rather than to change which analyses are ultimately found. No + fixture in this suite is known to depend on `MergeEquivalentAnalyses: false` producing a different + result than `true`, but the default is documented here because it is still host configuration this + suite's `expected.tsv` was generated under, and a reimplementation that skips the equivalent-shape + merge (most will — it is a C#-side performance optimization, not part of the formalism) must still + ensure it explores the same eventual analysis set that expansion restores. +- **`guessRoot` — see section 3's "Guess-stem rendering" discussion above.** Already documented + there: `BatchCommand`/`SignatureFormat.ParseOneWord` hardcode `guessRoot: false`, so no adapter-mode + fixture output ever reflects root-guessing, and `guess: true` words are self-check-only. Restated + here because it is host configuration in exactly the same sense as the four properties above — it + just already had its own writeup. +- **`LexEntrySelector` / `RuleSelector` — default `entry => true` / `rule => true`.** These are + host-installed predicates that can exclude specific lexical entries or specific rules from + participating in analysis/synthesis at all (checked in, e.g., `Morpher.LexicalLookup` and in each + compiled rule's `Apply`, such as `AnalysisCompoundingRule.Apply` and `AnalysisRewriteRule.Apply` + above). Neither `BatchCommand`/`HCContext` nor the harness's self-check runner ever installs a + narrower predicate, so every fixture's `expected.tsv` was generated with **every** lexical entry and + **every** rule in `grammar.xml` eligible to participate — a reimplementation must not implement any + equivalent of a partial-grammar or partial-lexicon mode (even for performance or scoping reasons) + without expecting to diverge, since there is no signal in `grammar.xml` itself that any entry or + rule was excluded. + +These are the only settable, parse-affecting properties found on `Morpher`; `XmlLanguageLoader` +(which builds the `Language` object from `grammar.xml`) does not read, set, or expose any of them — +every one of the above is host-side configuration layered on top of the grammar, never something a +grammar file itself can express or override. diff --git a/conformance/README.md b/conformance/README.md new file mode 100644 index 000000000..e83737848 --- /dev/null +++ b/conformance/README.md @@ -0,0 +1,226 @@ +# The morphological parser conformance suite + +A general-purpose, engine-agnostic conformance test suite for what a morphological/phonological +parser needs to get right, usable independently of this repo and of any one engine. + +**The goal: any grammar expressible in the HermitCrab XML, parsed correctly — with a named +asterisk.** That is the aspiration this suite is built to reach and to measure progress toward. The +asterisk is short, exact, and machine-proven rather than hand-waved: every surface named below is +proven to have **no** engine consumer — the engine contains no reference to it, so no grammar can make +it influence a parse. That single fact is recorded in two different ledgers depending on how a surface +fails to earn a counterfactual verdict: `no-consumer` in `conformance/semantic-coverage-proofs.tsv` for +a surface a fixture *does* declare but mutating it changes nothing, and `dead-schema` in +`conformance/semantic-coverage-baseline.txt` for a surface no fixture ever attempts to declare because +the engine never reads the owning element at all (recomputed by scanning +`src/SIL.Machine.Morphology.HermitCrab` for the element name, never trusted from the ledger). Both are +the same underlying claim — zero engine references — so both feed this one list. + + +Eleven surfaces across three feature areas are expressible in the DTD and consulted by **no** engine +code path: + +- **Cyclic strata and simultaneous rule order** (`no-consumer`): `Stratum/cyclicity="cyclic"` and + `Stratum/phonologicalRuleOrder="simultaneous"`. `SynthesisStratumRule.Apply` and + `AnalysisStratumRule.Apply` build the rule cascade unconditionally, with no branch point that could + select either mode. +- **Syntactic subcategorization** (`dead-schema`, six surfaces): the elements `SyntacticRule`, + `SyntacticRules`, `OutputSubcategorizationOverride`, `OutputSubcategorizationOverrides`, plus the + `OutputSubcategorizationOverride/isActive` enum (`yes` and `no`). The DTD wires these through the + `requiredSubcategorizedRules`, `subcategorizations`, `outputSubcategorization`, + `headSubcategorizedRules`, and `nonHeadSubcategorizedRules` IDREFS attributes on + `MorphologicalInput`, `MorphologicalRule`, and `CompoundingRule` — the entire feature is + unimplemented end to end, not just one element in isolation. +- **Cross-word phonological context** (`dead-schema`, three surfaces): `PreviousWord`, `NextWord`, and + `Null`, the legal children of every `PhonologicalSubrule` describing an adjacent word's shape. + + +A grammar may declare any of these; the engine ignores all eleven. Those are unimplemented formalism +features, not coverage gaps, and together they are the entire current exception list. Keeping it a +list — rather than retreating from the claim — is what makes progress toward the goal measurable. +`tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExceptionListTests.cs` pins this list +against both ledgers so a newly discovered `no-consumer` or `dead-schema` surface cannot silently drop +out of it. + +**What passing means today.** An engine reproduces the reference implementation's observable parse +behaviour — signature, status, pinned crash — on every fixture its declared capability profile +admits. "Complete" is currently an *accounting* claim: every inventory item carries an explicit +status, and uncovered means listed rather than unknown. The inventory is the formalism's surfaces, +not languages. Coverage is tracked at three levels: a surface's existence in the DTD (complete by +construction), whether it is load-bearing (evidenced, or classified impossible to evidence with a +reason), and interactions between surfaces (not yet enumerated) — closing that third level is what +remains between here and the goal. + +**Rule order is part of the contract, not an implementation detail.** A parse runs in two passes: +the word is **torn down** to find candidate stems, then **built back up** to check the rebuild +reproduces the surface it started from. This is analysis-by-synthesis — propose by stripping, +confirm by regenerating — and the engine's own vocabulary is *unapply* for the first pass and +*apply* for the second. + +| Pass | Direction | Per-stratum order | +|---|---|---| +| **Analysis** — tearing down (`unapply`) | surface inward | phonological rules unapplied **first**, then affix templates and morphological rules | +| *lexical lookup* | the hinge | each stripped form is looked up for real lexical entries; `Morpher.Synthesize` calls this, so the engine places it at the **start of the build-up** | +| **Synthesis** — building up (`apply`) | stem outward | morphological rules and affix templates first, *mutually recursive* — each may invoke the other — then phonological rules **last** | + +Strata run in declaration order building up, and reversed tearing down. Note the two passes are +mirror images: whatever runs last on the way up runs first on the way down. + +Two consequences a consumer must reproduce. **Within one stratum pass a phonological rule cannot +feed a morphological rule or template** — phonology runs after morphology in synthesis and before it +in analysis — so that class of interaction does not exist and needs no coverage. **Across strata it +can**: stratum *N*'s phonological output is stratum *N+1*'s morphological input. And because +analysis is the inverse of synthesis, an interaction that *feeds* in one direction *bleeds* in the +other, so an interaction witnessed only in synthesis is untested in the direction a proposer runs. + +The order is fixed by the engine, not by the grammar: `SynthesisStratumRule.Apply` and +`AnalysisStratumRule.Apply` build it as an unconditional cascade, which is also why +`Stratum/cyclicity` and `phonologicalRuleOrder` are inert — there is no branch point for them to +select. + +`PROTOCOL.md` specifies the adapter contract in engine-agnostic terms; +nothing in `conformance/` depends on Machine's build, layout, or C#. `SIL.Machine.Morphology.HermitCrab` +supplies the seed construct vocabulary (`constructs.txt`) and its C# engine is the **founding +oracle** that generated every fixture's ground truth, but it is not a hard boundary: any engine that +implements `PROTOCOL.md`'s contract can be validated here, declaring a partial **capability +profile** (e.g. morphotactics-only, no phonological rules) to be measured fairly against just the +subset it claims to support. + +## Shape + +``` +conformance/ + languages// grammar.xml + words.yaml -- 8 typologically-selected synthetic languages + edge-cases// grammar.xml + words.yaml -- 21 micro-grammars for things no shared grammar hosts + coverage.csv GENERATED: language x word x construct + rules.csv GENERATED: language x grammar rule id x exercising words + HermitCrabInput.dtd the published grammar DTD (byte-identical to the library's embedded copy) + schema/ Draft 2020-12 contracts for the authoring and product formats + generated/ GENERATED: the versioned JSON manifest a consumer imports +``` + +## Consuming the suite from another repository + +`words.yaml` is the single canonical authored format — the only place case data (inputs, parses, +rejections, skips, `neutralizes`) lives. There is no generated JSON restatement of it: an earlier +`hc-conformance-corpus/v1` product duplicated that ground truth into a 409KB file, and it carried +less than the 383KB of authored `words.yaml`/`grammar.xml` sources it was generated from, because +those sources hold 1011 comment lines of reasoning — why a fixture exists, what it pins — that JSON +cannot express. Two representations of the same ground truth also meant a permanent drift gate. It +has been deleted, along with `schema/conformance-corpus.schema.json`. + +What that product genuinely contributed was provenance, not case data, so that is what survives as +`generated/hc-conformance-manifest.v1.json` (`hc-conformance-manifest/v1`, `schema/conformance-manifest.schema.json`, +13KB): one entry per fixture carrying `fixtureId`, `category`, `displayLanguage`, `grammarPath`, +`grammarSha256`, `wordsPath`, `wordsSha256`, `caseCount`, and `expectedCrash`, plus top-level +`dtdPath`, `dtdSha256`, `sourceHash`, and the three format-version identifiers +(`hc-conformance-manifest/v1`, `hc-conformance-words/v1`, `sil-machine-hermit-crab-input-xml/v1`). +A consumer reads the manifest to discover fixtures and verify integrity, then reads `grammar.xml` +and `words.yaml` directly for the actual grammar and cases. Paths inside the manifest are +repository-relative, never relative to the manifest itself. + +Regenerate with `hc-conformance --generate-manifest`; `--check-manifest` verifies the checked-in +bytes and exits nonzero on drift. Both validate every grammar against the DTD and every +`words.yaml` against `schema/words.schema.json` before writing anything. + +The DTD is published at `conformance/HermitCrabInput.dtd` so a consumer that receives `conformance/` +alone — PanGloss sparse-checks-out exactly that path — can resolve it. The library keeps its own +copy at `src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd` because `XmlLanguageLoader` +reads it as an embedded resource by manifest name; a test holds the two byte-identical. When +resolving a grammar's DOCTYPE, admit only the system identifier `HermitCrabInput.dtd` and map it to +the published DTD path the manifest records. Any other external entity, network fetch, or +filesystem fallback should be refused rather than attempted. + +Exactly two files per fixture. `words.yaml` is the single ground truth: front matter (`language`, +`inspired_by`, `sources`, `requires`) plus one entry per word, each carrying a `note` and either +`parses` (`signature`/`gloss`/`rules`/`exercises`, one per distinct analysis), `expect_fail` + +`blocked_by` (well-formed input, zero valid analyses), or `expect_skip` (the oracle throws +`InvalidShapeException`, e.g. an undeclared segment — status "SKIPPED", not "ok"). Optional fields: +`provenance` (bug/PR reference), `guess` (a `LexicalGuess` parse), +`budget_ms`/`expect_crash` (edge-cases only). Signatures are authored-and-verified, never blindly +regenerated — self-check FAILs on mismatch; `--propose` prints a patch for a human to accept, never +writes. Full schema: `schema/words.schema.json`. + +## The eight languages + +| Directory | Grammar name | Simulates | +|---|---|---| +| `suffixing-vowel-harmony` | SuffixingVowelHarmony | Long-distance backness harmony, long agglutinative suffix chains, consonant-gradation allomorphy | +| `templatic-root-modification` | TemplaticRootModification | Templatic root-and-pattern morphology, stem names, OCP co-occurrence, simultaneous rewrite | +| `suffixing-extension-slot-ordering` | SuffixingExtensionSlotOrdering | Realizational rules, MPR groups, verbal reduplication, post-nasal mutation, CARP-style extension ordering | +| `metathesis-phase-isolation` | MetathesisPhaseIsolation | Infix, circumfix, reduplication, metathesis, subtractive truncation | +| `polysynthetic-stratal-derivation-chain` | PolysyntheticStratalDerivationChain | Derivation-then-inflection recursion across strata, incorporation-style compounding, guessed stems | +| `suffixing-evidential-adjacency-chain` | SuffixingEvidentialAdjacencyChain | Evidential suffix chain, morpheme-adjacency co-occurrence, `requires: []` — the XAmple-eligible, phonology-free grammar | +| `prefixal-discontinuous-slot-dependency` | PrefixalDiscontinuousSlotDependency | Left-edge position-class template, fused/discontinuous slot dependencies | +| `fusional-realizational-morphology` | FusionalRealizationalMorphology | Inflection classes, syncretism, ablaut as sole exponent, realizational blocking/suppletion | + +Each is a dense, synthetic grammar (invented lexemes and segment inventories, no orthographic claim +about any real language) where ordinary words exercise several constructs at once, rather than a +one-mechanism probe. `edge-cases/` holds the 25 things no shared grammar can host faithfully: +loader/XML-semantics probes, an `expect_crash` pin, a `budget_ms` pathological stress case, and +allomorphy/rewrite pins whose exact rule shape a naturalistic grammar wouldn't contain. + +33 fixtures and 446 cases in total, summed from `generated/hc-conformance-manifest.v1.json`. The +manifest's per-fixture `caseCount` is what `--check-manifest` verifies; these two prose totals are +hand-copied from it and have already drifted once, so read the manifest, not this sentence. + +## What the coverage numbers claim, and what they do not + +Every coverage figure here is **per surface** — one DTD element, or one enumerated attribute value. +A surface counts as covered when a fixture exercises it and, in the counterfactual ledger, +neutralizing it changes a real word's parse. That is a strong claim about each surface on its own. + +It is **not** a claim about surfaces in combination. Nothing in this suite enumerates or measures +interactions between surfaces, so a green run means "no uncovered surface is known", never "no +uncovered behaviour is known". A defect needing two or more surfaces together can sit behind +fully-covered ingredients indefinitely; one does today. Enumerating every pairwise interaction is +not the fix, since the space is combinatorial while the coverage claim is per-surface; closing this +gap needs selective, named interaction coverage instead, tracked as `conformance/interface-inventory.tsv` +(integration/edge, landed) plus a capped hand-crafted integration/chain set. + +## Coverage philosophy + +`constructs.txt` is the flat, cross-grammar checklist of grammar-model constructs every fixture's +`exercises:` values are drawn from — the coverage report cross-references against it and flags both +zero-coverage constructs and **dead rules** (a `grammar.xml` rule id no word exercises). `rules:` +per parse is a verified dimension, not aspirational: self-check runs the oracle with tracing on and +FAILs if the traced rule applications diverge from the declared list. As of this writing, 19/19 +in-scope constructs are covered (`Tracing (TraceType)` is out of scope — it was never in +`expected.tsv`'s domain). + +## Running it + +``` +# self-check: in-process C# oracle against every fixture +dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --include-pathological + +# adapter mode: materializes words.txt/expected.tsv to temp, runs an external engine +dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --adapter "" + +# coverage + dead-rule report: writes coverage.csv and rules.csv +dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --coverage-report + +# migration parity proof (v1->v2 floors + the permanent absolute construct check) +python conformance/parity-check.py +``` + +## Growth policy: every bug fix lands with a conformance addition + +> **Every bug fix in a conforming engine lands together with a conformance addition** — a new word, +> a new grammar, or a new edge-case. + +The cheap path, in order of preference: + +1. **Add a word.** One `words.yaml` entry (word + `note` + `parses` + `provenance`) in the language + whose grammar already covers the territory. No harness or grammar changes. +2. **Extend a grammar** when no existing language's grammar can express the trigger but the + phenomenon is typologically plausible for one of the eight (e.g. a new backness-harmony + interaction belongs in `suffixing-vowel-harmony`). +3. **Add an edge-case** when the pin is engine-internal or too specific to embed naturalistically + (an XML-loader quirk, a crash, a rule shape no real grammar would contain). +4. **Add a new `languages/` member** only for genuinely new typological territory not covered by any + of the eight, not for an incremental variant of one that already exists. + +## See also + +- `PROTOCOL.md` — the adapter contract: CLI shape, TSV format, signature algorithm, capability + profiles, per-engine grammar representation. diff --git a/conformance/adapters/hc-dotnet-wrapper.sh b/conformance/adapters/hc-dotnet-wrapper.sh new file mode 100644 index 000000000..a65996593 --- /dev/null +++ b/conformance/adapters/hc-dotnet-wrapper.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# Adapter-protocol wrapper for SIL.Machine.Morphology.HermitCrab.Tool (hc.dll), per +# conformance/PROTOCOL.md section 7: hc.dll's own CLI shape ("-i grammar -s script.txt", where +# script.txt contains a "batch words.txt output.tsv" line) predates and doesn't match section 1's +# single 3-positional-arg contract, so this one-line-idea wrapper bridges the two: it writes a +# temporary script.txt and invokes hc.dll the normal way. +# +# Usage (matches the protocol's canonical shape, plus one extra arg for the tool path): +# hc-dotnet-wrapper.sh batch [path/to/hc.dll] +# +# Exists so --adapter mode (SIL.Machine.Morphology.HermitCrab.Conformance's external-engine path) +# can be exercised end-to-end against a real conforming engine even when no second engine (e.g. +# hc-rs, the Rust port) is present in this checkout -- this repo's own C# oracle, run as a +# subprocess through the documented adapter contract instead of self-check mode's in-process call, +# is a legitimate (if not very interesting) conformance-testable engine in its own right. +set -euo pipefail + +if [ "${1:-}" != "batch" ]; then + echo "usage: hc-dotnet-wrapper.sh batch [path/to/hc.dll]" >&2 + exit 2 +fi +grammar="$2" +words="$3" +output="$4" + +# Resolve the default hc.dll path relative to this script's own location (repo root), not the +# caller's cwd, so the wrapper works when invoked from anywhere. An explicit 5th arg always wins, +# used exactly as given (relative to the caller's cwd, same as before). +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd "$script_dir/../.." && pwd)" + +if [ -n "${5:-}" ]; then + hcdll="$5" +else + hcdll="" + for candidate in \ + "$repo_root/src/SIL.Machine.Morphology.HermitCrab.Tool/bin/Debug/net10.0/hc.dll" \ + "$repo_root/src/SIL.Machine.Morphology.HermitCrab.Tool/bin/Release/net10.0/hc.dll" + do + if [ -f "$candidate" ]; then + hcdll="$candidate" + break + fi + done + # Neither build exists: fall through with the Debug path so the error message below points at + # the expected default location instead of silently trying an empty path. + if [ -z "$hcdll" ]; then + hcdll="$repo_root/src/SIL.Machine.Morphology.HermitCrab.Tool/bin/Debug/net10.0/hc.dll" + fi +fi + +tmpscript="$(mktemp)" +trap 'rm -f "$tmpscript"' EXIT + +printf 'batch "%s" "%s"\n' "$words" "$output" > "$tmpscript" + +# hc.dll's stdout is load-progress/prompt chatter, not adapter-contract output -- but it also +# carries load errors, which AdapterEngine needs to see in its own captured stderr on a nonzero +# exit. Redirect (not discard) it, so it's still available for diagnostics without polluting the +# adapter protocol's stdout. Now that Program.Main's script mode actually returns a nonzero exit +# code on failure (rather than always 0), `set -e` above genuinely propagates a hc.dll failure. +dotnet "$hcdll" -i "$grammar" -s "$tmpscript" >&2 diff --git a/conformance/construct-claim-corroboration.tsv b/conformance/construct-claim-corroboration.tsv new file mode 100644 index 000000000..867ff4f17 --- /dev/null +++ b/conformance/construct-claim-corroboration.tsv @@ -0,0 +1,461 @@ +# GENERATED by hc-conformance --write-coverage-traceability. One row per words.yaml +# 'exercises:' claim (self-reported by the fixture author), cross-checked against that +# fixture's OWN grammar.xml. This is a STRUCTURAL check, not a semantic one: Confirmed means +# the construct text names a DTD element/attribute this grammar actually contains, never that +# the word's parse depends on it. Contradicted means identifiers were found in the construct's +# text but none appear in this grammar -- the claim looks wrong. Unmapped means the construct's +# text contains no identifier ConstructClaimCorroboration recognizes, so it cannot be checked +# either way. matched_tokens is empty for Unmapped. signature is "-" for expect_fail/expect_skip words. +fixture word signature construct status matched_tokens +edge-cases/alpha-variable-name-collision au - Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +edge-cases/alpha-variable-name-collision ia AU|ia Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +edge-cases/bistratal-overlapping-segment-representation abis - CharacterDefinitionTable: more than one table, one per stratum Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/bistratal-overlapping-segment-representation basi - CharacterDefinitionTable: more than one table, one per stratum Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/bistratal-overlapping-segment-representation des ROOT3|des CharacterDefinitionTable: more than one table, one per stratum Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/bistratal-overlapping-segment-representation eds - CharacterDefinitionTable: more than one table, one per stratum Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/bistratal-overlapping-segment-representation sed ROOT4|sed CharacterDefinitionTable: more than one table, one per stratum Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/compounding-breadth ka KA|ka CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/compounding-breadth kaitu - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/compounding-breadth kaki - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/compounding-breadth kamtu - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/compounding-breadth kaptu - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/compounding-breadth kati - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/compounding-breadth katu KA+TU|katu CompoundingRule Confirmed CompoundingRule +edge-cases/compounding-breadth katumi - CompoundingRule Confirmed CompoundingRule +edge-cases/compounding-breadth kutu - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/compounding-breadth patu - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/compounding-breadth tu TU|tu CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +edge-cases/deep-optional-affix-nesting k K|k Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/deep-optional-affix-nesting xxxxxxxxxxxxk P12+P11+P10+P9+P8+P7+P6+P5+P4+P3+P2+P1+K|xxxxxxxxxxxxk Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments años YEAR+PL|años Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments años YEAR+PL|años AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/diacritic-segments años YEAR+PL|años MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +edge-cases/diacritic-segments añota - NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/diacritic-segments cafés COFFEE+PL|cafés Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments cafés COFFEE+PL|cafés AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/diacritic-segments cafés COFFEE+PL|cafés MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +edge-cases/diacritic-segments caféta COFFEE+DIM|caféta Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments caféta COFFEE+DIM|caféta AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/diacritic-segments caféta COFFEE+DIM|caféta MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +edge-cases/diacritic-segments caféta COFFEE+DIM|caféta NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/diacritic-segments göls LAKE+PL|göls Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments göls LAKE+PL|göls AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/diacritic-segments göls LAKE+PL|göls MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +edge-cases/diacritic-segments gölta - NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/diacritic-segments gül - Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/diacritic-segments kelîs WORD+PL|kelîs Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments kelîs WORD+PL|kelîs AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/diacritic-segments kelîs WORD+PL|kelîs MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +edge-cases/diacritic-segments kelîta WORD+DIM|kelîta Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/diacritic-segments kelîta WORD+DIM|kelîta AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/diacritic-segments kelîta WORD+DIM|kelîta MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +edge-cases/diacritic-segments kelîta WORD+DIM|kelîta NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/disjunctive-recheck gray |gray Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck grey |grey Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck pakda - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck pakza +|pakza Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck pitda +|pitda Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck pitza - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck wak |wak Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck wakta - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck wok - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/disjunctive-recheck wokta +|wokta Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/feature-gating-breadth kal KAL|kal Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth kalid KAL+PAST|kalid RealizationalAffixProcessRule Unmapped - +edge-cases/feature-gating-breadth kalidka - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/feature-gating-breadth kalidmu - RealizationalAffixProcessRule Unmapped - +edge-cases/feature-gating-breadth kalka KAL+AGR|kalka Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth kalkano KAL+AGR+LOUD|kalkano Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth kalmuid KAL+EMPH+PAST|kalmuid RealizationalAffixProcessRule Unmapped - +edge-cases/feature-gating-breadth kalnoka - Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth mol MOL|mol Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth molka - Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth nal NAL|nal Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth nalno NAL+LOUD|nalno Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth nalnomu NAL+LOUD+EMPH|nalnomu Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth tun TUN|tun Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-gating-breadth tunka - Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/feature-system-breadth ak - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +edge-cases/feature-system-breadth ask - Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +edge-cases/feature-system-breadth at AT|at NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/feature-system-breadth ik AK|ik RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +edge-cases/feature-system-breadth ikt TI+SUF|ikt MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth ikt TIK|ikt MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth isk ASK|isk Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +edge-cases/feature-system-breadth it TI|it MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth itk - MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth ka KA|ka MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth ktl - MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth sal SAL|sal NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/feature-system-breadth salk - AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +edge-cases/feature-system-breadth tal - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/feature-system-breadth ti - MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth tik - MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth tkl - MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth tlk TKL|tlk MetathesisRule Confirmed MetathesisRule +edge-cases/feature-system-breadth ts TS|ts NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/free-fluctuating-allomorph-pair kit - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/free-fluctuating-allomorph-pair kits ORD+SSFX|kits Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/free-fluctuating-allomorph-pair kot ORD|kot Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/free-fluctuating-allomorph-pair kots - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/free-fluctuating-allomorph-pair pel ALT|pel Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/free-fluctuating-allomorph-pair pol ALT|pol Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/loader-default-symbol bat |bat Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-default-symbol bdt - Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-isactive kat |kat Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-isactive sod |sod Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-isactive-breadth kol - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth kul KUL|kul Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth kul= - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth mep - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth mo+kul MO+KUL|mo+?kul Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth mukul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth otkul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth pekul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth put - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth qekul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth qokul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth qot - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth qukul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth takul TA+KUL|takul Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth tatakul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth tatatakul - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth tup - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-isactive-breadth zal - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/loader-pattern-shapes bat |b[ae]t Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-pattern-shapes bet |b[ae]t Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-pattern-shapes bit - Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/loader-pattern-shapes bt - CharacterDefinitionTable pattern shapes: optional group / Kleene star Confirmed CharacterDefinitionTable,characterDefinitionTable +edge-cases/metathesis-comparison-crash ti - MetathesisRule Confirmed MetathesisRule +edge-cases/morphotactic-attribute-breadth bak VAK|bak Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth bakgi VAK+UNBLK|bakgi Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth dom ZOM|dom Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/morphotactic-attribute-breadth kul KUL|kul Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth kulba - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth kulbubidu KUL+MB+MA+MREQ|kulbubidu MPR features/groups Unmapped - +edge-cases/morphotactic-attribute-breadth kulde KUL+TWICE|kulde Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth kuldede KUL+TWICE|kuldede Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth kuldedede - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth kulgi KUL+UNBLK|kulgi MPR features/groups Unmapped - +edge-cases/morphotactic-attribute-breadth kulgimo KUL+UNBLK+PART|kulgimo Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/morphotactic-attribute-breadth kulmo KUL+PART|kulmo Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth kulmoru KUL+PART+REAL|kulmoru Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/morphotactic-attribute-breadth kulpu - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/morphotactic-attribute-breadth kulru KUL+REAL|kulru RealizationalAffixProcessRule Unmapped - +edge-cases/morphotactic-attribute-breadth kulsi - Element deactivation (isActive) across loader collections Confirmed isActive +edge-cases/morphotactic-attribute-breadth kur - Disjunctive allomorphs / free-fluctuation Unmapped - +edge-cases/morphotactic-attribute-breadth nap NAP|nap Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth napmo - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth pog POG|pog Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth pogli POG+POGAFX|pogli Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/morphotactic-attribute-breadth pogliti POG+POGAFX+PO|pogliti Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth pogti POG+PO|pogti Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth rog ROG|rog Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/morphotactic-attribute-breadth sim SIM|sim Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +edge-cases/morphotactic-attribute-breadth simru SIM+REAL|simru Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth sol - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +edge-cases/morphotactic-attribute-breadth top TOP|top Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Contradicted requiredStemName +edge-cases/morphotactic-attribute-breadth topsakanabu TOP+COA+COB+COD+MB|topsakanabu Affix template slots (obligatory/disjunctive/ordering) Unmapped - +edge-cases/morphotactic-attribute-breadth topsakatana TOP+COA+COB+COC+COD|topsakatana MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +edge-cases/mpr-gated-exception menulik NPFX+TULIK|menulik RewriteRule direction (Dir): left-to-right Unmapped - +edge-cases/mpr-group-overwrite-without-realizational udof THEMEA+DOF|udof MPR features/groups Unmapped - +edge-cases/mpr-group-overwrite-without-realizational udofq THEMEA+DOF+ENDC|udofq MPR features/groups Unmapped - +edge-cases/mpr-group-overwrite-without-realizational wudof THEMEB+THEMEA+DOF|wudof MPR features/groups Unmapped - +edge-cases/mpr-group-overwrite-without-realizational wudofq - MPR features/groups Unmapped - +edge-cases/process-morphology-in-place-mutation a ROOT+ABLAUT|a MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext Confirmed InsertSimpleContext,ModifyFromInput +edge-cases/right-to-left-anchor-environment aa - RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment aaa - RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment aae ROOT1|aae RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment ae ROOT2|ae RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment aea - RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment eaa - RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment eaaa - RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment eeae ROOT3|eeae RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/right-to-left-anchor-environment eeee - RewriteRule direction (Dir): right-to-left Unmapped - +edge-cases/stem-name-restricted-root-allomorph kap - Stem names Unmapped - +edge-cases/stem-name-restricted-root-allomorph kapom ROOT+PERS1|kapom Stem names Unmapped - +edge-cases/stem-name-restricted-root-allomorph kapur - Stem names Unmapped - +edge-cases/stem-name-restricted-root-allomorph tam ROOT|tam Stem names Unmapped - +edge-cases/stem-name-restricted-root-allomorph tamom - Stem names Unmapped - +edge-cases/stem-name-restricted-root-allomorph tamur ROOT+PERS2|tamur Stem names Unmapped - +edge-cases/strrep-identity imat ++|[(^0)∅]?+?i+?mat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity imat ++|i+?[(^0)∅]?+?mat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity imat +|i+?mat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity ipat - NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity mat +|[(^0)∅]?+?mat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity mat |mat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity mumat +|mu+?mat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity mupat +|mu+?pat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity muuta - NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity mwpat - NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity mwuta +|mw+?uta NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity ndmat - NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity ndpat ++|[(^0)∅]?+?nd+?pat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity ndpat ++|nd+?[(^0)∅]?+?pat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity ndpat +|nd+?pat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity pat +|[(^0)∅]?+?pat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/strrep-identity pat |pat NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +edge-cases/subrule-morphosyntactic-gating bat ROOT1+DERIVE|bat RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level Unmapped - +edge-cases/subrule-morphosyntactic-gating pat ROOT1|pat RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level Unmapped - +edge-cases/truncate-morphotactic ag +|ag AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic as +|as AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic bag - AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic bubibi |bubibi AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic gas ++|gas AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic gas +|gas AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic gbubibi +|gbubibi AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic sa +|sa AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic sag |sag AffixProcessRule: subtraction/truncation Unmapped - +edge-cases/truncate-morphotactic sas |sas AffixProcessRule: subtraction/truncation Unmapped - +languages/fusional-realizational-morphology benox BEPFX1+NOXV|benox AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/fusional-realizational-morphology corriv BLOCKHEAD+BLOCKNON|cor+?riv CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +languages/fusional-realizational-morphology ducit - RealizationalAffixProcessRule Unmapped - +languages/fusional-realizational-morphology ducunt DUC+PL2|ducunt RealizationalAffixProcessRule Unmapped - +languages/fusional-realizational-morphology feres FER+TENSE|feres RealizationalAffixProcessRule Unmapped - +languages/fusional-realizational-morphology feresid - RealizationalAffixProcessRule Unmapped - +languages/fusional-realizational-morphology ferid FER+RPAST|ferid RealizationalAffixProcessRule Unmapped - +languages/fusional-realizational-morphology ficlav FIC+LAV|fic+?lav CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +languages/fusional-realizational-morphology gelobt GET+LOB|gelobt AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/fusional-realizational-morphology gelobth GET+LOB+S3|gelobth AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/fusional-realizational-morphology gelobthh - AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/fusional-realizational-morphology genlav - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +languages/fusional-realizational-morphology gofhw - MPR features/groups Unmapped - +languages/fusional-realizational-morphology gofwh GOF+ENDW+ENDH|gofwh MPR features/groups Unmapped - +languages/fusional-realizational-morphology gofwz - MPR features/groups Unmapped - +languages/fusional-realizational-morphology gofz GOF+ENDZ|gofz MPR features/groups Unmapped - +languages/fusional-realizational-morphology gofzw GOF+ENDZ+ENDW|gofzw MPR features/groups Unmapped - +languages/fusional-realizational-morphology kath - MPR features/groups Unmapped - +languages/fusional-realizational-morphology katw KAT+ENDW|katw MPR features/groups Unmapped - +languages/fusional-realizational-morphology lexbedom LEX+BEPFX2+DOMV|lex+?bedom CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology lexbex - CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology lexdom LEX+DOMN|lex+?dom CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology lexdom LEX+DOMV|lex+?dom CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology limh - MPR features/groups Unmapped - +languages/fusional-realizational-morphology limw - MPR features/groups Unmapped - +languages/fusional-realizational-morphology lobh LOB+S3|lobh AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/fusional-realizational-morphology man - Stem names Unmapped - +languages/fusional-realizational-morphology mano STEM+P1|mano Stem names Unmapped - +languages/fusional-realizational-morphology mans STEM+P2|mans Stem names Unmapped - +languages/fusional-realizational-morphology mant - Stem names Unmapped - +languages/fusional-realizational-morphology min - Stem names Unmapped - +languages/fusional-realizational-morphology mino STEM+P1|mino Stem names Unmapped - +languages/fusional-realizational-morphology mins - Stem names Unmapped - +languages/fusional-realizational-morphology mint STEM+P3|mint Stem names Unmapped - +languages/fusional-realizational-morphology mitlav MIT+LAV|mit+?lav CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +languages/fusional-realizational-morphology mitlavlav - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +languages/fusional-realizational-morphology mun STEM|mun Stem names Unmapped - +languages/fusional-realizational-morphology muno - Stem names Unmapped - +languages/fusional-realizational-morphology muns - Stem names Unmapped - +languages/fusional-realizational-morphology munt - Stem names Unmapped - +languages/fusional-realizational-morphology panbenox - CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology pandex - CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology pannox PAN+NOXN|pan+?nox CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology pannox PAN+NOXV|pan+?nox CompoundingRule Confirmed CompoundingRule +languages/fusional-realizational-morphology sang SING+ABLAUT|sang MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext Confirmed InsertSimpleContext,ModifyFromInput +languages/fusional-realizational-morphology seclav - CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) Confirmed CompoundingRule +languages/fusional-realizational-morphology sodh SOD+ENDH|sodh MPR features/groups Unmapped - +languages/fusional-realizational-morphology sodw - MPR features/groups Unmapped - +languages/fusional-realizational-morphology tul TUL|tul RealizationalAffixProcessRule Unmapped - +languages/fusional-realizational-morphology vinc VIC+PRESSTEM|vinc AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/fusional-realizational-morphology xped THEMEX+PED|xped MPR features/groups Unmapped - +languages/fusional-realizational-morphology xpedz THEMEX+PED+ENDZ|xpedz MPR features/groups Unmapped - +languages/fusional-realizational-morphology ygofz - MPR features/groups Unmapped - +languages/fusional-realizational-morphology yxped THEMEY+THEMEX+PED|yxped MPR features/groups Unmapped - +languages/fusional-realizational-morphology yxpedz - MPR features/groups Unmapped - +languages/metathesis-phase-isolation bahain BAHA+LNK|bahain AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/metathesis-phase-isolation bahain BAHA+LNK|bahain MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +languages/metathesis-phase-isolation idil - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/metathesis-phase-isolation katabɯd - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/metathesis-phase-isolation katibɯd KTB+PERF|katibɯd AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/metathesis-phase-isolation katibɯd KTB+PERF|katibɯd RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/metathesis-phase-isolation keadilan NMLZ+ADIL|keadilan AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/metathesis-phase-isolation keadilan NMLZ+ADIL|keadilan MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +languages/metathesis-phase-isolation mu+i MI+3SGU|mu+?i Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/metathesis-phase-isolation mu+i MI+3SGU|mu+?i MetathesisRule Confirmed MetathesisRule +languages/metathesis-phase-isolation niu - MetathesisRule Confirmed MetathesisRule +languages/metathesis-phase-isolation nui NIU|nui MetathesisRule Confirmed MetathesisRule +languages/metathesis-phase-isolation pui PU+3SGI|pui AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/metathesis-phase-isolation pur PURE+INCP|pur AffixProcessRule: subtraction/truncation Unmapped - +languages/metathesis-phase-isolation sumulat SULAT+AV|sumulat AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/metathesis-phase-isolation sumulat SULAT+AV|sumulat MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +languages/metathesis-phase-isolation tulatula RDPL+TULA|tulatula AffixProcessRule: reduplication (ReduplicationHint) Unmapped - +languages/metathesis-phase-isolation tutula RDP+TULA|tutula AffixProcessRule: reduplication (ReduplicationHint) Unmapped - +languages/polysynthetic-stratal-derivation-chain akupitat - CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain akutas - CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain akutat AKU+TATN|aku+?tat Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/polysynthetic-stratal-derivation-chain akutat AKU+TATN|aku+?tat CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain akutat AKU+TATV|aku+?tat Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/polysynthetic-stratal-derivation-chain akutat AKU+TATV|aku+?tat CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain bubu DR1|bubu RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain bubu DR2|bubu RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain bubu DR3|bubu RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain buibu - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain buiibuii - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain buuubuuu MDC|buuubuuu RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain kuiikuii - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain kuuukuuu MS|kuuukuuu RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain matu - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain mau MDC2|mau RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain nunaliq NUNA+DERIV|nunaliq AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/polysynthetic-stratal-derivation-chain nunaliqvuq NUNA+DERIV+INFL|nunaliqvuq AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/polysynthetic-stratal-derivation-chain nunaliqvuq NUNA+DERIV+INFL|nunaliqvuq Stratum (Linear/Unordered rule order) Confirmed Stratum +languages/polysynthetic-stratal-derivation-chain nunavuq - Stratum (Linear/Unordered rule order) Confirmed Stratum +languages/polysynthetic-stratal-derivation-chain pitat PIPFX1+TATV|pitat AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/polysynthetic-stratal-derivation-chain silaaku - CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain silamak - CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain silamanuk SILA+MAPFX2+NUKV|sila+?manuk CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain silanuk SILA+NUKN|sila+?nuk Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/polysynthetic-stratal-derivation-chain silanuk SILA+NUKN|sila+?nuk CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain silanuk SILA+NUKV|sila+?nuk Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/polysynthetic-stratal-derivation-chain silanuk SILA+NUKV|sila+?nuk CompoundingRule Confirmed CompoundingRule +languages/polysynthetic-stratal-derivation-chain takuvuq taku+INFL|takuvuq Guesser/LexicalGuess Unmapped - +languages/polysynthetic-stratal-derivation-chain takuvuq taku+INFL|takuvuq Guesser/LexicalGuess Unmapped - +languages/polysynthetic-stratal-derivation-chain takuvuq takuvuq|takuvuq Guesser/LexicalGuess Unmapped - +languages/polysynthetic-stratal-derivation-chain takuvuq takuvuq|takuvuq Guesser/LexicalGuess Unmapped - +languages/polysynthetic-stratal-derivation-chain utui - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain uui MDC3|uui RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/polysynthetic-stratal-derivation-chain uuu - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/prefixal-discontinuous-slot-dependency bishiwodkal - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency bishiyidkal OBJ+SBJ+PRF+CLF+KAL|bishiyidkal Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency gabishiyidkal ADVA+OBJ+SBJ+PRF+CLF+KAL|gabishiyidkal Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency gahobishiyidkal - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency hogabishiyidkal ADVB+ADVA+OBJ+SBJ+PRF+CLF+KAL|hogabishiyidkal Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency kal - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency niyidtan SBJ+PRF+CLF+TAN|niyidtan Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency shiwodkal SBJ+IMPF+CLF+KAL|shiwodkal Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency shiyidkal SBJ+PRF+CLF+KAL|shiyidkal Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/prefixal-discontinuous-slot-dependency yidkal - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain kantancha - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain kantay SING+1SG|kantay MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain sipulupachikmi - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain sipulupami SIPU+2PL+DIR|sipulupami MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain sipun SIPU+3SG|sipun Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain sipuncha SIPU+3SG+CONJ|sipun(ch)a MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain siputuku - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain siputukuchikmi SIPU+1PL.INCL+PL+DIR|siputuku(ch)ikmi MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain siputukumi SIPU+1PL.INCL+DIR|siputukumi MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain sipuy SIPU+1SG|sipuy Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain sipuymi SIPU+1SG+DIR|sipuymi Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain takincha SING+3SG+CONJ|takin(ch)a MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain takiy SING+1SG|takiy Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain tupay TUPA+1SG|tupay Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain tupay TUPA2+1SG|tupay Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain walakchik - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain walakni WALAK+1SG|walakni Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain walaknichik WALAK+1SG+PL|walakni(ch)ik Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain walaknichiktan WALAK+1SG+PL+ASSUM|walakni(ch)iktan MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain walaknichikwas - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain walaknitan WALAK+1SG+ASSUM|walaknitan MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain walakniwas WALAK+1SG+MIR|walakniwas MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain walaknki WALAK+2SG|walaknki Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain walaknkicha - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain walaknkichikmi WALAK+2SG+PL+DIR|walaknki(ch)ikmi Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-evidential-adjacency-chain walaknkishi WALAK+2SG+REP|walaknki(sh)i Disjunctive allomorphs / free-fluctuation Unmapped - +languages/suffixing-evidential-adjacency-chain walaknkisi WALAK+2SG+REP|walaknkisi Disjunctive allomorphs / free-fluctuation Unmapped - +languages/suffixing-evidential-adjacency-chain walakntan - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/suffixing-evidential-adjacency-chain walaky - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering andik - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering andika AND+FV|andika Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering andikila AND+APPL+FV|andikila Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering andikilisha AND+APPL+CAUS+FV|andikilisha Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering andikisha AND+CAUS+FV|andikisha Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering andikishila AND+CAUS+APPL+FV|andikishila Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-extension-slot-ordering belh BEL+ENDH|belh MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering belw - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering dabep DAB+NUMPL|dabep Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +languages/suffixing-extension-slot-ordering dabepez DAB+NUMPL+AGR|dabepez Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +languages/suffixing-extension-slot-ordering dabez DAB+AGR|dabez Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +languages/suffixing-extension-slot-ordering daheh - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering daleh DAL+STEMREQ|daleh Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering dalehiz - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering dalizeh DAL+RECURSUF+STEMREQ|dalizeh Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering kes KES|kes Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +languages/suffixing-extension-slot-ordering kesepez KES+NUMPL+AGR|kesepez Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +languages/suffixing-extension-slot-ordering kesez - Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) Confirmed OutputFootFeatures,OutputHeadFeatures,RequiredFootFeatures,RequiredHeadFeatures +languages/suffixing-extension-slot-ordering kibh - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering kibw KIB+ENDW|kibw MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering kimbiakimbia KIMB+RED|kimbiakimbia AffixProcessRule: reduplication (ReduplicationHint) Unmapped - +languages/suffixing-extension-slot-ordering limaile LIM+RPAST|limaile RealizationalAffixProcessRule Unmapped - +languages/suffixing-extension-slot-ordering limape LIM+TENSE|limape RealizationalAffixProcessRule Unmapped - +languages/suffixing-extension-slot-ordering limapeile - RealizationalAffixProcessRule Unmapped - +languages/suffixing-extension-slot-ordering lisez PHXROOT+PHXSRC|lisez MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering mba PAV|mba RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-extension-slot-ordering mbe - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering mpa - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-extension-slot-ordering nalh - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering nalw - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering nba PPO|nba RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level Unmapped - +languages/suffixing-extension-slot-ordering nbael - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering npa - RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level Unmapped - +languages/suffixing-extension-slot-ordering npael PPO+PHDESTROY|npael MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering sekhw - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering sekwh SEK+ENDW+ENDH|sekwh MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering sekwz - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering sekzw SEK+ENDZ+ENDW|sekzw MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering siliz SIL+RECURSUF|siliz Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering siliziz - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering xkib EXTX+KIB|xkib MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering xkibz EXTX+KIB+ENDZ|xkibz MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering yxkib EXTY+EXTX+KIB|yxkib MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering yxkibz - MPR features/groups Unmapped - +languages/suffixing-extension-slot-ordering zamed - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-extension-slot-ordering zimed - Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) Confirmed requiredStemName +languages/suffixing-vowel-harmony duii - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony duy DUII|duy RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony esalik - AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/suffixing-vowel-harmony etemik - AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/suffixing-vowel-harmony guan GAN+INTS|guan AffixProcessRule: prefix/suffix/circumfix/infix Unmapped - +languages/suffixing-vowel-harmony kalit - Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +languages/suffixing-vowel-harmony kalit - RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony kalitin - Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +languages/suffixing-vowel-harmony kalitin - RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony kalut KALT|kalut Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +languages/suffixing-vowel-harmony kalut KALT|kalut RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony kalutun KALT+ALPHA|kalutun Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +languages/suffixing-vowel-harmony kalutun KALT+ALPHA|kalutun RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony kutagida KUTAK+PAST|kutagida Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony kutagida KUTAK+PAST|kutagida Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/suffixing-vowel-harmony kutagida KUTAK+PAST|kutagida NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision Confirmed FeatureNaturalClass,SegmentNaturalClass,Segments,naturalClass +languages/suffixing-vowel-harmony kutagida KUTAK+PAST|kutagida RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony kutagida KUTAK+PAST|kutagida RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony kutagila KUTAK+PRES|kutagila Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony kutagila KUTAK+PRES|kutagila Boundary markers (CharacterDefinitionTable) Confirmed CharacterDefinitionTable,characterDefinitionTable +languages/suffixing-vowel-harmony kutagila KUTAK+PRES|kutagila RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony kutagila KUTAK+PRES|kutagila RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony kutak - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony kutakler - Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony satun SAT+ALPHA|satun Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +languages/suffixing-vowel-harmony semitide SEMIT+PAST|semitide Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony semitide SEMIT+PAST|semitide RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony semitideler SEMIT+PAST+PL|semitideler Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony semitile SEMIT+PRES|semitile Affix template slots (obligatory/disjunctive/ordering) Unmapped - +languages/suffixing-vowel-harmony semitile SEMIT+PRES|semitile RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony setin SET+ALPHA|setin Alpha-variable phonological environments (VariableFeature/AlphaVariables) Confirmed AlphaVariables,VariableFeature,variableFeature +languages/suffixing-vowel-harmony sueb SUEEB|sueb RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony sueeb - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony unitide UNT+PAST|unitide RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/suffixing-vowel-harmony unitide UNT+PAST|unitide RewriteRule Simultaneous Unmapped - +languages/suffixing-vowel-harmony untda - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification gigigi - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification gigigi - RewriteRule Simultaneous Unmapped - +languages/templatic-root-modification gigugi FEEDITER|gigugi RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification gigugu FEEDSIM|gigugu RewriteRule Simultaneous Unmapped - +languages/templatic-root-modification halak HLK|halak Stem names Unmapped - +languages/templatic-root-modification halaku - Stem names Unmapped - +languages/templatic-root-modification hilaka - Stem names Unmapped - +languages/templatic-root-modification hilaki HLK+PERF|hilaki Stem names Unmapped - +languages/templatic-root-modification hilaku HLK+IMPF|hilaku Stem names Unmapped - +languages/templatic-root-modification hulaka HLK+JUSS|hulaka Stem names Unmapped - +languages/templatic-root-modification hulaki HLK+PERF|hulaki Stem names Unmapped - +languages/templatic-root-modification hulaku - Stem names Unmapped - +languages/templatic-root-modification iktub KTUB|iktub RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification kataba KTB+P3SG|kataba MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +languages/templatic-root-modification katabit KTB+P1SG|katabit MorphologicalOutputAction: CopyFromInput/InsertSegments Confirmed CopyFromInput,InsertSegments +languages/templatic-root-modification katabit KTB+P1SG|katabit RewriteRule Simultaneous Unmapped - +languages/templatic-root-modification katabt - RewriteRule Simultaneous Unmapped - +languages/templatic-root-modification ktub - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification qil QWL+PASS|qil MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext Confirmed InsertSimpleContext,ModifyFromInput +languages/templatic-root-modification rada - RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification radda RAD|radda RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) Unmapped - +languages/templatic-root-modification samm - MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule Confirmed AllomorphCoOccurrenceRule,MorphemeCoOccurrenceRule +languages/templatic-root-modification sapr SPR+FORMII|sapr MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext Confirmed InsertSimpleContext,ModifyFromInput diff --git a/conformance/constructs.txt b/conformance/constructs.txt new file mode 100644 index 000000000..3b144f82b --- /dev/null +++ b/conformance/constructs.txt @@ -0,0 +1,47 @@ +# HermitCrab grammar-model construct checklist +# +# This is the coverage-report key set: every conformance/languages//words.yaml and +# conformance/edge-cases//words.yaml's per-parse and per-word "exercises:" entries are +# expected to draw their values verbatim from this list. It is a data file, not compiled code, so a +# new construct can be added here the moment a fixture needs it, without touching the harness. +# +# Format: one construct per line. Blank lines and lines starting with "#" are ignored. A line's +# text (verbatim, including punctuation) is the key the coverage report (--coverage-report) +# cross-references against every word's/parse's "exercises:" entries, emitting coverage.csv and +# flagging both zero-coverage constructs and dead rules (grammar.xml rule ids no word exercises, +# emitted in rules.csv). This file IS the grammar-model construct checklist; add a new row's +# construct text here the moment a fixture needs it, so the report picks it up. +# +# The harness treats an "exercises:" value that ISN'T in this file as a soft warning (a genuinely +# new construct, or a typo) -- never a hard error. + +Stratum (Linear/Unordered rule order) +AffixProcessRule: prefix/suffix/circumfix/infix +AffixProcessRule: reduplication (ReduplicationHint) +AffixProcessRule: subtraction/truncation +RealizationalAffixProcessRule +CompoundingRule +MorphologicalOutputAction: CopyFromInput/InsertSegments +MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext +RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +RewriteRule Simultaneous +RewriteRule direction (Dir): left-to-right +RewriteRule direction (Dir): right-to-left +RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level +MetathesisRule +Affix template slots (obligatory/disjunctive/ordering) +NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +Boundary markers (CharacterDefinitionTable) +CharacterDefinitionTable: more than one table, one per stratum +MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +MPR features/groups +Guesser/LexicalGuess +Disjunctive allomorphs / free-fluctuation +Stem names +Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +Alpha-variable phonological environments (VariableFeature/AlphaVariables) +CharacterDefinitionTable pattern shapes: optional group / Kleene star +CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +Tracing (TraceType) +Element deactivation (isActive) across loader collections diff --git a/conformance/coverage.csv b/conformance/coverage.csv new file mode 100644 index 000000000..97cb60dca --- /dev/null +++ b/conformance/coverage.csv @@ -0,0 +1,453 @@ +language,word,signature,construct +AlphaVariableNameCollision,au,,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +AlphaVariableNameCollision,ia,AU|ia,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +BistratalOverlappingSegmentRepresentation,des,ROOT3|des,"CharacterDefinitionTable: more than one table, one per stratum" +BistratalOverlappingSegmentRepresentation,sed,ROOT4|sed,"CharacterDefinitionTable: more than one table, one per stratum" +BistratalOverlappingSegmentRepresentation,basi,,"CharacterDefinitionTable: more than one table, one per stratum" +BistratalOverlappingSegmentRepresentation,abis,,"CharacterDefinitionTable: more than one table, one per stratum" +BistratalOverlappingSegmentRepresentation,eds,,"CharacterDefinitionTable: more than one table, one per stratum" +CompoundingBreadth,ka,KA|ka,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +CompoundingBreadth,tu,TU|tu,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +CompoundingBreadth,katu,KA+TU|katu,CompoundingRule +CompoundingBreadth,katumi,,CompoundingRule +CompoundingBreadth,kaki,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +CompoundingBreadth,kati,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +CompoundingBreadth,kamtu,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +CompoundingBreadth,kaptu,,Element deactivation (isActive) across loader collections +CompoundingBreadth,kaitu,,Element deactivation (isActive) across loader collections +CompoundingBreadth,kutu,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +CompoundingBreadth,patu,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +PathologicalDeepOptionalAffixNesting,k,K|k,Affix template slots (obligatory/disjunctive/ordering) +PathologicalDeepOptionalAffixNesting,xxxxxxxxxxxxk,P12+P11+P10+P9+P8+P7+P6+P5+P4+P3+P2+P1+K|xxxxxxxxxxxxk,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,años,YEAR+PL|años,AffixProcessRule: prefix/suffix/circumfix/infix +LatinDiacriticProbe,años,YEAR+PL|años,MorphologicalOutputAction: CopyFromInput/InsertSegments +LatinDiacriticProbe,años,YEAR+PL|años,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,cafés,COFFEE+PL|cafés,AffixProcessRule: prefix/suffix/circumfix/infix +LatinDiacriticProbe,cafés,COFFEE+PL|cafés,MorphologicalOutputAction: CopyFromInput/InsertSegments +LatinDiacriticProbe,cafés,COFFEE+PL|cafés,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,göls,LAKE+PL|göls,AffixProcessRule: prefix/suffix/circumfix/infix +LatinDiacriticProbe,göls,LAKE+PL|göls,MorphologicalOutputAction: CopyFromInput/InsertSegments +LatinDiacriticProbe,göls,LAKE+PL|göls,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,kelîs,WORD+PL|kelîs,AffixProcessRule: prefix/suffix/circumfix/infix +LatinDiacriticProbe,kelîs,WORD+PL|kelîs,MorphologicalOutputAction: CopyFromInput/InsertSegments +LatinDiacriticProbe,kelîs,WORD+PL|kelîs,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,caféta,COFFEE+DIM|caféta,AffixProcessRule: prefix/suffix/circumfix/infix +LatinDiacriticProbe,caféta,COFFEE+DIM|caféta,MorphologicalOutputAction: CopyFromInput/InsertSegments +LatinDiacriticProbe,caféta,COFFEE+DIM|caféta,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,caféta,COFFEE+DIM|caféta,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +LatinDiacriticProbe,kelîta,WORD+DIM|kelîta,AffixProcessRule: prefix/suffix/circumfix/infix +LatinDiacriticProbe,kelîta,WORD+DIM|kelîta,MorphologicalOutputAction: CopyFromInput/InsertSegments +LatinDiacriticProbe,kelîta,WORD+DIM|kelîta,Affix template slots (obligatory/disjunctive/ordering) +LatinDiacriticProbe,kelîta,WORD+DIM|kelîta,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +LatinDiacriticProbe,añota,,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +LatinDiacriticProbe,gölta,,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +LatinDiacriticProbe,gül,,Boundary markers (CharacterDefinitionTable) +DisjunctiveRecheckProbe,wak,|wak,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,wok,,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,wakta,,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,wokta,+|wokta,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,pakza,+|pakza,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,pakda,,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,pitza,,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,pitda,+|pitda,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,gray,|gray,Disjunctive allomorphs / free-fluctuation +DisjunctiveRecheckProbe,grey,|grey,Disjunctive allomorphs / free-fluctuation +FeatureGatingBreadth,kal,KAL|kal,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,kalka,KAL+AGR|kalka,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,tun,TUN|tun,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,tunka,,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,mol,MOL|mol,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,molka,,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,kalid,KAL+PAST|kalid,RealizationalAffixProcessRule +FeatureGatingBreadth,kalidka,,Affix template slots (obligatory/disjunctive/ordering) +FeatureGatingBreadth,nal,NAL|nal,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,nalno,NAL+LOUD|nalno,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,nalnomu,NAL+LOUD+EMPH|nalnomu,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,kalkano,KAL+AGR+LOUD|kalkano,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,kalnoka,,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +FeatureGatingBreadth,kalmuid,KAL+EMPH+PAST|kalmuid,RealizationalAffixProcessRule +FeatureGatingBreadth,kalidmu,,RealizationalAffixProcessRule +FeatureSystemBreadth,ik,AK|ik,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +FeatureSystemBreadth,ak,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +FeatureSystemBreadth,at,AT|at,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +FeatureSystemBreadth,sal,SAL|sal,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +FeatureSystemBreadth,isk,ASK|isk,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +FeatureSystemBreadth,ask,,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +FeatureSystemBreadth,it,TI|it,MetathesisRule +FeatureSystemBreadth,ti,,MetathesisRule +FeatureSystemBreadth,ikt,TI+SUF|ikt,MetathesisRule +FeatureSystemBreadth,ikt,TIK|ikt,MetathesisRule +FeatureSystemBreadth,itk,,MetathesisRule +FeatureSystemBreadth,tik,,MetathesisRule +FeatureSystemBreadth,ka,KA|ka,MetathesisRule +FeatureSystemBreadth,tkl,,MetathesisRule +FeatureSystemBreadth,tlk,TKL|tlk,MetathesisRule +FeatureSystemBreadth,ktl,,MetathesisRule +FeatureSystemBreadth,ts,TS|ts,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +FeatureSystemBreadth,salk,,AffixProcessRule: prefix/suffix/circumfix/infix +FeatureSystemBreadth,tal,,Element deactivation (isActive) across loader collections +FreeFluctuatingAllomorphPair,pol,ALT|pol,Disjunctive allomorphs / free-fluctuation +FreeFluctuatingAllomorphPair,pel,ALT|pel,Disjunctive allomorphs / free-fluctuation +FreeFluctuatingAllomorphPair,kits,ORD+SSFX|kits,Disjunctive allomorphs / free-fluctuation +FreeFluctuatingAllomorphPair,kots,,Disjunctive allomorphs / free-fluctuation +FreeFluctuatingAllomorphPair,kot,ORD|kot,Disjunctive allomorphs / free-fluctuation +FreeFluctuatingAllomorphPair,kit,,Disjunctive allomorphs / free-fluctuation +N2-DefaultSymbol,bat,|bat,Boundary markers (CharacterDefinitionTable) +N2-DefaultSymbol,bdt,,Boundary markers (CharacterDefinitionTable) +N1-IsActive,kat,|kat,Boundary markers (CharacterDefinitionTable) +N1-IsActive,sod,|sod,Boundary markers (CharacterDefinitionTable) +IsActiveBreadth,kul,KUL|kul,Element deactivation (isActive) across loader collections +IsActiveBreadth,takul,TA+KUL|takul,Element deactivation (isActive) across loader collections +IsActiveBreadth,tatakul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,tatatakul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,mukul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,pekul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,kol,,Element deactivation (isActive) across loader collections +IsActiveBreadth,mep,,Element deactivation (isActive) across loader collections +IsActiveBreadth,qot,,Element deactivation (isActive) across loader collections +IsActiveBreadth,zal,,Element deactivation (isActive) across loader collections +IsActiveBreadth,qokul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,qekul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,qukul,,Element deactivation (isActive) across loader collections +IsActiveBreadth,mo+kul,MO+KUL|mo+?kul,Element deactivation (isActive) across loader collections +IsActiveBreadth,kul=,,Element deactivation (isActive) across loader collections +IsActiveBreadth,tup,,Element deactivation (isActive) across loader collections +IsActiveBreadth,put,,Element deactivation (isActive) across loader collections +IsActiveBreadth,otkul,,Element deactivation (isActive) across loader collections +N3-PatternShapes,bat,|b[ae]t,Boundary markers (CharacterDefinitionTable) +N3-PatternShapes,bet,|b[ae]t,Boundary markers (CharacterDefinitionTable) +N3-PatternShapes,bit,,Boundary markers (CharacterDefinitionTable) +N3-PatternShapes,bt,,CharacterDefinitionTable pattern shapes: optional group / Kleene star +MetathesisComparisonCrash,ti,,MetathesisRule +MorphotacticAttributeBreadth,kul,KUL|kul,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kulde,KUL+TWICE|kulde,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kuldede,KUL+TWICE|kuldede,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kuldedede,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kulba,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kulgi,KUL+UNBLK|kulgi,MPR features/groups +MorphotacticAttributeBreadth,kulmo,KUL+PART|kulmo,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kulru,KUL+REAL|kulru,RealizationalAffixProcessRule +MorphotacticAttributeBreadth,kulsi,,Element deactivation (isActive) across loader collections +MorphotacticAttributeBreadth,nap,NAP|nap,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,napmo,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,sol,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +MorphotacticAttributeBreadth,kur,,Disjunctive allomorphs / free-fluctuation +MorphotacticAttributeBreadth,kulpu,,Affix template slots (obligatory/disjunctive/ordering) +MorphotacticAttributeBreadth,bak,VAK|bak,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,dom,ZOM|dom,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +MorphotacticAttributeBreadth,bakgi,VAK+UNBLK|bakgi,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,sim,SIM|sim,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +MorphotacticAttributeBreadth,rog,ROG|rog,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +MorphotacticAttributeBreadth,simru,SIM+REAL|simru,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,top,TOP|top,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,topsakatana,TOP+COA+COB+COC+COD|topsakatana,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +MorphotacticAttributeBreadth,kulbubidu,KUL+MB+MA+MREQ|kulbubidu,MPR features/groups +MorphotacticAttributeBreadth,pog,POG|pog,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,pogli,POG+POGAFX|pogli,Affix template slots (obligatory/disjunctive/ordering) +MorphotacticAttributeBreadth,pogti,POG+PO|pogti,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,pogliti,POG+POGAFX+PO|pogliti,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +MorphotacticAttributeBreadth,kulgimo,KUL+UNBLK+PART|kulgimo,Affix template slots (obligatory/disjunctive/ordering) +MorphotacticAttributeBreadth,kulmoru,KUL+PART+REAL|kulmoru,Affix template slots (obligatory/disjunctive/ordering) +MorphotacticAttributeBreadth,topsakanabu,TOP+COA+COB+COD+MB|topsakanabu,Affix template slots (obligatory/disjunctive/ordering) +Ranavu,menulik,NPFX+TULIK|menulik,RewriteRule direction (Dir): left-to-right +MprGroupOverwriteWithoutRealizational,udof,THEMEA+DOF|udof,MPR features/groups +MprGroupOverwriteWithoutRealizational,wudof,THEMEB+THEMEA+DOF|wudof,MPR features/groups +MprGroupOverwriteWithoutRealizational,udofq,THEMEA+DOF+ENDC|udofq,MPR features/groups +MprGroupOverwriteWithoutRealizational,wudofq,,MPR features/groups +ProcessMorphologyInPlaceMutation,a,ROOT+ABLAUT|a,MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext +RightToLeftAnchorEnvironment,aae,ROOT1|aae,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,ae,ROOT2|ae,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,aaa,,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,aa,,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,eaa,,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,aea,,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,eaaa,,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,eeae,ROOT3|eeae,RewriteRule direction (Dir): right-to-left +RightToLeftAnchorEnvironment,eeee,,RewriteRule direction (Dir): right-to-left +StemNameRestrictedRootAllomorph,tam,ROOT|tam,Stem names +StemNameRestrictedRootAllomorph,kap,,Stem names +StemNameRestrictedRootAllomorph,kapom,ROOT+PERS1|kapom,Stem names +StemNameRestrictedRootAllomorph,tamom,,Stem names +StemNameRestrictedRootAllomorph,tamur,ROOT+PERS2|tamur,Stem names +StemNameRestrictedRootAllomorph,kapur,,Stem names +StrRepIdentityProbe,pat,+|[(^0)∅]?+?pat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,pat,|pat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,mat,+|[(^0)∅]?+?mat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,mat,|mat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,mupat,+|mu+?pat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,mumat,+|mu+?mat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,mwpat,,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,mwuta,+|mw+?uta,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,muuta,,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,ndpat,++|[(^0)∅]?+?nd+?pat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,ndpat,++|nd+?[(^0)∅]?+?pat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,ndpat,+|nd+?pat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,ndmat,,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,imat,++|[(^0)∅]?+?i+?mat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,imat,++|i+?[(^0)∅]?+?mat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,imat,+|i+?mat,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +StrRepIdentityProbe,ipat,,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +SubruleMorphosyntacticGating,pat,ROOT1|pat,RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level +SubruleMorphosyntacticGating,bat,ROOT1+DERIVE|bat,RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level +TruncateRulesProbe,sag,|sag,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,sas,|sas,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,bubibi,|bubibi,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,sa,+|sa,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,ag,+|ag,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,as,+|as,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,gbubibi,+|gbubibi,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,gas,++|gas,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,gas,+|gas,AffixProcessRule: subtraction/truncation +TruncateRulesProbe,bag,,AffixProcessRule: subtraction/truncation +FusionalRealizationalMorphology,mun,STEM|mun,Stem names +FusionalRealizationalMorphology,muno,,Stem names +FusionalRealizationalMorphology,muns,,Stem names +FusionalRealizationalMorphology,munt,,Stem names +FusionalRealizationalMorphology,mano,STEM+P1|mano,Stem names +FusionalRealizationalMorphology,mans,STEM+P2|mans,Stem names +FusionalRealizationalMorphology,mant,,Stem names +FusionalRealizationalMorphology,man,,Stem names +FusionalRealizationalMorphology,mino,STEM+P1|mino,Stem names +FusionalRealizationalMorphology,mins,,Stem names +FusionalRealizationalMorphology,mint,STEM+P3|mint,Stem names +FusionalRealizationalMorphology,min,,Stem names +FusionalRealizationalMorphology,ferid,FER+RPAST|ferid,RealizationalAffixProcessRule +FusionalRealizationalMorphology,feres,FER+TENSE|feres,RealizationalAffixProcessRule +FusionalRealizationalMorphology,feresid,,RealizationalAffixProcessRule +FusionalRealizationalMorphology,tul,TUL|tul,RealizationalAffixProcessRule +FusionalRealizationalMorphology,ducit,,RealizationalAffixProcessRule +FusionalRealizationalMorphology,ducunt,DUC+PL2|ducunt,RealizationalAffixProcessRule +FusionalRealizationalMorphology,gelobt,GET+LOB|gelobt,AffixProcessRule: prefix/suffix/circumfix/infix +FusionalRealizationalMorphology,lobh,LOB+S3|lobh,AffixProcessRule: prefix/suffix/circumfix/infix +FusionalRealizationalMorphology,gelobth,GET+LOB+S3|gelobth,AffixProcessRule: prefix/suffix/circumfix/infix +FusionalRealizationalMorphology,gelobthh,,AffixProcessRule: prefix/suffix/circumfix/infix +FusionalRealizationalMorphology,vinc,VIC+PRESSTEM|vinc,AffixProcessRule: prefix/suffix/circumfix/infix +FusionalRealizationalMorphology,pannox,PAN+NOXN|pan+?nox,CompoundingRule +FusionalRealizationalMorphology,pannox,PAN+NOXV|pan+?nox,CompoundingRule +FusionalRealizationalMorphology,benox,BEPFX1+NOXV|benox,AffixProcessRule: prefix/suffix/circumfix/infix +FusionalRealizationalMorphology,panbenox,,CompoundingRule +FusionalRealizationalMorphology,pandex,,CompoundingRule +FusionalRealizationalMorphology,lexdom,LEX+DOMN|lex+?dom,CompoundingRule +FusionalRealizationalMorphology,lexdom,LEX+DOMV|lex+?dom,CompoundingRule +FusionalRealizationalMorphology,lexbedom,LEX+BEPFX2+DOMV|lex+?bedom,CompoundingRule +FusionalRealizationalMorphology,lexbex,,CompoundingRule +FusionalRealizationalMorphology,gofz,GOF+ENDZ|gofz,MPR features/groups +FusionalRealizationalMorphology,ygofz,,MPR features/groups +FusionalRealizationalMorphology,xped,THEMEX+PED|xped,MPR features/groups +FusionalRealizationalMorphology,yxped,THEMEY+THEMEX+PED|yxped,MPR features/groups +FusionalRealizationalMorphology,xpedz,THEMEX+PED+ENDZ|xpedz,MPR features/groups +FusionalRealizationalMorphology,yxpedz,,MPR features/groups +FusionalRealizationalMorphology,katw,KAT+ENDW|katw,MPR features/groups +FusionalRealizationalMorphology,sodw,,MPR features/groups +FusionalRealizationalMorphology,limw,,MPR features/groups +FusionalRealizationalMorphology,kath,,MPR features/groups +FusionalRealizationalMorphology,sodh,SOD+ENDH|sodh,MPR features/groups +FusionalRealizationalMorphology,limh,,MPR features/groups +FusionalRealizationalMorphology,gofzw,GOF+ENDZ+ENDW|gofzw,MPR features/groups +FusionalRealizationalMorphology,gofwz,,MPR features/groups +FusionalRealizationalMorphology,gofwh,GOF+ENDW+ENDH|gofwh,MPR features/groups +FusionalRealizationalMorphology,gofhw,,MPR features/groups +FusionalRealizationalMorphology,sang,SING+ABLAUT|sang,MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext +FusionalRealizationalMorphology,mitlav,MIT+LAV|mit+?lav,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +FusionalRealizationalMorphology,ficlav,FIC+LAV|fic+?lav,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +FusionalRealizationalMorphology,seclav,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +FusionalRealizationalMorphology,genlav,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +FusionalRealizationalMorphology,mitlavlav,,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +FusionalRealizationalMorphology,corriv,BLOCKHEAD+BLOCKNON|cor+?riv,CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) +MetathesisPhaseIsolation,idil,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +MetathesisPhaseIsolation,nui,NIU|nui,MetathesisRule +MetathesisPhaseIsolation,niu,,MetathesisRule +MetathesisPhaseIsolation,mu+i,MI+3SGU|mu+?i,MetathesisRule +MetathesisPhaseIsolation,mu+i,MI+3SGU|mu+?i,Boundary markers (CharacterDefinitionTable) +MetathesisPhaseIsolation,pui,PU+3SGI|pui,AffixProcessRule: prefix/suffix/circumfix/infix +MetathesisPhaseIsolation,sumulat,SULAT+AV|sumulat,AffixProcessRule: prefix/suffix/circumfix/infix +MetathesisPhaseIsolation,sumulat,SULAT+AV|sumulat,MorphologicalOutputAction: CopyFromInput/InsertSegments +MetathesisPhaseIsolation,keadilan,NMLZ+ADIL|keadilan,AffixProcessRule: prefix/suffix/circumfix/infix +MetathesisPhaseIsolation,keadilan,NMLZ+ADIL|keadilan,MorphologicalOutputAction: CopyFromInput/InsertSegments +MetathesisPhaseIsolation,tutula,RDP+TULA|tutula,AffixProcessRule: reduplication (ReduplicationHint) +MetathesisPhaseIsolation,tulatula,RDPL+TULA|tulatula,AffixProcessRule: reduplication (ReduplicationHint) +MetathesisPhaseIsolation,pur,PURE+INCP|pur,AffixProcessRule: subtraction/truncation +MetathesisPhaseIsolation,bahain,BAHA+LNK|bahain,AffixProcessRule: prefix/suffix/circumfix/infix +MetathesisPhaseIsolation,bahain,BAHA+LNK|bahain,MorphologicalOutputAction: CopyFromInput/InsertSegments +MetathesisPhaseIsolation,katibɯd,KTB+PERF|katibɯd,AffixProcessRule: prefix/suffix/circumfix/infix +MetathesisPhaseIsolation,katibɯd,KTB+PERF|katibɯd,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +MetathesisPhaseIsolation,katabɯd,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,nunaliq,NUNA+DERIV|nunaliq,AffixProcessRule: prefix/suffix/circumfix/infix +PolysyntheticStratalDerivationChain,nunaliqvuq,NUNA+DERIV+INFL|nunaliqvuq,Stratum (Linear/Unordered rule order) +PolysyntheticStratalDerivationChain,nunaliqvuq,NUNA+DERIV+INFL|nunaliqvuq,AffixProcessRule: prefix/suffix/circumfix/infix +PolysyntheticStratalDerivationChain,nunavuq,,Stratum (Linear/Unordered rule order) +PolysyntheticStratalDerivationChain,akutat,AKU+TATN|aku+?tat,CompoundingRule +PolysyntheticStratalDerivationChain,akutat,AKU+TATN|aku+?tat,Boundary markers (CharacterDefinitionTable) +PolysyntheticStratalDerivationChain,akutat,AKU+TATV|aku+?tat,CompoundingRule +PolysyntheticStratalDerivationChain,akutat,AKU+TATV|aku+?tat,Boundary markers (CharacterDefinitionTable) +PolysyntheticStratalDerivationChain,pitat,PIPFX1+TATV|pitat,AffixProcessRule: prefix/suffix/circumfix/infix +PolysyntheticStratalDerivationChain,akupitat,,CompoundingRule +PolysyntheticStratalDerivationChain,akutas,,CompoundingRule +PolysyntheticStratalDerivationChain,silaaku,,CompoundingRule +PolysyntheticStratalDerivationChain,silanuk,SILA+NUKN|sila+?nuk,CompoundingRule +PolysyntheticStratalDerivationChain,silanuk,SILA+NUKN|sila+?nuk,Boundary markers (CharacterDefinitionTable) +PolysyntheticStratalDerivationChain,silanuk,SILA+NUKV|sila+?nuk,CompoundingRule +PolysyntheticStratalDerivationChain,silanuk,SILA+NUKV|sila+?nuk,Boundary markers (CharacterDefinitionTable) +PolysyntheticStratalDerivationChain,silamanuk,SILA+MAPFX2+NUKV|sila+?manuk,CompoundingRule +PolysyntheticStratalDerivationChain,silamak,,CompoundingRule +PolysyntheticStratalDerivationChain,takuvuq,taku+INFL|takuvuq,Guesser/LexicalGuess +PolysyntheticStratalDerivationChain,takuvuq,taku+INFL|takuvuq,Guesser/LexicalGuess +PolysyntheticStratalDerivationChain,takuvuq,takuvuq|takuvuq,Guesser/LexicalGuess +PolysyntheticStratalDerivationChain,takuvuq,takuvuq|takuvuq,Guesser/LexicalGuess +PolysyntheticStratalDerivationChain,bubu,DR1|bubu,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,bubu,DR2|bubu,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,bubu,DR3|bubu,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,buibu,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,kuuukuuu,MS|kuuukuuu,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,kuiikuii,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,buuubuuu,MDC|buuubuuu,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,buiibuii,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,mau,MDC2|mau,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,matu,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,uui,MDC3|uui,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,uuu,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PolysyntheticStratalDerivationChain,utui,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +PrefixalDiscontinuousSlotDependency,shiyidkal,SBJ+PRF+CLF+KAL|shiyidkal,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,niyidtan,SBJ+PRF+CLF+TAN|niyidtan,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,bishiyidkal,OBJ+SBJ+PRF+CLF+KAL|bishiyidkal,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,bishiwodkal,,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,yidkal,,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,kal,,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,shiwodkal,SBJ+IMPF+CLF+KAL|shiwodkal,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,gabishiyidkal,ADVA+OBJ+SBJ+PRF+CLF+KAL|gabishiyidkal,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,hogabishiyidkal,ADVB+ADVA+OBJ+SBJ+PRF+CLF+KAL|hogabishiyidkal,Affix template slots (obligatory/disjunctive/ordering) +PrefixalDiscontinuousSlotDependency,gahobishiyidkal,,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,tupay,TUPA+1SG|tupay,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,tupay,TUPA2+1SG|tupay,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,sipuy,SIPU+1SG|sipuy,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walakni,WALAK+1SG|walakni,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walaky,,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walaknki,WALAK+2SG|walaknki,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,sipun,SIPU+3SG|sipun,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walaknichik,WALAK+1SG+PL|walakni(ch)ik,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,sipuymi,SIPU+1SG+DIR|sipuymi,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walaknkisi,WALAK+2SG+REP|walaknkisi,Disjunctive allomorphs / free-fluctuation +SuffixingEvidentialAdjacencyChain,walaknkishi,WALAK+2SG+REP|walaknki(sh)i,Disjunctive allomorphs / free-fluctuation +SuffixingEvidentialAdjacencyChain,sipuncha,SIPU+3SG+CONJ|sipun(ch)a,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,takiy,SING+1SG|takiy,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,kantay,SING+1SG|kantay,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,takincha,SING+3SG+CONJ|takin(ch)a,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,kantancha,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,walaknitan,WALAK+1SG+ASSUM|walaknitan,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,walaknichiktan,WALAK+1SG+PL+ASSUM|walakni(ch)iktan,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,walakntan,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,walakniwas,WALAK+1SG+MIR|walakniwas,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,walaknichikwas,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,siputukumi,SIPU+1PL.INCL+DIR|siputukumi,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,siputukuchikmi,SIPU+1PL.INCL+PL+DIR|siputuku(ch)ikmi,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,siputuku,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,sipulupami,SIPU+2PL+DIR|sipulupami,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,sipulupachikmi,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingEvidentialAdjacencyChain,walaknkichikmi,WALAK+2SG+PL+DIR|walaknki(ch)ikmi,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walakchik,,Affix template slots (obligatory/disjunctive/ordering) +SuffixingEvidentialAdjacencyChain,walaknkicha,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +SuffixingExtensionSlotOrdering,mbe,,MPR features/groups +SuffixingExtensionSlotOrdering,nbael,,MPR features/groups +SuffixingExtensionSlotOrdering,npael,PPO+PHDESTROY|npael,MPR features/groups +SuffixingExtensionSlotOrdering,nba,PPO|nba,RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level +SuffixingExtensionSlotOrdering,npa,,RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level +SuffixingExtensionSlotOrdering,lisez,PHXROOT+PHXSRC|lisez,MPR features/groups +SuffixingExtensionSlotOrdering,mba,PAV|mba,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingExtensionSlotOrdering,mpa,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingExtensionSlotOrdering,limaile,LIM+RPAST|limaile,RealizationalAffixProcessRule +SuffixingExtensionSlotOrdering,limape,LIM+TENSE|limape,RealizationalAffixProcessRule +SuffixingExtensionSlotOrdering,limapeile,,RealizationalAffixProcessRule +SuffixingExtensionSlotOrdering,xkib,EXTX+KIB|xkib,MPR features/groups +SuffixingExtensionSlotOrdering,yxkib,EXTY+EXTX+KIB|yxkib,MPR features/groups +SuffixingExtensionSlotOrdering,xkibz,EXTX+KIB+ENDZ|xkibz,MPR features/groups +SuffixingExtensionSlotOrdering,yxkibz,,MPR features/groups +SuffixingExtensionSlotOrdering,kibw,KIB+ENDW|kibw,MPR features/groups +SuffixingExtensionSlotOrdering,belw,,MPR features/groups +SuffixingExtensionSlotOrdering,nalw,,MPR features/groups +SuffixingExtensionSlotOrdering,kibh,,MPR features/groups +SuffixingExtensionSlotOrdering,belh,BEL+ENDH|belh,MPR features/groups +SuffixingExtensionSlotOrdering,nalh,,MPR features/groups +SuffixingExtensionSlotOrdering,sekzw,SEK+ENDZ+ENDW|sekzw,MPR features/groups +SuffixingExtensionSlotOrdering,sekwz,,MPR features/groups +SuffixingExtensionSlotOrdering,sekwh,SEK+ENDW+ENDH|sekwh,MPR features/groups +SuffixingExtensionSlotOrdering,sekhw,,MPR features/groups +SuffixingExtensionSlotOrdering,kimbiakimbia,KIMB+RED|kimbiakimbia,AffixProcessRule: reduplication (ReduplicationHint) +SuffixingExtensionSlotOrdering,andika,AND+FV|andika,Affix template slots (obligatory/disjunctive/ordering) +SuffixingExtensionSlotOrdering,andik,,Affix template slots (obligatory/disjunctive/ordering) +SuffixingExtensionSlotOrdering,andikisha,AND+CAUS+FV|andikisha,Affix template slots (obligatory/disjunctive/ordering) +SuffixingExtensionSlotOrdering,andikila,AND+APPL+FV|andikila,Affix template slots (obligatory/disjunctive/ordering) +SuffixingExtensionSlotOrdering,andikishila,AND+CAUS+APPL+FV|andikishila,Affix template slots (obligatory/disjunctive/ordering) +SuffixingExtensionSlotOrdering,andikilisha,AND+APPL+CAUS+FV|andikilisha,Affix template slots (obligatory/disjunctive/ordering) +SuffixingExtensionSlotOrdering,dabep,DAB+NUMPL|dabep,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +SuffixingExtensionSlotOrdering,dabepez,DAB+NUMPL+AGR|dabepez,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +SuffixingExtensionSlotOrdering,dabez,DAB+AGR|dabez,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +SuffixingExtensionSlotOrdering,kes,KES|kes,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +SuffixingExtensionSlotOrdering,kesez,,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +SuffixingExtensionSlotOrdering,kesepez,KES+NUMPL+AGR|kesepez,Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +SuffixingExtensionSlotOrdering,siliz,SIL+RECURSUF|siliz,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,siliziz,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,daleh,DAL+STEMREQ|daleh,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,daheh,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,dalizeh,DAL+RECURSUF+STEMREQ|dalizeh,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,dalehiz,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,zimed,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingExtensionSlotOrdering,zamed,,Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) +SuffixingVowelHarmony,semitide,SEMIT+PAST|semitide,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,semitide,SEMIT+PAST|semitide,RewriteRule Simultaneous +SuffixingVowelHarmony,semitile,SEMIT+PRES|semitile,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,semitile,SEMIT+PRES|semitile,RewriteRule Simultaneous +SuffixingVowelHarmony,semitideler,SEMIT+PAST+PL|semitideler,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,kutagida,KUTAK+PAST|kutagida,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,kutagida,KUTAK+PAST|kutagida,RewriteRule Simultaneous +SuffixingVowelHarmony,kutagida,KUTAK+PAST|kutagida,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,kutagida,KUTAK+PAST|kutagida,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +SuffixingVowelHarmony,kutagida,KUTAK+PAST|kutagida,Boundary markers (CharacterDefinitionTable) +SuffixingVowelHarmony,kutagila,KUTAK+PRES|kutagila,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,kutagila,KUTAK+PRES|kutagila,RewriteRule Simultaneous +SuffixingVowelHarmony,kutagila,KUTAK+PRES|kutagila,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,kutagila,KUTAK+PRES|kutagila,Boundary markers (CharacterDefinitionTable) +SuffixingVowelHarmony,kutak,,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,kutakler,,Affix template slots (obligatory/disjunctive/ordering) +SuffixingVowelHarmony,unitide,UNT+PAST|unitide,RewriteRule Simultaneous +SuffixingVowelHarmony,unitide,UNT+PAST|unitide,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,untda,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,guan,GAN+INTS|guan,AffixProcessRule: prefix/suffix/circumfix/infix +SuffixingVowelHarmony,etemik,,AffixProcessRule: prefix/suffix/circumfix/infix +SuffixingVowelHarmony,esalik,,AffixProcessRule: prefix/suffix/circumfix/infix +SuffixingVowelHarmony,duii,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,duy,DUII|duy,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,sueeb,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,sueb,SUEEB|sueb,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +SuffixingVowelHarmony,satun,SAT+ALPHA|satun,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +SuffixingVowelHarmony,setin,SET+ALPHA|setin,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +SuffixingVowelHarmony,kalut,KALT|kalut,RewriteRule Simultaneous +SuffixingVowelHarmony,kalut,KALT|kalut,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +SuffixingVowelHarmony,kalit,,RewriteRule Simultaneous +SuffixingVowelHarmony,kalit,,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +SuffixingVowelHarmony,kalutun,KALT+ALPHA|kalutun,RewriteRule Simultaneous +SuffixingVowelHarmony,kalutun,KALT+ALPHA|kalutun,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +SuffixingVowelHarmony,kalitin,,RewriteRule Simultaneous +SuffixingVowelHarmony,kalitin,,Alpha-variable phonological environments (VariableFeature/AlphaVariables) +TemplaticRootModification,katabit,KTB+P1SG|katabit,RewriteRule Simultaneous +TemplaticRootModification,katabit,KTB+P1SG|katabit,MorphologicalOutputAction: CopyFromInput/InsertSegments +TemplaticRootModification,katabt,,RewriteRule Simultaneous +TemplaticRootModification,kataba,KTB+P3SG|kataba,MorphologicalOutputAction: CopyFromInput/InsertSegments +TemplaticRootModification,sapr,SPR+FORMII|sapr,MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext +TemplaticRootModification,samm,,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +TemplaticRootModification,qil,QWL+PASS|qil,MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext +TemplaticRootModification,halak,HLK|halak,Stem names +TemplaticRootModification,halaku,,Stem names +TemplaticRootModification,hilaku,HLK+IMPF|hilaku,Stem names +TemplaticRootModification,hilaka,,Stem names +TemplaticRootModification,hilaki,HLK+PERF|hilaki,Stem names +TemplaticRootModification,hulaka,HLK+JUSS|hulaka,Stem names +TemplaticRootModification,hulaku,,Stem names +TemplaticRootModification,hulaki,HLK+PERF|hulaki,Stem names +TemplaticRootModification,gigugu,FEEDSIM|gigugu,RewriteRule Simultaneous +TemplaticRootModification,gigugi,FEEDITER|gigugi,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +TemplaticRootModification,gigigi,,RewriteRule Simultaneous +TemplaticRootModification,gigigi,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +TemplaticRootModification,iktub,KTUB|iktub,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +TemplaticRootModification,ktub,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +TemplaticRootModification,radda,RAD|radda,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +TemplaticRootModification,rada,,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) diff --git a/conformance/dataflow-obligations.tsv b/conformance/dataflow-obligations.tsv new file mode 100644 index 000000000..5ec63f3b8 --- /dev/null +++ b/conformance/dataflow-obligations.tsv @@ -0,0 +1,362 @@ +# GENERATED by hc-conformance --write-dataflow-obligations. One row per required CELL of +# this file's own obligation matrix -- all-uses, plus MC/DC on every gate, plus every kill-path +# witnessed -- built on conformance/interaction-chains.tsv (InteractionChainLedger). Every chain +# gates (see DataflowObligationLedger's own doc comment for why the old required*/excluded*-name +# heuristic was wrong), so cell_kind=McDc contributes the +# floor 4 cells per chain (PresentControl/PresentGatedForm/AbsentControl/AbsentGatedForm). +# cell_kind=ConditionExtension adds the extra MC/DC vectors an MPR-feature gate needs when a real +# fixture's attribute value lists more than one feature id (n conditions need n+1 cases, not a +# fixed 2) -- attributed to the specific fixture that realizes it. cell_kind=Mutator adds a +# MutatorAbsent/MutatorPresent pair per (chain, ObligationMutatorClass) the payload type/writer +# make schema-applicable -- mutator_class names which one; only Overwrite has a corpus detector +# today, the other three are declared-but-unmodelled. status is Satisfied only for a same-word +# PAIR witness (writer AND reader severance both flip one named word -- see +# conformance/interface-witness.tsv); NotSatisfied when the chain is not even structurally +# exercised; Unknown otherwise -- deliberate, not a gap (see this class's own doc comment). +cell_id writer_element writer_attribute payload_type reader_element reader_attribute cell_kind role mutator_class status evidence +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc PresentGatedForm - Satisfied paired witness: severing writer and reader both flip 'vokadan' from failed to successful parse in edge-cases/mpr-gated-exception (conformance/interface-witness.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3Control:languages/fusional-realizational-morphology LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures ConditionExtension McDcVector3Control - Unknown mechanically required by 2-condition gate observed in languages/fusional-realizational-morphology ('mprConjA mprConjB'); no per-vector witness check implemented yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3GatedForm:languages/fusional-realizational-morphology LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures ConditionExtension McDcVector3GatedForm - Unknown mechanically required by 2-condition gate observed in languages/fusional-realizational-morphology ('mprConjA mprConjB'); no per-vector witness check implemented yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc PresentGatedForm - Satisfied paired witness: severing writer and reader both flip 'mbe' from failed to successful parse in languages/suffixing-extension-slot-ordering (conformance/interface-witness.tsv) +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures Mutator MutatorPresent Overwrite NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures McDc PresentGatedForm - Satisfied paired witness: severing writer and reader both flip 'topdori' from failed to successful parse in edge-cases/morphotactic-attribute-breadth (conformance/interface-witness.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3Control:edge-cases/mpr-overwrite-order-dependence MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures ConditionExtension McDcVector3Control - Unknown mechanically required by 2-condition gate observed in edge-cases/mpr-overwrite-order-dependence ('mprP mprQ'); no per-vector witness check implemented yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3GatedForm:edge-cases/mpr-overwrite-order-dependence MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures ConditionExtension McDcVector3GatedForm - Unknown mechanically required by 2-condition gate observed in edge-cases/mpr-overwrite-order-dependence ('mprP mprQ'); no per-vector witness check implemented yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc AbsentGatedForm - Satisfied paired witness: severing writer and reader both flip 'ygofz' from failed to successful parse in languages/fusional-realizational-morphology (conformance/interface-witness.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorAbsent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures Mutator MutatorPresent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures McDc PresentGatedForm - Satisfied paired witness: severing writer and reader both flip 'menanukam' from failed to successful parse in edge-cases/mpr-gated-exception (conformance/interface-witness.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorAbsent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures Mutator MutatorPresent Overwrite Unknown no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc AbsentGatedForm - Satisfied paired witness: severing writer and reader both flip 'nbael' from failed to successful parse in languages/suffixing-extension-slot-ordering (conformance/interface-witness.tsv) +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent CompoundingNonHeadDrop Unknown no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorAbsent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures Mutator MutatorPresent Overwrite Unknown structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorAbsent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorPresent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc AbsentGatedForm - Satisfied paired witness: severing writer and reader both flip 'katumi' from failed to successful parse in edge-cases/compounding-breadth (conformance/interface-witness.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc AbsentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc AbsentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc PresentControl - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc PresentGatedForm - NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorAbsent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorPresent Blocking NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion NotSatisfied chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc AbsentGatedForm - Satisfied paired witness: severing writer and reader both flip 'nunavuq' from failed to successful parse in languages/polysynthetic-stratal-derivation-chain (conformance/interface-witness.tsv) +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc AbsentGatedForm - Satisfied paired witness: severing writer and reader both flip 'idil' from failed to successful parse in languages/metathesis-phase-isolation (conformance/interface-witness.tsv) +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorAbsent PosPriorityUnion Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech Mutator MutatorPresent PosPriorityUnion Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentControl Allomorph stemName StemName MorphologicalRule requiredStemName McDc AbsentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentGatedForm Allomorph stemName StemName MorphologicalRule requiredStemName McDc AbsentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:PresentControl Allomorph stemName StemName MorphologicalRule requiredStemName McDc PresentControl - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:PresentGatedForm Allomorph stemName StemName MorphologicalRule requiredStemName McDc PresentGatedForm - Unknown chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::Mutator:MutatorAbsent:Blocking Allomorph stemName StemName MorphologicalRule requiredStemName Mutator MutatorAbsent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::Mutator:MutatorPresent:Blocking Allomorph stemName StemName MorphologicalRule requiredStemName Mutator MutatorPresent Blocking Unknown structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here diff --git a/conformance/docs/README.md b/conformance/docs/README.md new file mode 100644 index 000000000..83458f071 --- /dev/null +++ b/conformance/docs/README.md @@ -0,0 +1,65 @@ +# The conformance suite: documentation + +These documents ship **with** the fixtures. That is deliberate: a consumer receives the +`conformance/` directory and nothing else — PanGloss, the first external consumer, sparse-checks out +exactly this path — so anything explaining the suite that lives outside it may as well not exist. + +Read in this order. + +| | | +|---|---| +| [what-it-is.md](what-it-is.md) | the suite, the fixture contract, the two-file format | +| [what-it-claims.md](what-it-claims.md) | the honest numbers, the named exceptions, and what is **not** claimed | +| [how-it-is-computed.md](how-it-is-computed.md) | the four coverage layers and how each denominator is derived | +| [how-it-works.md](how-it-works.md) | every ledger, its generator, its gate, and how to regenerate | +| [decisions-and-lessons.md](decisions-and-lessons.md) | what was tried, what was wrong, and how we know | +| [PROTOCOL.md](../PROTOCOL.md) | the adapter contract an engine must implement | + +## If you are implementing an engine + +You need **`PROTOCOL.md` and nothing else here.** Your entire obligation is to produce the same +parses for each fixture's `grammar.xml` and words. If you do, you inherit whatever this suite covers. + +Everything else — the counterfactual census, the interface inventory, the severance witness sweep, +the interaction chains, the data-flow obligations — is internal to HermitCrab. It exists so this +suite can justify the claim that its fixture set is complete. You never run it, never regenerate it, +and are never measured against it. + +The ledgers are shipped anyway, because a claim you cannot inspect is a claim you have to take on +trust. + +## Status: what is live, what is frozen, what nobody should extend + +This suite is deliberately stopped at a known point rather than finished. The measurement apparatus +did its job -- it established what the fixtures witness, and it produced the map of what remains -- +and its marginal return then fell to roughly nothing. Freezing it is a decision, not neglect. + +**Live, cheap, and worth keeping working.** The self-check, `--check-manifest`, and the drift gates +that compare a checked-in ledger against a fresh recompute. These run in seconds and they are what +stop the published numbers from quietly going stale. + +**Frozen, and honest as they stand.** The ledgers. They record 14 of 46 gate arms evidenced, 5 of 23 +gates with both MC/DC arms, and 8 defensible obligation cells of 18 worth covering. Those are +findings, not a backlog. `obligation-triage.tsv` classifies every unmet obligation by the blocker its +own ledger records, and most of the remainder is either impossible or strained -- read it before +assuming a number should be higher. + +**Do not extend.** The missing severance primitives (whole-element removal, element-content +severance) exist only to feed a campaign that has ended. The authoring-yield measurement loop +optimises a process whose output has no consumer. `fieldworks-producibility.tsv` is a hand-researched +snapshot of an external repository with a demonstrated non-composing failure mode, and patching it +further buys less than replacing its role would. + +**Where the next real gain is, and it is not here.** Two engines already exist and both already speak +`PROTOCOL.md`. Running them against each other -- on generated grammars, or better, on the grammars +real projects actually produce -- measures the half of the engine this apparatus does not: not +whether a rule was correctly declined, but whether the parse it produces is the same one. The three +defects this suite has found were all of that kind. + +## If you are extending the suite + +Start with [decisions-and-lessons.md](decisions-and-lessons.md), not with the code. Several +approaches here were tried, measured, and rejected, and the reasoning is worth more than the +approaches were. In particular, one mistake has been made five times in five different forms — +reporting that something is *present* as though it had been shown to *matter* — and that document +exists mostly to stop it happening a sixth time. diff --git a/conformance/docs/decisions-and-lessons.md b/conformance/docs/decisions-and-lessons.md new file mode 100644 index 000000000..ce4e1f62b --- /dev/null +++ b/conformance/docs/decisions-and-lessons.md @@ -0,0 +1,238 @@ +# Decisions and lessons + +Most of the reasoning behind this suite's design exists only in the commit messages that built it — +long, argued, and never read again once buried in history. This document mines that record. Every +entry names what was believed, what turned out to be true, how that was established, and what now +stops it recurring. Where a thread could not be pinned to a specific commit, that gap is stated +rather than papered over. + +## The pattern: presence reported as evidence + +The single idea this suite got wrong more than once, in more than one shape, is mistaking *a +construct is declared and loads cleanly* for *a construct was shown to do something*. Four concrete +instances of it are on record with commits; a fifth is referenced only in the documents this one +supports. + +**1. The `RequiredToLoad` verdict.** The original counterfactual gate counted a mutation that made a +grammar fail to *load* at the same strength as one that changed a *parse* — 78 of 264 unit surfaces, +40% of everything resolved, credited this way. `3d724023` split it in two: `RequiredByDtd` (the +mutant fails generic DTD content-model validation before any HermitCrab-specific code runs — this +only re-derives the DTD's own content model, proving nothing about the engine) and `RequiredByLoader` +(the mutant passes DTD validation but fails inside the loader itself — an `IDREF`/lookup/coercion +failure, a genuine engine-semantic fact, though still not a word-level witness). The split was +mechanical, not hand-labeled: which of the 78 fell into which bucket was determined from the +mutation's own recorded kind (`GrammarMutator.DeletedElements`/`EmptiedChildren` for `RequiredByDtd`, +`RewroteAttribute` for `RequiredByLoader`), and falsified in the same commit by inverting the +classifying condition and confirming two known cases flip. + +**2. The interface inventory's `exercised` column.** `interface-inventory.tsv` originally called an +IDREF/IDREFS attribute "exercised" whenever it resolved to a real reference somewhere in the corpus — +structural presence, nothing about whether severing it changed anything. `47b0c30f` renamed the +column to `present` and built `interface-witness.tsv` to run the real severance test per (element, +attribute, fixture) triple. The gap was not small: of 42 present interfaces, only 15 are ever actually +witnessed. Framed the other way, the fold-in candidate count computed under the old predicate (2) was +mostly wrong once witness was required (1) — one of the two "exercised" interfaces turned out to be +present but permanently inert (`SymbolicFeature.defaultSymbol`). + +**3. A fixture design that exercises without witnessing.** `347c54987` corrects a wrong +generalization about how many cases a fixture needs — "two entries" had been stated as a rule rather +than derived from what was being attributed. With only a gated stem, severing the gate changes the +outcome — but so would a rule that never fires at all, and a single-arm fixture cannot tell those +apart. `mpr-gated-exception`'s own notes already called its second, ungated entry "a plain control"; +the commit generalizes that vocabulary: the count needed is whatever leaves exactly one explanation of +the observed difference standing (one, when the counterfactual itself supplies the contrast; four for +a gate — two conditions, present and absent, each needing its own control; three for a mutation caught +in transit between a write and a read). A fixture built to the wrong count exercises a construct and +witnesses nothing, indistinguishable from a correctly designed one until someone asks what it would +take to fool it. + +**4. An internal design document's own baseline table.** An early version of the data-flow coverage +design measured its own starting point — all-defs, all-uses, kill-paths — using +`interaction-chains.tsv`'s `exercised` column: +the same identifier appearing in both a writer's and a reader's attribute values somewhere in one +fixture, with no ordering, no reachability, and no parse-level evidence. `56ac9773` recomputed it +against the real severance sweep instead: all-uses fell from a published 20/40 to a witness-grade +11/40. The commit names this explicitly as the fourth occurrence of the same mistake, inside the very +document written to abolish it, and states the pattern once rather than just the instance: **the weak +predicate is always the one already computed, and it is always the cheaper reach.** + +**5. An agent's headline.** `what-it-claims.md` and the commit shipping it (`ac384820`) both state +that this suite got the presence/evidence distinction wrong five times, the other four being the ones +above. Neither names which commit the fifth is, and it could not be independently located in the +commit range examined for this document. Recorded here as an acknowledged gap rather than a guessed +citation: if a future reader finds it, this line should be replaced with the commit and its evidence. + +**What now prevents a sixth.** No single gate closes this off, because the failure is a habit of +reasoning rather than a bug in one ledger. What exists instead is the vocabulary and the standing +question, applied at every later layer: the inclusion rule — *test every mechanism that can change a +parse; do not test one that cannot, unless it sits in a chain that does* — and the requirement that a +human "yes" on a coverage cell carries a hash of the machine evidence it was shown and lapses the +moment that evidence moves, so +witnessed and reviewed can never quietly collapse into one status again. + +## The rule-interaction-pair ledger's demotion + +`13ea28c2` introduced `rule-interaction-pairs.tsv` to answer a real question: coverage measured per +surface cannot see a defect that needs several surfaces at once (the MPR-overwrite defect below is +exactly such a case), so interactions needed their own denominator — every pipeline-permitted ordered +pair of rule-bearing units within a stratum, 1,290 pairs across 39 strata at introduction. + +The ledger looked like a coverage denominator and was initially treated like one, but it has a +property no denominator can have: it grew every time a fixture was added. `0f0a32f5c` records the +count moving to 1,305 when four more fixtures landed; `b22c038e` names the consequence plainly — it is +"not a coverage denominator," because 1,217 of those 1,305 rows are `Undetermined` by construction +(the disjointness check that would resolve a row only applies to phonological-rule pairs; every other +unit-kind combination cannot be classified at all), and a number that rises when the corpus grows is a +statistic about the corpus, not a bound on the engine. `6b6f7ae4` separately corrects three arithmetic +errors that had crept into the pinning comment along the way (a wrong stratum count, a stale total, and +a citation of the wrong estimate), restating the whole thing as "a corpus statistic, not a bound." + +The ledger was not deleted — it does a real job, just a smaller one. It was demoted explicitly to +**per-grammar pruning**: given one grammar, which adjacent rule swaps are even +worth running a counterfactual on, and which are provably inert. It is good at that question and is +kept for it; it simply stopped being asked the coverage question once that question had a real answer +(the interaction-chain and obligation-cell layers, layers 3 and 4 of `how-it-is-computed.md`). + +## Name-prefix heuristics failing twice + +Two different classification questions in this suite were first answered by guessing from an +attribute's name, and both guesses were wrong in ways only a real grammar shape exposed. + +**Write/read direction.** `5a78c69` built the first interface inventory and classified each +IDREF/IDREFS attribute's direction — write, read, or bare reference — from its name (does it start +with `output`, `assigned`, `required`, and so on). `86d3bbf4` replaced it with +`SemanticInterfaceDirection`, a table checked against the engine's actual read/write sites for all 60 +declared interfaces, after a real field grammar showed the naming convention wrong: +`LexicalEntry.ruleFeatures` reads as a bare reference under the "ref" prefix rule, but the loader +unions it straight into the same live MPR-feature set every gate reads from — it is the lexicon's own +*write* of a lexical entry's initial feature set, not a reference to one. Fixing the one reported case +and then applying the same engine-checked test to everything else surfaced two more misclassified +attributes (`LexicalEntry.partOfSpeech`, `Allomorph.stemName`) and one entirely new junction +(`StemName`) the prefix heuristic could never have produced, since it doesn't correspond to any +"write"-looking prefix at all. Even after the replacement shipped, the same bug resurfaced one call +site over: `cc4dc0eb` found that `interface-inventory.tsv`'s own junction-counting code still +classified direction by prefix internally, so `Allomorph.stemName` never got asked the junction +question in that code path either. The fix was structural, not another patch: point that code at the +same `SemanticInterfaceDirection` table instead of re-deriving its own answer, so the two ledgers +cannot disagree about direction again by construction. + +**Gate-ness.** The first version of the data-flow obligation plan classified a chain as "gated" (and +therefore subject to MC/DC) only when its reader was a `required*`/`excluded*`-named attribute — the +same shape of naming-convention shortcut, applied one layer up. `56ac9773` and `bede48be` replace it: +`SemanticInterfaceDirection`'s own definition of a *read* already means "the engine makes a +control-flow decision on this value," which is gating by definition, so **all 40 chains gate**, not +just the ones with a suggestive name. Twelve chains have `head*`/`nonHead*` readers that gate in engine +code exactly as much as any `required*` one does; the name told nothing about it either way. + +Both fixes point at the same underlying rule, now load-bearing across this suite: a classification +that could instead be checked against engine behavior must be, and a naming convention is only ever a +first guess, never the answer. + +## A tie-break that hid 22 obligations + +`CounterfactualLedger` recorded, per surface, only the single best-verdict fixture — and on a tie +between two fixtures both reaching `Evidenced`, it kept whichever was discovered first. +`Fixture.DiscoverAll` sorts by id, and `edge-cases` sorts before `languages` alphabetically, so on +every such tie the fabricated fixture was recorded and a language-family grammar witnessing the exact +same surface was silently dropped. The ledger could answer *which fixture was recorded first*; it +could never answer *which fixtures witness a surface*, which is the question the fold-in strategy +actually needed. + +`138559e2` fixed it by keeping winner selection untouched (so no existing consumer's answer moves) and +adding a `witnessed_by` column naming every fixture reaching the best verdict, not just the recorded +one. The effect on the number that was actually driving strategy: the count of obligations witnessed +*only* by a fabricated edge case fell from 30 to 8. Twenty-two obligations had a language grammar +witnessing them the whole time, with words already sitting in the repository, and the ledger's own +tie-break was the only thing standing between that fact and the fold-in plan. + +The same commit also removed a `TEMP-BEFORE-MEASUREMENT` marker that had sat unchanged since the +founding commit of the whole coverage apparatus, guarding a `bestSoFar` dictionary that was written and +never read — a short-circuit that, on inspection, skipped nothing at all. The reason it had to go +rather than simply be renamed: exhaustive evaluation of every fixture against every surface is the only +correct behavior here, because a short-circuit would suppress exactly the ties this fix depends on +being able to see. A marker that says "temporary, revisit before trusting this" is only useful if +someone eventually revisits it; this one sat for the suite's entire history without being read for the +thing it was guarding. + +## Why all-uses, not all-du-paths — and a citation that had to be withdrawn + +`f961c321` adopted data-flow coverage (Rapps and Weyuker, 1985) and MC/DC (DO-178C) as the criteria +for the interaction layer, and set the target at **all-uses plus MC/DC on every gate plus every +kill-path witnessed** — deliberately short of **all-du-paths** (every distinct path from a write to a +read, not just one def-clear path per pair). The commit's original justification for stopping short +cited NIST SP 800-142, reading it as evidence that most faults come from a small number of interacting +factors and that the marginal yield of full path coverage doesn't justify its cost. + +`56ac9773` withdrew that citation and replaced it with the honest one. SP 800-142 is a combinatorial- +testing standard about *input-parameter* interaction, not path coverage, and read on its own terms it +argues the *opposite* direction for this exact case: a (writer, mutator, reader) triple is a 3-factor +interaction, squarely inside the 1-to-3-factor band the standard says accounts for most faults — which +would mandate covering the *full* kill-path space, not license a short list from it. The corrected +reasoning states it in the terms that actually hold: the real justification is the classical one +already inside the data-flow literature itself — path explosion, and the cost of proving an infeasible +path infeasible — not a borrowed citation from an adjacent field that does not transfer. The correction +also records, without hiding it, that the criterion was chosen *after* the baseline measurement was +already in hand (`interaction-chains.tsv` landed a day before the corrected reasoning was written), +which does not make all-uses the wrong bound but means it should never be presented as though it +preceded the number it explains. + +## Taking shape, never scale, from a real grammar + +`ea42ff499` measured one real grammar — a Bantu language converted to `HermitCrabInput` XML — against +the entire 33-fixture synthetic corpus: 224 morphological rules, 415 subrules, and 93 slots in that one +grammar against 137, 152, and 46 across everything this suite had built, at roughly 1MB against an +11KB median fixture size. That one grammar also exercised two interfaces the whole synthetic corpus +never had — both on the MPR-to-phonology gate. **One real grammar outweighed the whole corpus**, in +both what it revealed and in sheer size. + +The size difference is exactly why it was never imported wholesale. `99754f4b` measured the +consequence the other way: of the 42 interfaces the corpus exercises at all, 40 are already reached by +one of the eight `languages/` grammars, and only two depend solely on a fabricated `edge-cases/` +fixture — the fabricated fixtures are pins for specific hazards, a real job, but they are not what +makes the coverage claim true. So the procedure this pair of commits establishes is to mine a real +grammar for **shape** — which constructs genuinely co-occur, in what configuration — and reproduce that +configuration at the **minimal scale** that still witnesses the obligation: where the real grammar +needed 12 MPR features, 14 tagged entries, and 4 gated phonological rules to exhibit a gate, the fixture +needs one feature, one gated rule, and (per the control-count rule above) two entries — one the gate +applies to, one it does not. Importing the real grammar's scale directly would have dominated every +gate that walks the fixture set — several of which regenerate a ledger per fixture — trading a suite +that runs in minutes for one that does not, to buy configuration information a two-entry fixture +already captures in full. + +## Other findings worth carrying forward + +**The MPR-overwrite defect is the founding example, not a hypothetical one.** `13ea28c2` is where the +whole interaction/data-flow apparatus starts, because per-surface coverage genuinely cannot see this +class of bug: an MPR feature group with `outputType="overwrite"` evicts its whole group instead of +accumulating into it, so on an unordered stratum, two rules writing that group leave different state +depending on which ran last — a rule gated on the evicted member then succeeds under one derivation +order and fails under the reverse, with every individual ingredient already fully evidenced on its own. +The append-mode mirror (the same two orders through a non-overwriting group, both succeeding) is what +makes this attributable to the overwrite semantics specifically rather than to ordering in general. +Every later layer in `how-it-is-computed.md` exists to generalize past this one pinned case. + +**Mechanical is not the same as meaningful.** The very first semantic census in this suite's history +was mechanically generated, honestly gated against drift, and +almost useless — complete over a denominator that was roughly 90% XML scaffolding no grammar could +meaningfully vary. Deriving a number does not make it worth measuring; every layer that followed was +chosen specifically so each member is semantically load-bearing, not merely countable. + +**A gate and a measuring instrument are different things, and conflating them produces something too +slow to trust and too weak to run always.** `faa092519` separates the deterministic, always-on +dataflow-claim gate (cell exists, before/after values match a fresh recomputation, ledger status is +`Satisfied`) from a separate calibrator that measures whether an AI reviewer can be trusted near that +gate at all, by perturbing known-good claims into deliberate mutants and scoring the reviewer blind per +mutant class. The same commit records why this suite's earlier, unrelated rejection of mutation testing +for Rust code does not transfer here: that rejection held because the mutants there did not correspond +to real defects, whereas here the mutants *are* the defect class under study — a rare case where the +same tool that was rightly rejected for one purpose is exactly right for a different one. + +**Closing one hole in a review process can open a different one, and the fix has to name the new +hole rather than pretend it isn't there.** `9f1840b9` moved the evidence-card generator's grammar-line +citations from human-produced to machine-extracted, which is more reliable but costs a real anti- +faking property: a fabricating reviewer used to give itself away with wrong line numbers, and a +machine now hands the correct numbers to it. The replacement is a semantic check instead of a +structural one (the cited line must actually carry the payload the cell names, on the element the +chain names) plus a new calibrator mutant class built specifically to test whether that replacement +catches a citation repointed at a line that doesn't declare the claimed payload. The lesson generalizes: +a fix to a known weakness should be evaluated for what it removes as well as what it adds. diff --git a/conformance/docs/hc-xml-semantic-catalog.md b/conformance/docs/hc-xml-semantic-catalog.md new file mode 100644 index 000000000..1e4b2fae2 --- /dev/null +++ b/conformance/docs/hc-xml-semantic-catalog.md @@ -0,0 +1,831 @@ +# Canonical HermitCrab XML semantic coverage catalog + +Status: design and initial source-derived inventory
+Catalog profile: `sil.machine.hc-feature/v1`
+Combination profile: `sil.machine.hc-combination/v1` + +> **Superseded, 2026-08-14.** This catalog's central design — the "Combination profile" below, +> canonical hashed IDs over occurrence/schedule/interaction graphs, with full-coverage obligations +> for "every compatible rule-category pair and connected triple, including repetition" (§1) — was +> never implemented, nor was a later, matching `ObligationGenerator`/`CanonicalIdentity` design: an +> MPR `overwrite`-group defect needs four co-occurring, individually-`Evidenced` ingredients, so a +> pairwise or triple-wise enumerator reports full coverage over exactly the ingredients that produce +> the defect and still misses it — arity is not the axis, and enumerating to arity 4 over 264 +> observable surfaces is ~198 million 4-tuples. The governing design now covers the same ground with +> two DTD/engine-derived layers sized very differently: integration/edge, 60 declared +> `IDREF`/`IDREFS` interfaces (`conformance/interface-inventory.tsv`, landed), and integration/chain, +> roughly 15 writer x reader chains through the two junctions where a type is both written and read +> (in progress). **Section 1's "unbounded XML feature-combination denominator" framing and the +> pair/triple/topology obligations in the rest of this document should not be read as current design +> or as a remaining-work list.** The per-feature inventory in §4 (before combinations) is kept as a +> source-derived enumeration exercise that informed later work; it was never machine-generated or +> gated, and the shipped unit-layer denominator (264 grammar-observable surfaces, 113 evidenced) comes +> from `DtdInventoryReader` and `conformance/semantic-coverage-counterfactuals.tsv` instead, not from +> this catalog's hand-authored feature IDs. + +## 1. Purpose and claim boundary + +Machine owns the semantic denominator for HermitCrab XML conformance. The denominator is the set of +meaningful grammar shapes that the XML format can express and the C# HermitCrab loader and engine can +execute, reject, or fail to execute. PanGloss and other consumers run their implementations against +that Machine-owned denominator; they do not define it. + +This catalog is intentionally above compiler lowering. Two XML features remain distinct when they +reach the same low-level operation but enter it through different grammar semantics. A prefix inserted +by an ordinary affix rule, an epenthetic rewrite, and a realizational suffix may all eventually create +segments, but they differ in anchoring, gating, scheduling, inversion, and analysis identity. Each has +its own coverage obligation. + +“Full coverage” here means complete coverage of a finite, named partition of the unbounded XML space: + +1. every XML construct, enum value, meaningful default, and loader-derived semantic branch is + classified; +2. every admitted feature leaf has positive and negative or contrastive evidence; +3. every compatible rule-category pair and connected triple, including repetition, is required or + explicitly retired; +4. every applicable scheduling topology is required or explicitly impossible; +5. a required obligation earns coverage only from discriminating C# HermitCrab evidence; and +6. every consumer backend either matches the C# result or returns an approved explicit refusal. + +This is not every XML document. IDs, strings, feature values, rule counts, pattern bounds, and nesting +depths are unbounded. Those values are partitioned by semantics, with boundary-value and seeded fuzz +tests layered above the categorical obligations. + +The v1 oracle contract is the final analysis set returned by the complete C# `Morpher.ParseWord` +pipeline. That pipeline is deliberately bidirectional: analysis/unapplication generates candidates, +synthesis reapplies the grammar to confirm them, and final validity checks remove candidates. The +catalog therefore records three effects for every semantic leaf: `analysisCandidateEffect`, +`synthesisConfirmationEffect`, and `finalParseEffect`. An effect can be `none`, but it cannot be +omitted. Standalone C# word generation is a separate runtime capability and ledger; it must not be +inferred from parse conformance. + +## 2. Sources and fail-closed completeness + +The catalog is derived from all of the following, not from the DTD alone: + +- `src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd`: syntactically expressible XML; +- `XmlLanguageLoader.cs`: what is loaded, defaulted, derived, ignored, or rejected; +- the HermitCrab model and compiled analysis/synthesis rules: actual execution semantics; +- `conformance/constructs.txt`: the existing coarse human checklist; +- conformance `grammar.xml` and `words.yaml`: existing evidence, not the definition of the space. + +The eventual machine-readable catalog must have a completeness gate against the frozen XML surface. +Adding a DTD element/attribute/enum, a loader switch branch, a public grammar-model rule kind, or a +derived execution branch must fail CI until it is mapped to one of these dispositions: + +| Disposition | Meaning | Required evidence | +|---|---|---| +| `semantic` | Loaded and can affect an analysis set | C# positive and discriminating negative/control cases | +| `loader` | Affects acceptance or construction but not analysis semantics | Focused loader success/failure case | +| `metadata` | Preserved or exposed but intentionally ignored by semantic equality | Round-trip/API test; no analysis credit | +| `ignored` | DTD-valid input is currently ignored by the C# loader | Explicit limitation case; never “supported” | +| `ignored-reference` | A reference is valid but its active runtime object is unavailable and the loader omits it | Loader diagnostic plus constructed-model assertion | +| `partial-load` | An error handler records a construction failure and loading continues with a reduced grammar | Typed diagnostic, constructed-model assertion, and no semantic credit for the omitted object | +| `invalid` | Rejected by DTD, loader, or model validation | Typed rejection case | +| `nonconvergent` | Valid grammar and word do not converge | Controlled `nonconvergent` outcome | + +An unclassified surface is a build failure. A C# crash is never a catalog disposition; it is a red +Machine defect. + +## 3. Canonical identities + +### 3.1 Feature IDs + +A feature ID names one XML-level semantic partition: + +```text +sil.machine.hc-feature/v1/morph/affix/output/insert-segments/prefix +sil.machine.hc-feature/v1/morph/affix/output/copy/reduplication/partial-prefix +sil.machine.hc-feature/v1/phon/rewrite/iterative/rtl/epenthesis +sil.machine.hc-feature/v1/gate/mpr/group/output/overwrite +sil.machine.hc-feature/v1/container/template/slot/required +``` + +IDs describe semantics, not fixture filenames, authored XML IDs, C# class names, or PanGloss backend +mechanisms. Renaming a fixture or rule does not change a feature ID. Changing the semantic partition +requires a new profile version or a new leaf. + +### 3.2 Combination IDs + +A combination is a canonical structured value containing: + +- typed feature occurrences; +- occurrence-local profiles; +- a schedule graph; +- a connected semantic-interaction graph; and +- the carrier that establishes each schedule edge. + +Example: + +```yaml +profile: sil.machine.hc-combination/v1 +occurrences: + - feature: sil.machine.hc-feature/v1/morph/affix/output/insert-segments/suffix + - feature: sil.machine.hc-feature/v1/morph/compound/head-before-nonhead + - feature: sil.machine.hc-feature/v1/phon/rewrite/iterative/ltr/feature-change +schedule: + - {left: 0, relation: unordered-union, right: 1, carrier: morph-stratum} + - {left: 0, relation: precedes, right: 2, carrier: stratum-phase} + - {left: 1, relation: precedes, right: 2, carrier: stratum-phase} +interactions: + - {left: 0, relation: feeds, right: 1, channel: morpheme-sequence} + - {left: 1, relation: feeds, right: 2, channel: segment-sequence} +``` + +Canonicalization uses RFC 8785 JSON and SHA-256 over its UTF-8 bytes. Occurrences initially receive +fixture-local indices only so the schedule and interaction edges can refer to them. Machine enumerates +every label-preserving permutation of the occurrence nodes, jointly remaps both edge sets, sorts edges +by `(left, relation, right, carrier-or-channel)`, serializes each complete object, and chooses the +lexicographically least byte sequence. Repeated equal-profile occurrences remain separate nodes, but +their authored IDs and original indices do not survive canonicalization. Schedule DAGs are stored as +their unique transitive reduction; cyclic or non-DAG schedule policies use an explicitly named policy. + +The authoritative ID is `sha256:<64-lowercase-hex-digits>`. A readable slug is diagnostic only; a +slug collision appends the first twelve digest digits. The implementation must ship vectors for +unique labels, `AAB`, `AAA`, disconnected candidate graphs, mixed partial orders, symmetric edges, +and jointly permuted schedule/interaction edges. Fixture IDs remain evidence references outside the +hashed semantic object. + +## 4. Complete grammar-feature inventory + +This section enumerates the semantic partitions that the v1 machine-readable catalog must contain. +The listed stems omit the common `sil.machine.hc-feature/v1/` prefix. + +Every row expands to a phase-effect record. Unless a row says otherwise, “requires”, “excludes”, +“blocks”, or “outputs” on a morphological or phonological subrule is not presumed symmetric. Current +C# analysis commonly unapplies a structural transform permissively; synthesis then enforces +POS/feature/MPR/environment gates, applies output state, and performs blocking. The final parse effect +is the intersection of generated candidates with successful synthesis confirmation and final +validity. Fixtures must distinguish these phases in traces or counterfactual results; a final result +alone may prove the oracle result but cannot certify a claimed internal phase effect. + +The machine-readable record minimally contains: + +```yaml +analysisCandidateEffect: {reads: [], writes: [], behavior: none|propose|filter|transform} +synthesisConfirmationEffect: {reads: [], writes: [], behavior: none|confirm|reject|transform} +finalParseEffect: {behavior: preserve|remove|add-analysis|typed-outcome} +``` + +### 4.1 Document selection and activation + +| ID stem | XML shape and semantic partitions | +|---|---| +| `document/language/active-single` | Exactly one active `Language`; the loader calls `Single(IsActive)` | +| `document/language/active-none` | No active language; loader rejection | +| `document/language/active-multiple` | More than one active language; loader rejection | +| `document/phon-feature-system/active-single` | Exactly one active phonological feature system | +| `document/phon-feature-system/active-none` | Accepted featureless mode: loader freezes an empty system and segment definitions ignore authored phonological FeatureValues | +| `document/phon-feature-system/active-multiple` | More than one active system reaches `SingleOrDefault`; typed loader rejection | +| `document/activation/active` | An `isActive`-bearing definition participates | +| `document/activation/inactive` | Inactive feature systems, features, tables, definitions, classes, families, rules, subrules, templates, slots, entries, allomorphs, and co-occurrence rules are excluded | +| `document/reference/dtd-unresolved` | A true unresolved IDREF under validating .NET XML loading is an `invalid` document | +| `document/reference/inactive-or-failed-object` | An IDREF resolves in XML, but the target was inactive or failed construction; stratum rule lists and template slots may silently omit it as `ignored-reference` | +| `document/load/error-handler-continues` | A subrule/allomorph construction error is reported and loading continues; `partial-load`, never semantic credit | +| `document/load/platform-validation` | .NET validating-load and Mono/non-validating behavior are distinct harness profiles; the oracle profile requires validating .NET behavior | +| `document/dtd/defaulted-attribute` | DTD default is omitted and the loader observes the intended default | +| `document/dtd/explicit-default` | The same default is written explicitly; semantic result equals the omitted form | + +Activation must be tested at each loader collection boundary. One inactive rule does not certify an +inactive feature, character definition, subrule, slot, or allomorph. + +### 4.2 Feature systems and feature structures + +| ID stem | Partitions | +|---|---| +| `feature/pos` | One/multiple parts of speech; required, assigned, and output POS; absent POS | +| `feature/phon/symbolic` | Symbolic phonological feature with one/multiple symbols | +| `feature/phon/default-symbol/present` | `defaultSymbol` present and used in matching | +| `feature/phon/default-symbol/absent` | No default symbol | +| `feature/syntax/head/symbolic` | Symbolic head feature | +| `feature/syntax/head/complex` | Nested complex head feature | +| `feature/syntax/foot/symbolic` | Symbolic foot feature | +| `feature/syntax/foot/complex` | Nested complex foot feature | +| `feature/value/single` | One symbolic value | +| `feature/value/disjunctive` | Multiple `symbolValues` in one feature value | +| `feature/value/complex` | Recursive `FeatureValue` for a complex feature | +| `feature/value/empty-complex` | Complex feature with no child values | +| `feature/value/symbolic-without-symbol-values` | Symbolic feature used without `symbolValues` reaches the invalid complex-feature cast branch | +| `feature/value/complex-with-symbol-values` | Complex feature used with `symbolValues` reaches the invalid symbolic-feature cast branch | +| `feature/value/symbolic-values-with-children` | Symbolic feature has `symbolValues` and recursive children; loader uses the symbols and ignores the children | +| `feature/value/complex-values-with-children` | Complex feature has both `symbolValues` and children; invalid symbolic-feature cast occurs before children can load | +| `feature/value/inactive` | Inactive `FeatureValue` is omitted | +| `feature/agreement/required-head` | Rule or allomorph requires head features | +| `feature/agreement/required-foot` | Rule or allomorph requires foot features | +| `feature/agreement/assigned-head` | Lexical entry/stem-name region supplies head features | +| `feature/agreement/assigned-foot` | Lexical entry/stem-name region supplies foot features | +| `feature/agreement/output-head` | Morphological rule writes head features | +| `feature/agreement/output-foot` | Morphological rule writes foot features | +| `feature/agreement/obligatory` | Output feature completeness requirement, both satisfied and unsatisfied | +| `feature/realizational/required` | Realizational feature structure selects a realizational rule | + +Required/assigned/output are distinct leaves even when backed by the same `FeatureStruct` operation. + +### 4.3 MPR state + +| ID stem | Partitions | +|---|---| +| `mpr/feature` | Individual MPR feature present/absent | +| `mpr/group/match/any` | Any group member satisfies a requirement | +| `mpr/group/match/all` | All group members are required | +| `mpr/group/output/append` | Output accumulates group members | +| `mpr/group/output/overwrite` | Output replaces prior members of the group | +| `mpr/gate/required` | Required MPR on an ordinary morphological input, compound head input, or phonological subrule | +| `mpr/gate/excluded` | Excluded MPR at those same supported sites | +| `mpr/gate/required-and-excluded` | Same or overlapping set exercises conflict semantics | +| `mpr/output/morphological` | Morphological output adds MPR state | +| `mpr/compound/head-production` | Head production restriction | +| `mpr/compound/nonhead-production` | Non-head production restriction | +| `mpr/compound/output-production` | Output production restriction | + +The DTD and loader do not provide symmetric non-head-input required/excluded MPR attributes for a +`CompoundingSubrule`; that absence is a model limitation, not a missing test leaf. + +### 4.4 Character definitions and representations + +| ID stem | Partitions | +|---|---| +| `representation/table/single` | One character-definition table | +| `representation/table/multiple-disjoint` | Multiple tables with disjoint representations | +| `representation/table/multiple-overlap` | Multiple tables share a surface representation with different identities/features | +| `representation/table/stratum-transition` | Word crosses strata that use different tables | +| `representation/table/explicit-pattern-override` | `Segments@characterDefinitionTable` overrides the carrier table | +| `representation/table/explicit-output-override` | `InsertSegments@characterDefinitionTable` overrides the carrier table | +| `representation/segment/featureless` | Segment definition without phonological features | +| `representation/segment/feature-bearing` | Fully or partially specified segment feature structure | +| `representation/segment/one-spelling` | One representation | +| `representation/segment/multiple-spellings` | Multiple representations for one segment identity | +| `representation/segment/prefix-overlap` | Distinct spellings overlap by prefix; segmentation deterministically chooses the longest match | +| `representation/segment/normalized-duplicate-across-definitions` | A normalized spelling already owned by an earlier definition; table construction rejects the later definition | +| `representation/segment/normalized-duplicate-within-definition` | Two spellings in one new definition normalize identically; construction accepts them and the lookup collapses to one key | +| `representation/segment/cross-table-overlap` | Separate tables may assign the same spelling to different identities; the active carrier table disambiguates | +| `representation/output/multiple-spellings` | One segment identity has multiple output spellings; enumerate the C# surface alternatives separately from input segmentation | +| `representation/segment/diacritic` | Combining or precomposed representation identity | +| `representation/boundary/defined` | Boundary definition and representation | +| `representation/boundary/in-pattern` | Boundary marker participates in a pattern | +| `representation/boundary/inserted` | Inserted segment string contains a boundary | +| `representation/root/boundary-only` | Root parses to boundaries only; loader rejects it | +| `representation/invalid-word` | Input cannot be represented by the selected table; `invalidInput` | +| `representation/root-pattern/literal` | Root `PhoneticShape` longest-match segmentation with pattern syntax enabled | +| `representation/root-pattern/class` | Root `[Class]` expands one natural-class member | +| `representation/root-pattern/optional-class` | Root `([Class])` permits one optional class; compound parenthesized patterns are invalid | +| `representation/root-pattern/repeated-class` | Root `[Class]*` expands zero or more members; `+` is a boundary marker, not a Kleene operator | +| `representation/root-pattern/malformed` | Unclosed/unknown class and malformed metacharacter syntax produce typed loader failure | +| `representation/normalization/nfd` | Root and word representations normalize to NFD before segmentation | +| `representation/normalization/collision` | Canonical-equivalence collision is partitioned by within-definition acceptance versus across-definition rejection | + +### 4.5 Natural classes, patterns, and environments + +| ID stem | Partitions | +|---|---| +| `pattern/atom/segment` | Literal `Segment` identity | +| `pattern/atom/segments` | Literal `Segments` string expanded under a table | +| `pattern/atom/natural-class/segment-list` | `SegmentNaturalClass` | +| `pattern/atom/natural-class/feature` | `FeatureNaturalClass` | +| `pattern/atom/natural-class/empty` | Empty class, if loader/model accepts it, with no-match evidence | +| `pattern/atom/boundary` | `BoundaryMarker` | +| `pattern/sequence/empty` | Empty phonetic sequence | +| `pattern/sequence/multiple-atoms` | Ordered multi-atom sequence | +| `pattern/quantifier/default-star` | Missing `min`/`max`: `0..unbounded` | +| `pattern/quantifier/optional` | `0..1` | +| `pattern/quantifier/bounded` | Other finite `min..max`, including exact repetition | +| `pattern/quantifier/unbounded-positive` | Positive minimum and unbounded maximum | +| `pattern/quantifier/invalid-bounds` | Negative/ill-ordered/non-numeric bounds; typed loader/model rejection | +| `pattern/capture/named` | Named input part used by output action or metathesis switch | +| `pattern/capture/uncaptured` | Pattern material intentionally omitted from output | +| `environment/left` | Left environment only | +| `environment/right` | Right environment only | +| `environment/bilateral` | Both environments | +| `environment/empty` | Explicit environment with no effective side | +| `environment/anchor/initial` | Initial boundary condition | +| `environment/anchor/final` | Final boundary condition | +| `environment/anchor/both` | Both anchors | +| `environment/alpha/plus` | Positive alpha-variable agreement | +| `environment/alpha/minus` | Negative alpha-variable disagreement | +| `environment/alpha/multiple` | Multiple variables/features in one rule | +| `environment/alpha/reused` | One variable reused across target/output/environment | + +Pattern leaves must be exercised in each semantically distinct carrier that supports them: root +allomorph shape, morphological LHS, rewrite LHS/RHS/environment, metathesis structural description, +and allomorph environment. A quantifier in one carrier does not certify another carrier's execution. +Alpha variables in an allomorph environment are currently a `blocked-csharp-defect`: the loader +passes an empty variable map and indexes it when the alpha context is loaded. They cannot earn +semantic carrier credit until C# is fixed. + +### 4.6 Lexicon, allomorphy, and blocking + +| ID stem | Partitions | +|---|---| +| `lexicon/entry/single-allomorph` | One root allomorph | +| `lexicon/entry/multiple-allomorph/free` | Constraint-equivalent alternatives free-fluctuate | +| `lexicon/entry/multiple-allomorph/prioritized` | Constraint-distinct alternatives trigger disjunctive re-check/order | +| `lexicon/entry/partial` | Partial lexical entry participates in continuation/template semantics | +| `lexicon/allomorph/bound` | Bound root cannot stand alone | +| `lexicon/allomorph/required-environment` | Required left/right/bilateral environment | +| `lexicon/allomorph/excluded-environment` | Excluded left/right/bilateral environment | +| `lexicon/allomorph/required-and-excluded` | Interacting positive and negative environments | +| `lexicon/allomorph/stem-name` | Stem-name region selects the root allomorph | +| `lexicon/stem-name/one-region` | One POS/head/foot region | +| `lexicon/stem-name/multiple-regions` | Disjunctive regions | +| `lexicon/family/blocking` | Irregular family member blocks a regular derivation | +| `lexicon/property/metadata` | Arbitrary properties are loaded but do not by themselves earn semantic coverage | +| `lexicon/morpheme-id-gloss/metadata` | Identity/presentation fields, separate from rule behavior | + +### 4.7 Ordinary and realizational affix-process rules + +| ID stem | Partitions | +|---|---| +| `morph/affix/rule` | Ordinary `MorphologicalRule` | +| `morph/realizational/rule` | `RealizationalRule` with empty/non-empty realizational features | +| `morph/affix/subrule/single` | One allomorph/subrule | +| `morph/affix/subrule/multiple` | Competing or gated allomorphs; declaration priority/free fluctuation | +| `morph/affix/input/one-part` | One captured input part | +| `morph/affix/input/multiple-parts` | Discontinuous/circumfix-capable input | +| `morph/affix/input/unnamed-referenced-part` | `PhoneticSequence@id` omitted but Copy/Modify references its index; typed loader failure | +| `morph/affix/output/copy/once` | `CopyFromInput` once | +| `morph/affix/output/copy/reordered` | Captured parts copied in a different order: movement/permutation | +| `morph/affix/output/copy/repeated` | Same part copied more than once: reduplication | +| `morph/affix/output/omit/leading` | Leading captured material omitted: subtraction/truncation | +| `morph/affix/output/omit/trailing` | Trailing captured material omitted | +| `morph/affix/output/omit/internal` | Internal captured part omitted | +| `morph/affix/output/empty` | No RHS actions: complete deletion of matched material where valid | +| `morph/affix/output/modify` | `ModifyFromInput` feature mutation | +| `morph/affix/output/insert-class` | `InsertSimpleContext` creates a natural-class/feature-defined segment | +| `morph/affix/output/insert-segments` | `InsertSegments` creates literal material | +| `morph/affix/output/mixed` | Multiple action kinds in one ordered RHS | +| `morph/affix/shape/prefix` | Derived action topology inserts/copies before the stem | +| `morph/affix/shape/suffix` | Derived action topology inserts/copies after the stem | +| `morph/affix/shape/infix` | Material inserted between copied portions | +| `morph/affix/shape/circumfix` | Material inserted on both sides | +| `morph/affix/shape/simulfix` | Modification is the sole or principal exponent | +| `morph/affix/redup-hint/prefix` | `redupMorphType=prefix` | +| `morph/affix/redup-hint/suffix` | `redupMorphType=suffix` | +| `morph/affix/redup-hint/implicit` | Default implicit hint, with true-copy and non-copy controls | +| `morph/affix/max-application/zero` | Rule cannot apply | +| `morph/affix/max-application/one` | Default single application | +| `morph/affix/max-application/multiple` | Bounded repetition, including upper DTD boundary 9 | +| `morph/affix/blockable/true` | Synthesis confirmation checks family blocking; analysis candidate generation does not | +| `morph/affix/blockable/false` | Synthesis confirmation bypasses blocking | +| `morph/affix/partial/true` | Partial-rule continuation behavior | +| `morph/affix/partial/false` | Ordinary complete rule | +| `morph/affix/gate/rule` | Required POS/head/foot/stem-name on the rule | +| `morph/affix/gate/subrule` | Required head/foot, MPR, and environments on the allomorph | +| `morph/affix/output/syntax` | Output POS/head/foot/obligatory features | +| `morph/realizational/blocking` | Synthesis-confirmation blocking and competition with ordinary rules; analysis only proposes candidates | + +Output topology is derived from the ordered LHS captures and RHS actions. It is not safe to infer +prefix/suffix/circumfix solely from `redupMorphType` or from the first inserted string. + +### 4.8 Compounding + +| ID stem | Partitions | +|---|---| +| `morph/compound/rule` | `CompoundingRule` | +| `morph/compound/subrule/single` | One compound subrule | +| `morph/compound/subrule/multiple` | Alternative compound shapes | +| `morph/compound/head-before-nonhead` | RHS places head material before non-head material | +| `morph/compound/nonhead-before-head` | RHS reverses that order | +| `morph/compound/interleaved-modified` | Mixed insertion/modification/reordering across head and non-head captures | +| `morph/compound/gate/head-pos` | Head POS restriction | +| `morph/compound/gate/nonhead-pos` | Non-head POS restriction | +| `morph/compound/gate/head-features` | Head head/foot feature restriction | +| `morph/compound/gate/nonhead-features` | Non-head head/foot feature restriction | +| `morph/compound/gate/head-mpr` | Head input required/excluded MPR | +| `morph/compound/production-mpr/nonhead-analysis-gate` | Analysis candidate generation checks non-head production restrictions | +| `morph/compound/production-mpr/head-synthesis-gate` | Synthesis confirmation checks head production restrictions | +| `morph/compound/production-mpr/output-synthesis` | Synthesis writes output production restrictions | +| `morph/compound/variable-binding/head-nonhead-not-unified` | Current C# synthesis does not unify head and non-head alpha-variable bindings; explicit implementation limitation | +| `morph/compound/output/syntax` | Output POS/head/foot/obligatory features | +| `morph/compound/max-application/zero` | Cannot apply | +| `morph/compound/max-application/one` | Default one application | +| `morph/compound/max-application/multiple` | Bounded recursive compounding, including upper boundary 9 | +| `morph/compound/blockable/true` | Synthesis confirmation checks family blocking; analysis candidate generation does not | +| `morph/compound/blockable/false` | Synthesis confirmation bypasses blocking | + +### 4.9 Templates and morphology scheduling + +| ID stem | Partitions | +|---|---| +| `container/morph-stratum/linear-synthesis` | Synthesis uses the authored total `LinearRuleCascade` | +| `container/morph-stratum/linear-analysis` | Analysis uses optional unapplication through a `PermutationRuleCascade`; the topology is ordered subsequences, not one reversed total order | +| `container/morph-stratum/unordered-union` | HC explores admissible loose-rule combinations/orders and unions results | +| `container/template/single` | One applicable template | +| `container/template/multiple-alternatives` | Multiple applicable templates are alternatives | +| `container/template/gate-pos` | Template required POS | +| `container/template/final/true` | Final template terminates loose/template continuation | +| `container/template/final/false` | Non-final template requires valid continuation | +| `container/template/slot/required` | Required slot | +| `container/template/slot/optional` | Optional slot | +| `container/template/slot/alternatives` | Multiple rules in one slot are alternatives, not a cascade | +| `container/template/slot/sequence` | Earlier and later slots establish order | +| `container/template/loose-rule/linear` | Template/loose-rule interaction in a linear stratum | +| `container/template/loose-rule/unordered` | Template and loose rules can interleave in an unordered stratum | +| `container/template/loose-rule/synthesis-two-root-paths` | Synthesis unions morphology-first and template-first roots; each branch may recursively enter the other | +| `container/template/loose-rule/analysis-two-root-paths` | Analysis unions template-first and morphology-first roots, reversing root enumeration while recursively crossing branches | +| `container/template/loose-rule/single-family-output` | Template-only and loose-morphology-only successful outputs remain admitted beside cross-branch outputs | +| `container/strata/sequence` | Synthesis proceeds by increasing stratum depth; analysis reverses it | +| `container/strata/same-table` | Ordered strata share representation | +| `container/strata/table-transition` | Ordered strata change representation table | + +### 4.10 Rewrite rules + +| ID stem | Partitions | +|---|---| +| `phon/rewrite/rule` | `PhonologicalRule`/`RewriteRule` | +| `phon/rewrite/subrule/single` | One subrule | +| `phon/rewrite/subrule/disjunctive-synthesis` | Synthesis selects the first applicable subrule in declaration order | +| `phon/rewrite/subrule/disjunctive-analysis` | Analysis visits every subrule against mutable candidate state; not first-match priority | +| `phon/rewrite/application/iterative-ltr` | Default left-to-right iterative application | +| `phon/rewrite/application/iterative-rtl` | Right-to-left iterative application | +| `phon/rewrite/application/simultaneous` | Simultaneous application; XML supplies no RTL-simultaneous variant | +| `phon/rewrite/application/analysis-forced-simultaneous` | Analysis forces deletion and expansion inverses to simultaneous regardless of the authored XML mode | +| `phon/rewrite/application/simultaneous-grouped-rhs-defect` | A simultaneous equal-child-count inverse with `Segments`/optional grouped RHS can cast Group/Quantifier to Constraint and crash; `blocked-csharp-defect` | +| `phon/rewrite/shape/cardinality-syntax-nodes` | Current analysis dispatch compares top-level pattern-child counts, not effective segment cardinality; grouped/quantified cross-products require explicit evidence | +| `phon/rewrite/shape/feature-change` | LHS and RHS cardinalities equal; feature/substitution reversal path | +| `phon/rewrite/shape/deletion` | LHS cardinality greater than RHS | +| `phon/rewrite/shape/epenthesis` | Empty LHS and non-empty RHS | +| `phon/rewrite/shape/expansion` | Non-empty LHS shorter than RHS | +| `phon/rewrite/shape/merge` | Multi-node LHS maps to fewer RHS nodes | +| `phon/rewrite/shape/empty-output` | Complete deletion | +| `phon/rewrite/shape/multi-output` | Multi-node output | +| `phon/rewrite/gate/pos` | Synthesis confirmation enforces required POS; analysis subrules propose without this gate | +| `phon/rewrite/gate/mpr-required` | Synthesis confirmation enforces required MPR; analysis proposes without it | +| `phon/rewrite/gate/mpr-excluded` | Synthesis confirmation enforces excluded MPR; analysis proposes without it | +| `phon/rewrite/boundary/analysis-filtered` | Analysis target matching excludes boundary nodes and strips boundaries from environments | +| `phon/rewrite/boundary/synthesis-retained` | Synthesis target matching and environments retain boundary nodes | +| `phon/rewrite/environment` | Left/right/bilateral/anchored/quantified/alpha-variable profiles from §4.5 | +| `phon/rewrite/analysis/reapply-normal` | Equal-width inverse reapplication | +| `phon/rewrite/analysis/reapply-deletion` | Deletion/expansion inverse uses bounded `DeletionReapplications` behavior | +| `phon/rewrite/analysis/reapply-self-opaquing` | Simultaneous inverse reapplication until self-opaque | +| `phon/rewrite/self-feeding/convergent` | Reapplication reaches a fixed point | +| `phon/rewrite/self-feeding/nonconvergent` | Controlled nonconvergent outcome | + +### 4.11 Metathesis + +| ID stem | Partitions | +|---|---| +| `phon/metathesis/rule` | `MetathesisRule` | +| `phon/metathesis/application/ltr` | Left-to-right iterative scan | +| `phon/metathesis/application/rtl` | Right-to-left iterative scan | +| `phon/metathesis/shape/adjacent` | Switch captures adjacent | +| `phon/metathesis/shape/nonadjacent` | Intervening material is retained | +| `phon/metathesis/shape/contextual` | Additional left/right material constrains the switch | +| `phon/metathesis/shape/anchored` | Initial/final/both boundary condition | +| `phon/metathesis/shape/quantified` | Optional/repeated intervening material | +| `phon/metathesis/shape/literal-switch` | Switches identify literal segments | +| `phon/metathesis/shape/class-switch` | Switches identify natural-class contexts | +| `phon/metathesis/switch/same-id` | Equal `leftSwitch` and `rightSwitch` IDREFs collide in the loader dictionary; typed invalid/blocked outcome | +| `phon/metathesis/switch/missing-capture` | A switch ID resolves in XML but is absent from the structural description capture set; typed loader/model outcome | +| `phon/metathesis/boundary/analysis-filtered` | Analysis structural matching excludes boundary nodes | +| `phon/metathesis/boundary/synthesis-retained` | Synthesis structural matching retains boundary nodes | +| `phon/metathesis/effect/analysis-feature-swap` | Analysis swaps feature structures in place, preserving node identity | +| `phon/metathesis/effect/synthesis-node-move` | Synthesis physically moves nodes and rebuilds morph annotations | +| `phon/metathesis/self-feeding/convergent` | Iteration stabilizes | +| `phon/metathesis/self-feeding/nonconvergent` | Controlled nonconvergent outcome if constructible | + +### 4.12 Co-occurrence and selection constraints + +Each of the following applies independently to morpheme and allomorph co-occurrence rules: + +| ID stem | Partitions | +|---|---| +| `constraint/cooccurrence/require` | Primary requires one of the named others | +| `constraint/cooccurrence/exclude` | Primary excludes the named others | +| `constraint/cooccurrence/anywhere` | No direction/distance restriction | +| `constraint/cooccurrence/somewhere-left` | Other occurs somewhere to the left | +| `constraint/cooccurrence/somewhere-right` | Other occurs somewhere to the right | +| `constraint/cooccurrence/adjacent-left` | Other immediately precedes primary | +| `constraint/cooccurrence/adjacent-right` | Other immediately follows primary | +| `constraint/cooccurrence/one-other` | One target | +| `constraint/cooccurrence/multiple-others` | Disjunctive target set | +| `constraint/cooccurrence/chain` | Multiple constraints form a dependency chain | +| `constraint/cooccurrence/cycle` | Constraints form a cycle or contradiction | + +### 4.13 Runtime dimensions adjacent to, but not defined by, the grammar + +These require conformance coverage but do not enter the XML feature-combination denominator: + +- lexical guessing on/off; +- tracing on/off and trace fidelity; +- merge-equivalent-analyses on/off; +- rule and lexical-entry selectors; +- C# analysis reapplication limits and maximum unapplications/stem count; +- engine-managed deterministic node/arc/traversal/application budgets; and +- batch, adapter, and structured-result behavior. + +They receive separate runtime-integration IDs so a runtime option cannot masquerade as coverage of an +XML feature. + +## 5. Interaction taxonomy + +Every semantic feature occurrence declares its three phase effects and which state domains each effect +reads, writes, adds, removes, selects, or bounds. Domains include segment sequence, segment features, +boundaries, morpheme sequence, allomorph choice, POS/category, head/foot/obligatory syntactic features, +realizational-feature state, MPR state, stem name, character table, template partial/final state, +deleted/modified node flags, current compound non-head, stratum phase, rule application/unapplication +counters, and other application history. + +The catalog uses these interaction relations: + +| Relation | Definition | Typical witness | +|---|---|---| +| `feeds` | A writes something B positively reads | Affix creates the segment targeted by rewrite | +| `bleeds` | A removes or changes something B positively reads | Rewrite destroys a later rule's environment | +| `counterfeeds` | Authored order prevents B from seeing material A would otherwise create | Reversing two ordered rules adds an analysis | +| `counterbleeds` | Authored order preserves a match that the reverse order would remove | Reversing two ordered rules removes an analysis | +| `competes` | A and B write overlapping state | Two rewrites target the same segment | +| `gates` | A's state controls whether B is eligible | MPR-producing rule enables a gated rule | +| `blocks` | A supplies an exception that suppresses B | Family/allomorph blocks regular morphology | +| `selects` | A changes the allomorph, subrule, template, or lexical alternative chosen | Output features select realizational allomorph | +| `accumulates` | A and B independently add state retained in the result | MPR append or independent feature outputs | +| `overwrites` | B replaces earlier state from A | MPR group overwrite | +| `copies-from` | B duplicates material/state produced or selected by A | Reduplication after stem modification | +| `bounds` | A limits B's repetition/search | Max-application and obligatory/final constraints | +| `recurs` | An occurrence reads its own output | Iterative rewrite, repeated morphology, recursive compound | +| `alternates` | Several rules/allomorphs/slots are alternatives rather than a cascade | Multiple template rules in one slot | +| `unions-orders` | HC admits several derivation orders and unions their results | Unordered morphological stratum | +| `crosses-phase` | State moves through morphology/phonology, template, or stratum boundary | Morphological output feeds later phonology | +| `threads-representation` | Identity crosses a character-table/boundary representation seam | Multi-table strata | +| `confirms` | A later validity check removes a candidate produced earlier | Co-occurrence or allomorph validity check | +| `orthogonal` | Proven non-interacting for the declared domains and placement | Disjoint rules; reported but not interaction credit | + +An interaction word is load-bearing only if removing or neutralizing each occurrence changes the C# +analysis set or typed outcome. Merely firing two rules is insufficient. For a connected triple, the +declared interaction graph must connect all three occurrences, and every declared edge needs a +counterfactual witness. + +## 6. Ordering and unordered semantics + +“Ordered” is not one flag. + +### 6.1 Rule-local policy + +- rewrite application: iterative or simultaneous; +- rewrite/metathesis scan: left-to-right or right-to-left; +- morphological/compound application: zero, one, or bounded multiple application; and +- self-application: convergent or nonconvergent. + +These are node profiles, not edges between rules. + +### 6.2 Container schedule + +- loose morphological rules in synthesis: authored linear cascade or unordered combination/union; +- loose morphological rules in analysis: optional unapplication, including ordered subsequences for + a linear stratum and admissible permutations for an unordered stratum; +- phonological rules: authored linear cascade in synthesis, reversed in analysis; +- template slots: linear sequence; +- rules within a template slot: alternatives; +- multiple applicable templates: alternatives; +- templates versus loose rules: carrier-dependent interleaving; and +- strata: ordered phase sequence, reversed by analysis. + +### 6.3 Pairwise schedule relations + +Every pair in a combination receives exactly one applicable relation: + +- `precedes` with a named carrier; +- `unordered-union` with a named carrier; +- `alternative` with a named carrier; +- `same-rule-local` for two profiles of one rule occurrence; or +- `not-co-schedulable`, which retires the candidate with a reason. + +Absence of an edge is not shorthand for unordered. + +### 6.4 Evidence rules + +For an ordered pair, reversing the relevant order must change the C# analysis set to earn +order-sensitive coverage. If it does not, the case earns `orthogonal` or order-invariant coverage, +not ordering coverage. + +For an ordered triple, every admitted sequence of category labels is a distinct type-level +obligation. A connected chain `A > B > C` needs load-bearing evidence for the declared edges, not +only a comparison of the complete order with its full reversal. + +For an unordered pair or triple, “unordered” means the union of admissible derivations, not that each +derivation has the same output. Evidence must establish both: + +1. the final C# result contains the required derivation-order contributions; and +2. every concrete XML declaration permutation produces the same final union. + +At arity three Machine runs all six permutations of the concrete rule occurrences, including `AAA` +and `AAB`, where same-category occurrences remain distinct through fixture-local rule IDs. + +Mixed partial orders are first-class. For example, two unordered morphological rules may both precede +a phonological rewrite. A tuple-level `ordered: true|false` cannot represent that grammar. + +## 7. Obligation enumeration + +The machine-readable catalog generates four related ledgers. + +### 7.1 Atomic ledger + +Every feature leaf in §4 receives at least: + +- a positive or accepted witness where meaningful; +- a negative, excluded, absent, or contrastive control; +- a C# outcome and structured analysis set when semantic; and +- a fixture and word/case reference. + +### 7.2 Within-rule configuration ledger + +For each rule kind, enumerate every compatible pair of local feature partitions: output action, +pattern form, gate, environment, state output, repetition, and rule-local application mode. Connected +triples are required when three settings jointly choose a distinct C# branch or have a known +three-way dependency. Mutually exclusive values of one enum are separate atomic variants, not a +nonsensical same-rule combination. + +### 7.3 Cross-rule interaction ledger + +Generate all compatible pairs and connected triples, with repetition, over the admitted high-level +rule profiles: + +- ordinary affix-process profiles; +- realizational affix-process profiles; +- compounding profiles; +- rewrite profiles; +- metathesis profiles; and +- independently schedulable constraint/selection participants where the C# model exposes them as + derivational participants. + +Do not collapse an affixation, truncation, reduplication, and mutation profile merely because all are +instances of `AffixProcessRule`. Each profile participates in the tuple denominator. Conversely, +templates, strata, environments, and feature structures enter as carriers/channels/profiles rather +than pretending to be schedulable rules. + +The generator first emits candidates from schema placement and read/write compatibility. Each +candidate must then be one of: + +- `required`: a Machine grammar and discriminating word must exist; +- `retired-invalid`: XML/model placement cannot express it; +- `retired-orthogonal`: a cited structural argument proves no interaction; +- `retired-duplicate`: canonicalization proves it is the same obligation; or +- `blocked-csharp-defect`: C# should support it but currently crashes or behaves incorrectly; red. + +No candidate silently disappears. + +### 7.4 Schedule ledger + +For every required combination, enumerate every scheduling topology admitted by its legal carriers. +Total orders, unordered unions, alternatives, and mixed partial orders are distinct obligations. A +carrier limitation is an explicit retirement, not an absent row. + +## 8. Evidence and ownership + +Machine owns: + +- the feature catalog and schema; +- canonicalization and combination generation; +- required and retired combination rows; +- the conformance grammars containing the interacting rules; +- `words.yaml` cases naming the obligations they witness; +- C# expected structured analyses and typed outcomes; and +- completeness reports for atomic, interaction, ordering, and C# evidence. + +PanGloss imports the catalog and evidence, maps each obligation to its backends, and runs every backend +that claims to represent it. PanGloss may add local diagnostic/unit tests, but those do not satisfy a +Machine semantic obligation. + +A fixture earns semantic credit only from `complete` C# results. `invalidInput` and `nonconvergent` +earn their respective safety/validation obligations but no positive semantic-analysis credit. Missing +C#, uncontrolled crash, malformed result, budget exhaustion, or harness failure is red. + +The adapter outcome is one of `complete`, `invalidInput`, `invalidGrammar`, `partialLoad`, +`nonconvergent`, or `harnessFailure`. Diagnostics are structured and may accompany +`invalidGrammar` or `partialLoad`. Today C# `AnalyzeWord` can collapse an +`InvalidShapeException` to an empty result, epenthesis can throw `InfiniteLoopException`, and a +self-opaquing inverse can run without a logical bound. Therefore these typed outcomes are a required +harness/engine change, not a description of already-controlled behavior. The runner must prevalidate +or intercept those paths, translate only known failures, and report every unknown exception, process +exit, or logical-budget exhaustion as red. Wall-clock limits remain engine management and are not +part of the semantic contract. + +## 9. DTD features currently accepted but not implemented by the C# loader + +Source inspection at Machine commit `73599a8` found these explicit gaps: + +| XML surface | Current C# behavior | Catalog treatment | +|---|---|---| +| `Stratum@cyclicity` | Loader never reads it | `ignored`; cannot claim cyclic-stratum support | +| `Stratum@phonologicalRuleOrder` (`linear|simultaneous`) | Loader never reads it; phonological rules always form a linear cascade | `ignored`; simultaneous cascade is not representable by current C# semantics | +| `PreviousWord` / `NextWord` / `Null` on a phonological subrule | Loader does not load them | `ignored`; cross-word phonological context unsupported through this loader | +| `SyntacticRules` / `SyntacticRule` | Loader does not load them | `ignored` | +| `AffixTemplate@requiredSubcategorizedRules` | Loader does not read it | `ignored` | +| `MorphologicalRule@requiredSubcategorizedRules` | Loader does not read it | `ignored` | +| `MorphologicalRule@outputSubcategorization` and `OutputSubcategorizationOverrides` | Loader does not read them | `ignored` | +| `LexicalEntry@morphologicalRules`, `subcategorizations`, `obligatoryHeadFeatures`, `obligatoryFootFeatures` | Loader does not read them | `ignored` | +| `CompoundingRule@headSubcategorizedRules`, `nonHeadSubcategorizedRules`, `outputSubcategorization` | Loader does not read them | `ignored` | +| simultaneous right-to-left rewrite | DTD has only `simultaneous`; loader maps its direction to left-to-right | `not-expressible` as a distinct variant | +| metathesis alpha variables | Metathesis loader supplies no variable definitions | `not-expressible` unless C# is extended | +| allomorph-environment alpha variables | Loader supplies an empty variable map, then indexes it for an alpha context | `blocked-csharp-defect`; valid XML must produce a controlled red outcome until fixed | +| compound non-head input MPR gate | DTD/model expose head-input gate only | `not-expressible` unless the format/model is extended | +| compound head/non-head alpha bindings | Synthesis contains an explicit TODO and does not unify the two binding sets | `blocked-csharp-defect` when an interaction requires shared binding | +| inactive or failed-loaded IDREF target | Some stratum rule lists and template slots omit the missing runtime object | `ignored-reference`; require diagnostic/model evidence | +| subrule or allomorph construction error | Some loader paths report through the error handler and continue | `partial-load`; never infer whole-grammar success | +| unrepresentable analysis word | `AnalyzeWord` can return an empty set after catching `InvalidShapeException` | runner must distinguish `invalidInput` from a valid no-analysis result | +| epenthesis or self-opaquing divergence | Current paths can throw or run without an explicit logical bound | `blocked-csharp-defect` until exposed as controlled `nonconvergent` | +| simultaneous rewrite with grouped/quantified RHS | Equal top-level child counts select a path that casts RHS children to `Constraint` | `blocked-csharp-defect`; cardinality must be classified by authored node shape as well as effective width | +| metathesis identical/missing switch captures | Identical switch IDs collide during dictionary construction; a resolved ID can still miss the structural-description capture | typed invalid or `blocked-csharp-defect`, determined by the corrected C# contract | + +These rows answer “the XML contains it” separately from “C# HC does it.” If a declared feature is +supposed to work, the correct resolution is to fix Machine and then promote the row to `semantic`, not +to make another engine imitate the ignored behavior invisibly. + +### 9.1 Frozen XML-surface accountability map + +The prose taxonomy is backed by a generated, exact manifest of DTD declarations and loader branches. +The manifest—not this grouped table—is the completeness input. This table states where every surface +family must land and prevents a whole XML family from escaping the semantic review: + +| XML/loader surface family | Required catalog destination | +|---|---| +| document root, languages, activation, DTD defaults, ID/IDREF resolution | §4.1 plus loader outcome records | +| parts of speech; phonological, head, and foot feature systems; symbolic/complex feature values | §4.2 | +| MPR features, groups, match type, and output type | §4.3 | +| character-definition tables, segment/boundary definitions, representations, normalization | §4.4 | +| natural classes, alpha variables, phonetic sequences, simple contexts, quantifiers | §4.5 | +| left/right environments, anchors, previous/next-word and null contexts | §4.5 or explicit §9 limitation | +| lexicon, lexical entries, root allomorphs, stem names/regions, families, properties | §4.6 | +| morphological and realizational rules, subrules, inputs, output actions, gates, output state | §4.7 | +| compounding rules, head/non-head inputs, production restrictions, output state | §4.8 | +| affix templates, slots, required/final flags, loose rules, strata and table assignment | §4.9 | +| rewrite rules/subrules, mode, direction, structural descriptions/changes, reapplication | §4.10 | +| metathesis rules, direction, switch captures, context and movement behavior | §4.11 | +| morpheme/allomorph co-occurrence, polarity, adjacency and target collections | §4.12 | +| syntactic rules and subcategorization surfaces | §9 until implemented | +| runtime Morpher options, selectors, tracing, logical budgets and adapter outcomes | §4.13, outside the XML tuple denominator | + +For each DTD declaration the generated manifest records element/attribute path, type or enum members, +default, cardinality, containing carriers, loader read sites, model destination, execution read sites, +disposition, and feature IDs. For each loader/model branch it records the source location and at least +one feature or typed-outcome ID. CI fails on an unmapped declaration, enum member, default, carrier, +loader branch, or execution branch. Reflection over public model types is supplemental only: private +derived branches and swallowed-error paths require source-maintained branch markers or an analyzer. + +## 10. Known gaps in the existing conformance vocabulary and corpus + +`conformance/constructs.txt` is useful but insufficient as the canonical catalog because its rows mix +rule types, modes, containers, operands, representation, runtime options, and tracing. It does not +enumerate enum/default partitions, carriers, derived rule shapes, or interactions. + +Source and current-fixture inspection identifies at least these gaps or unproven partitions: + +- MPR group `append` is distinct from `overwrite`; current graduated grammars visibly emphasize + overwrite and cannot transfer that evidence to append. +- Negative alpha-variable polarity and multiple distinct alpha variables need distinct evidence. + Reuse of one positive variable already exists in the suffixing-vowel-harmony fixture and must not be + reported as absent. +- Template `final=false`, partial entries/rules, and bound roots need explicit semantic witnesses. +- Morphological `multipleApplication=0`, values greater than one, and the upper DTD boundary need + discriminating evidence rather than comments about default one. +- Compounding multiple application and recursive compound-of-compound behavior remain incompletely + attributed in the existing suite. +- Ordinary and realizational `blockable=false/true` need direct contrasts, not only compound blocking. +- Empty, leading, trailing, and internal omission on morphological RHS must be separately covered; + “subtraction/truncation” is too coarse. +- Reordered captured parts (movement) must be distinguished from repeated capture (copy/reduplication). +- Every rewrite cardinality family—feature change, deletion, epenthesis, expansion, merge, and empty + output—needs both iterative/simultaneous combinations where expressible and direction combinations + where expressible. +- Rewrite subrule priority/overlap, allomorph priority/free fluctuation, template alternatives, and + unordered-rule union are four different choice mechanisms and need separate evidence. +- Metathesis needs right-to-left, anchored, quantified, adjacent, and non-adjacent profiles rather + than one generic construct row. +- Pattern atoms and quantifiers need carrier-specific coverage; loader execution in a root shape does + not prove rewrite/environment/metathesis behavior. +- Featureless phonology, mixed symbolic/complex `FeatureValue` shapes, allomorph-environment alpha + variables, and grouped/quantified simultaneous rewrite RHSs need explicit accepted/ignored/blocked + evidence rather than inheriting a nearby feature-structure or pattern result. +- Multi-table tests must cover disjoint, overlapping, explicit-override, and cross-stratum threading + shapes. +- Required/excluded environments need left, right, bilateral, overlapping, and contradictory cases on + roots and rule allomorphs. +- Morpheme and allomorph co-occurrence each need both require/exclude, all five adjacency values, + multiple targets, chains, and contradictory/cyclic configurations. +- No current completeness mechanism proves every compatible high-level pair, connected triple, + ordering, unordered declaration permutation, or mixed partial order has a discriminating word. +- Existing trace-based `rules:` coverage proves participation, not that the interaction or order is + load-bearing. Counterfactual C# results are required. +- Loader-ignored DTD fields in §9 are currently liable to look covered merely because the grammar + validates. They need explicit limitation tests and reporting. + +This list is the initial audit, not a waiver for anything not named. The generated completeness gate, +not this prose list, is the permanent defense against omissions. + +## 11. Required implementation artifacts + +The design resolves into these Machine-owned artifacts: + +1. a standalone JSON Schema for feature, combination, evidence, and retirement records; +2. a versioned semantic catalog mapping every DTD/loader/model surface to a disposition and effect + signature; +3. an exhaustive candidate generator and canonical ID implementation; +4. a ledger containing every required, retired, or blocked obligation; +5. conformance grammar/word references from each required obligation; +6. a C# runner that records structured semantic identity or typed outcomes per word; +7. declaration-permutation generation for unordered cases and counterfactual variants for ordered + cases; and +8. CI gates for catalog completeness, fixture completeness, C# evidence completeness, and stale + checked-in results when a grammar or word changes. + +Until those artifacts exist, this document is the source-derived design inventory, not a claim that +the current corpus already provides the coverage it specifies. diff --git a/conformance/docs/how-it-is-computed.md b/conformance/docs/how-it-is-computed.md new file mode 100644 index 000000000..1e7b293a0 --- /dev/null +++ b/conformance/docs/how-it-is-computed.md @@ -0,0 +1,456 @@ +# How coverage is computed + +`what-it-claims.md` gives the headline numbers. This document explains where each denominator comes +from and how a numerator is earned — the mechanics behind the claim, not the claim itself. + +## The governing rule: denominators come from the DTD and the engine, never from the corpus + +Every layer below answers "out of how many possible things" before it asks "how many of them does +the corpus demonstrate." That first number is always computed from `HermitCrabInput.dtd` (what a +grammar could legally declare) or from the engine's own source (what it actually reads), and never +by counting what fixtures happen to contain. The reason is structural: a denominator computed from +the corpus grows every time someone adds a fixture, which lets the coverage fraction rise by adding +easy cases instead of hard ones, and makes two runs of the suite at different fixture counts +incomparable. `conformance/rule-interaction-pairs.tsv` is the cautionary example on record — it +enumerates rule-interaction *instances* across whatever fixtures currently exist (1,305 rows at last +count, up from 1,290 when four fixtures were added), so it cannot serve as a coverage denominator and +is not used as one anywhere in this suite; see `decisions-and-lessons.md` for the full story of why +it was demoted to a different job. + +## Presence is not coverage — the idea everything else depends on + +A construct can be declared in a grammar, resolve correctly, and load cleanly, and still change +nothing when the grammar runs — invisible to any engine that only compares parses, and therefore +worth nothing to a claim meant to transfer to a different implementation. Concretely, from +`conformance/interface-witness.tsv`: the `AffixTemplate.requiredPartsOfSpeech` attribute is +*present* in six fixtures, but severing it (removing the attribute and re-parsing every word) +changes no result in four of them — + +``` +AffixTemplate requiredPartsOfSpeech edge-cases/deep-optional-affix-nesting Unobservable +AffixTemplate requiredPartsOfSpeech edge-cases/diacritic-segments Unobservable +AffixTemplate requiredPartsOfSpeech languages/suffixing-extension-slot-ordering Evidenced +AffixTemplate requiredPartsOfSpeech languages/suffixing-vowel-harmony Evidenced +``` + +— and changes one in the other two, where a specific named word's signature flips from a real parse +to none once the attribute is gone. Both kinds of fixture *declare* the attribute; only the second +kind *witnesses* it. Every layer below is built to keep that distinction visible rather than collapse +it, because collapsing it is a mistake this suite has made and re-made — see +`decisions-and-lessons.md`. + +The mechanical test behind "witnessed" is always the same shape, called a **counterfactual**: take a +fixture that declares a surface, neutralize it (delete the element, blank the attribute, remove the +enumerated value — whatever "gone" means for that surface), and re-parse every one of the fixture's +words against the mutant grammar. Four things can happen, and only one of them counts as evidence: + +| verdict | what happened | counts as evidence? | +|---|---|---| +| `Evidenced` | a named word's parse changed | yes — this is a real, word-level witness | +| `EvidencedJointly` | only a *joint* mutation with an independent partner changed a result | weaker; recorded, not counted alone | +| `RequiredByLoader` | the mutant fails to *load* — HermitCrab's own loader threw after DTD validation passed | a genuine engine-semantic fact, but no word was ever reached | +| `RequiredByDtd` | the mutant fails generic DTD content-model validation, before the loader even runs | re-derives the DTD's own content model; proves nothing about the engine | +| `Timeout` | the mutant did not finish in time | no — a timeout is not evidence, and is never read as if it were | +| `Unobservable` | every word parsed identically with the surface removed | no — this is the presence-without-witness case above | + +(Verdict definitions per `conformance/semantic-coverage-counterfactuals.tsv`'s own header.) A +`Timeout` is deliberately never treated as passing or as inconclusive-but-fine: "the sweep could not +look" must never read as "nothing is wrong there." + +## Layer 1: unit surfaces — 264 grammar-observable, 110 demonstrated + +**Denominator.** Every element `HermitCrabInput.dtd` allows to appear, and every value an enumerated +attribute can legally take, read directly off the DTD (`semantic-coverage-baseline.txt`'s own header: +"an element that can appear, or an enumerated attribute value that can be written"). This is a static +property of the schema; adding a fixture cannot change it. + +**Numerator.** `semantic-coverage-counterfactuals.tsv` runs the counterfactual test above once per +surface a fixture actually declares, and the number reported as "demonstrated" is the count of +`Evidenced` (plus the weaker `EvidencedJointly`) verdicts — 110 of 264. The rest are not silently +absorbed: 66 are `RequiredByDtd`, 13 are `RequiredByLoader` (both real facts, neither a parse-time +witness), and every remaining surface carries either an explicit **impossibility proof** +(`semantic-coverage-proofs.tsv` — a proof kind the gate recomputes, such as `dtd-default`: the value +equals its attribute's own DTD default, so a validating parser supplies it whether or not a fixture +writes it, and no word could ever discriminate that) or sits, named, in +`semantic-coverage-baseline.txt` as an acknowledged gap. `constructs.txt`'s eleven +engine-unimplemented surfaces (cyclic strata, syntactic subcategorization, cross-word phonological +context — see `conformance/README.md`) resolve here too, as `no-consumer`/`dead-schema`: proven, not +by a fixture, but by scanning the engine's own source for a reference to the element and finding +none. + +## Layer 2: interface edges — 60 declared, 44 present, 19 demonstrated + +**Denominator.** Every `IDREF`/`IDREFS` attribute `HermitCrabInput.dtd` declares, across 28 elements +— 60 of them, read straight off the DTD (`interface-inventory.tsv`'s header). Each is a typed +handoff: one construct pointing at another (an `Allomorph.stemName` pointing at a `StemName`, a +`CompoundingRule.headPartsOfSpeech` pointing at a `PartOfSpeech`). IDREFs are untyped in a DTD, so +the *target type* for each attribute is not read from the schema at all — it is discovered by +resolving every real reference across the whole corpus and recording what element type answers on +the other end (`observed_target_types` in `interface-inventory.tsv`). + +**Present versus demonstrated.** 42 of the 60 resolve to a real reference somewhere in the corpus — +"present," structural only, exactly the presence half of the distinction above. The demonstrated +count, 15, comes from `interface-witness.tsv`: the same counterfactual test as layer 1, run once per +(element, attribute, fixture) triple where the interface is present, by severing every occurrence of +that attribute in that fixture and re-parsing. The gap between 42 and 15 is the size of a mistake +this suite made once already: an earlier version reported the 42 itself as if it were coverage, and +`interface-witness.tsv` exists specifically to correct that (`decisions-and-lessons.md`). + +**Direction is engine-checked, not name-derived.** Whether a given interface *writes* a payload, +*reads* it (gates on it), or merely *refers* to it structurally is decided by +`SemanticInterfaceDirection`, a table verified against the engine's own read/write sites — not by an +attribute-name convention (does it start with `output`, `assigned`, `required`...). The +name-convention version existed first and was shown wrong by a real field grammar that writes zero +`MorphologicalOutput.MPRFeatures` and instead carries every inflection-class feature through +`LexicalEntry.ruleFeatures`, an attribute the naming convention calls "ref" even though the loader +unions it straight into the same live `MprFeatures` set every reader gates on. See +`decisions-and-lessons.md` for the fuller account; the fix is the reason interaction chains (layer 3) +exist as their own denominator rather than being read off `interface-inventory.tsv` directly. + +## Layer 3: interaction chains — 40 declared, 26 exercised, 9 with a paired witness + +A single interface edge in isolation cannot show what happens to a payload *between* one rule +writing it and another reading it — whether something sits in the path that overwrites, drops, or +otherwise destroys the value first. That composition is what this layer measures. + +**Denominator.** Group every declared interface by the payload type it carries (using the +engine-checked direction from layer 2, not the name-prefix heuristic), and keep only payload types +reached by at least one writer *and* at least one reader — a **chain junction** +(`interaction-chains.tsv`'s own header). One row per (writer edge, payload type, reader edge) at each +junction: 40 total, including junctions no fixture exercises yet, so an entirely untested reader +still appears in its own denominator rather than silently vanishing from it. + +**Numerator.** A chain counts as exercised when the same identifier appears in both the writer's and +the reader's attribute values in one fixture — a real but purely **static co-occurrence check**, not +proof that the payload actually reaches the reader unmutated. Correcting for that: of 40 chains, the +`all-uses` data-flow criterion (Rapps and +Weyuker, 1985 — a def-clear path from writer to reader, not merely both present) is met by 11, down +from 20 in a first published count that used the weaker static check. The suite deliberately targets +`all-uses` rather than the stronger `all-du-paths` (every path, not just one) — a scoping choice made +for the classical reason in the data-flow literature (path explosion, and the cost of proving +infeasible paths infeasible), recorded honestly as a choice made *after* the baseline number was +already in hand rather than argued for in advance. + +**Hazardous.** A chain is flagged `hazardous` in the ledger when at least one exercising fixture also +contains a known **mutating construct** on that payload's path — today, an `outputType="overwrite"` +MPR feature group. This is what layer 4 turns into obligations. + +## Layer 4: obligation cells — 346 enumerated, 18 worth covering, 9 demonstrated + +**Denominator.** For every chain in layer 3, derive the specific test cases that would demonstrate +it via an obligation matrix — this is the layer where MC/DC enters: + +- **Every chain gates — there is no plain, ungated def-use case.** A reader "gates" when it makes a + control-flow decision based on the payload, and that turns out to be true of all 40 chains, not + only the ones literally named `required*`/`excluded*`: `CompoundingRule.headPartsOfSpeech` gates + via `Unify` in engine code exactly as a `required*` attribute does. So every chain contributes the + MC/DC floor of four cells — `PresentControl`, `PresentGatedForm`, `AbsentControl`, + `AbsentGatedForm` — cell kind `McDc`. +- **MC/DC is per condition, not a fixed 2×2.** Where a real fixture's attribute value lists more than + one feature id under a conjunctive or disjunctive match (`requiredMPRFeatures="mprP mprQ"` is a + real, checked-in case), MC/DC over *n* conditions needs *n+1* cases, not 2 — cell kind + `ConditionExtension` adds exactly the extra vectors that specific fixture's condition count + requires, attributed to the fixture that realizes it, never assumed. +- **Mutator cells** add a `MutatorAbsent`/`MutatorPresent` pair per chain for each schema-applicable + **mutator class** — an engine-verified way a payload is altered in transit before the reader sees + it: + 1. **Overwrite** — an `outputType="overwrite"` MPR feature group drops the rest of its group before + unioning in a new value. The only class with a corpus detector today. + 2. **Blocking** — a blocked derivation is rebuilt as a new `Word` from a sibling lexical entry, + clearing and reseeding MPR features, syntactic features, and the root allomorph (hence stem + name) all at once. Reachable from any rule, since every rule defaults `blockable="true"`. + 3. **POS replacement** — an intervening rule's own `outputPartOfSpeech` priority-unions over a + part-of-speech definition placed earlier in the derivation, before a later + `required*PartsOfSpeech` read sees it. The most common mutation any realistic derivational + grammar would contain, and it currently has zero satisfied obligations. + 4. **Compounding non-head drop** — a compound's output is built from the head alone, so a + non-head's entire MPR feature set is never copied forward at all; no overwrite group is even + needed for its definition to fail to reach a later reader. + + Only class 1 is modeled by a corpus-wide detector; the other three are declared and scoped but not + yet automatically found in a fixture. + +346 cells in total. + +**Numerator, and what it actually requires.** A cell is `Satisfied` only by a **pair witness**: +severing the *writer* flips a named word's outcome, **and** severing the *reader* flips that *same* +word — not two independent facts (writer witnessed somewhere, reader witnessed somewhere, possibly on +different words in different fixtures), which would be edge coverage counted twice and is exactly the +fallacy this layer exists to rule out. Two cells meet that bar today. Every other cell is +`NotSatisfied` (the chain isn't even structurally exercised yet) or `Unknown` (structurally exercised, +but the pair witness hasn't been established) — both are named as gaps, never quietly folded into a +passing total. + +**What a cell being satisfied does *not* prove.** The counterfactual machinery proves a **flip** — +severing an attribute changed a word's outcome. It does not by itself prove **role attribution**: +that the flipped word actually occupies the specific matrix cell claimed (that the stem carries the +payload, that the named rule is the gated one, that the observed polarity is the expected one for that +reader). Attribution needs a human judgment on top of the machine-proved flip; a `words.yaml` word can +declare a `claimed_cells` entry naming which cell it witnesses, but that claim is checked against the +recomputed ledger, never taken on trust, and a sign-off is invalidated the moment the underlying +mutation or delta it was reviewed against changes. `conformance/evidence-cards/` renders one card per +cell precisely so this judgment can be made in one read instead of a four-artifact hand-join — see +`how-it-works.md`. + +## What none of these four layers measure + +Stated here because it bears directly on how to read the numbers above, and is stated at more length +in `what-it-claims.md`: nothing across these four layers measures a surface *in combination with* +another surface it wasn't specifically paired with (that is exactly what layers 3 and 4 exist to +start correcting, one payload type at a time, not a claim that the job is finished), and none of them +speaks to the *analysis* (unapplication) direction — every chain in layer 3 and every cell in layer 4 +is derived and judged in the synthesis direction only. Order dependence under an unordered stratum is +also outside what any of these four layers can express at all, existentially quantified criteria being +satisfied by one witnessed interleaving even when a second, unwitnessed one would fail — that hazard +class is pinned only by a hand-crafted fixture (`edge-cases/mpr-overwrite-order-dependence`), never by +a ledger. + +## A second denominator: engine gates, not DTD attribute pairs — 23 gates, 16 witnessed + +Every layer above is keyed to the DTD: an attribute, or a pair of attributes joined by a payload +type. `conformance/engine-gate-inventory.tsv` is keyed to something else entirely — +`SIL.Machine.Morphology.HermitCrab.FailureReason` (`ITraceManager.cs`), the 23-member enum +(excluding `None`) HermitCrab itself uses to name every decision it makes when declining to apply or +unapply something. This is the engine's own vocabulary for "why did this not happen", authored by +whoever wrote the engine, not derived from the schema at all — a genuinely different axis from the +four layers above, not a fifth rung on the same ladder, so none of "what none of these four layers +measure" changes; this layer has its own separate blind spots, described below. + +**Why a second denominator, not a replacement for the first.** The DTD-attribute layers answer "does +severing this payload flip a parse" — the right question for proving a schema-legal construct is +alive. But a schema-derived denominator can only ever name what the schema expresses, and the engine +makes some decisions the schema fuses or never names as its own thing: + +- **Fused.** `FailureReason.RequiredStemName` is ONE engine gate reached from TWO unrelated DTD + attributes on two different elements (`Allomorph.stemName`'s own check in `RootAllomorph.cs`, and + `MorphologicalRule.requiredStemName`'s check in `SynthesisAffixProcessRule.cs`) — a DTD-attribute-pair + ledger has no way to say these are "the same kind of failure," because its cells are organized by + attribute, not by engine decision. `RequiredMprFeatures`/`ExcludedMprFeatures` are each reached from + THREE attributes across three different elements the same way + (`MorphologicalInput`/`HeadMorphologicalInput`/`PhonologicalSubrule`). +- **Unnamed.** `FailureReason.PartialParse`, `FailureReason.BoundRoot`, + `FailureReason.MaxApplicationCount`, `FailureReason.DisjunctiveAllomorph`, and + `FailureReason.SurfaceFormMismatch` have no row in `dataflow-obligations.tsv` at all, because that + ledger's cells are payload write/read pairs and none of these five is that shape — `BoundRoot`, for + instance, is a single-attribute boolean gate (`Allomorph.isBound`) with no reader-side attribute to + pair it with, so a writer/reader-pair denominator cannot even pose the question. + +**What turned out to have an attribute anyway, against this layer's own working assumption when it +was proposed.** The proposal guessed `PartialParse`, `BoundRoot`, `MaxApplicationCount`, +`SurfaceFormMismatch`, `DisjunctiveAllomorph`, and the two template-ordering reasons had no DTD +attribute reaching them at all. Reading `XmlLanguageLoader.cs` line by line for every one of the 23 +raise sites (`EngineGateInventoryLedger.DtdAttributes`'s own doc comment cites the exact lines) showed +that guess half wrong: `BoundRoot` *does* resolve to one attribute (`Allomorph.isBound`), +`MaxApplicationCount` to one +(`MorphologicalRule.multipleApplication`/`CompoundingRule.multipleApplication`), `PartialParse` to two +(`Slot.optional`, `AffixTemplate.final`), and both template-ordering reasons to the same two +(`AffixTemplate.final`, `MorphologicalRule.partial`). Only `SurfaceFormMismatch` and +`DisjunctiveAllomorph` are genuinely attribute-free: the former is a pure engine-internal +reconstruction check with no grammar input at all, the latter is driven by allomorph order and +`Environment` element overlap among siblings, never a flat attribute value. Three more — +`Environments`, `Pattern`, `HeadPattern`/`NonHeadPattern` — join them for a different reason: their +DTD-side driver is child ELEMENT content (`RequiredEnvironments`/`ExcludedEnvironments`, a +`PhoneticSequence`), not an attribute, so `dtd_attributes` is honestly `-` for six gates in total, not +seven. Recording that a guess was wrong, and exactly how, is the point of writing the mapping down +mechanically-cited rather than asserting it. + +**How `Witnessed` is decided, and why it is a WEAKER claim than a `Satisfied` obligation cell — +read this before citing either number as if they meant the same thing.** `EngineGateWitnessSweep` +runs every non-pathological, non-crash fixture's words through the reference engine with tracing on +and records, per word, every non-`None` `FailureReason` value that appears ANYWHERE in that word's +trace tree. A gate is `Witnessed` the moment one word's trace contains it once — full stop. That is +deliberately the weakest question this layer could ask, and for a specific reason: +`FailureRuleAttributor`'s own doc comment (in this same Conformance project) documents that several of +these reasons — `RequiredMprFeatures`, `RequiredSyntacticFeatureStruct` chief among them — fire +*routinely* for a rule that was merely tried against a candidate it has nothing to do with, in a +linear/unordered stratum's search, and that there is no `FailureReason` value that reliably tells +"this candidate specifically conflicts with the rule" apart from "the rule doesn't apply here, as it +structurally never would." A `Witnessed` row here means only **"some word made this gate fire"** — it +does **not** mean "severing a payload provably flipped a parse," which is what a `Satisfied` row in +`dataflow-obligations.tsv` means (a same-word pair witness: severing the writer AND severing the +reader both flip one named word from failed to successful). The two numbers answer different +questions at different strengths, and neither substitutes for the other: a `Witnessed` engine gate can +be true of a fixture that would still show `NotSatisfied`/`Unknown` on every dataflow-obligation cell +touching the same rule, and a rule with a `Satisfied` obligation cell does not automatically make every +engine gate on its path `Witnessed` either — they are simply different measurements, not points on one +scale. + +**The trigger evidence is trace-derived, not a static guess.** `triggered_by_fixtures` and +`triggering_words` come from an actual engine run (`EngineGateWitnessSweep.Sweep`), not from reading +grammar.xml attribute values and inferring what "should" fire — the same standard `TraceRuleAttributor` +and `FailureRuleAttributor` already hold this suite's rule-level attribution to. + +**16 of 23 gates are `Witnessed`.** The 7 that are not are each a specific, named corpus gap, not "the +suite is thin" in the abstract — see `EngineGateInventoryLedgerTests.UnreachedGatesAreTheKnownCorpusGaps` +for the exact reasoning behind each one (a compounding candidate whose head/non-head phonetic pattern +is tried and fails; a rule re-applied to its own `multipleApplication` cap within one derivation; the +non-head-side compounding gates, structurally present but never the one that actually fails; a +`partial="true"` rule tried immediately after an explicit `AffixTemplate final="false"`; and a rule +whose `outputObligatoryFeatures` promise goes unmet by the time `Morpher.IsWordValid` checks it). +## A third constraint layer: what a real FieldWorks project can produce + +Everything above measures two layers: what the HC **engine** does, and what HC's XML/DTD can +**declare**. Neither speaks to a third, narrower constraint: what a real FieldWorks project can +**produce**. `HCLoader` (`Src/LexText/ParserCore/HCLoader.cs` in the separate FieldWorks repo) is the +single component that turns a LibLCM-backed FieldWorks project into an HC grammar — it is the only +place that integrates both the LibLCM data model and what is reachable from it, so it is the right +authority for this third layer. `conformance/fieldworks-producibility.tsv` records, for every +`FailureReason` the engine can report (`ITraceManager.cs`, 23 members besides `None`) and every +IDREF/IDREFS attribute this suite's own DTD inventory tracks (`interface-inventory.tsv`, 60 rows — +same 60 as layer 2 above), whether `HCLoader` can ever produce it. + +**Why a `No` here is an exclusion, not a gap.** Layers 1–4 are all in the business of finding gaps to +close — an unwitnessed surface is something a future fixture could still demonstrate. This layer is +the opposite kind of fact: if `HCLoader` never emits a construct, no FieldWorks user session can ever +produce it, no matter how the grammar is authored, so no fixture — however cleverly written — can make +covering that construct say anything about real FieldWorks use. A `No` here does not mean "not yet +covered"; it means the coverage question is moot for that subject, and the honest response is to +retire it from the "should the suite cover this" conversation rather than keep chasing it. 22 of the +83 subjects landed there. About a third of those (9 of 22, on the interface side) are constructs the +*engine* fully implements and even the engine's own reference XML loader reads — `HCLoader` simply +never wires them up from LibLCM (`CompoundingRule.outputObligatoryFeatures`, `.outputProdRestrictions +MprFeatures`, `HeadMorphologicalInput.requiredMPRFeatures`/`excludedMPRFeatures`, `InsertSegments.` / +`Segments.characterDefinitionTable`, `LexicalEntry.family`, `MorphologicalRule. +outputObligatoryFeatures`, `SymbolicFeature.defaultSymbol`) — a FieldWorks-specific exclusion layered +on top of an engine that could support them. The rest were already dead schema even in the engine's +own loader (the subcategorization/`SyntacticRule` family, plus `LexicalEntry.morphologicalRules` and +the two `obligatory*Features` attributes), so `HCLoader`'s absence there is inherited, not new. + +**Method.** Every verdict required reading the whole of `HCLoader.cs` (~2837 lines) and tracing each +subject to the specific runtime property it would need to set on this repo's own engine classes, +using `XmlLanguageLoader.cs` (this repo's reference HC-XML loader) as ground truth for which property +a DTD attribute maps to where the mapping isn't obvious from the name alone, and this repo's own +`InteractionChainLedger.cs` comments as corroboration for which attributes are dead even in the +engine's native loader. A `No` is backed by a full-file search for the property name and its plausible +spellings (never a single failed grep), and cites what was searched in +`conformance/fieldworks-producibility.tsv`'s `notes` column. `HCLoaderTests.cs` (FieldWorks repo) is +cited as corroborating evidence where it exercises a construct directly. + +**Generation.** The subject list — every `FailureReason` and every interface-inventory attribute — is +extracted mechanically by `conformance/tools/generate-fieldworks-producibility.ps1` from this repo's +own sources (`ITraceManager.cs` and `interface-inventory.tsv`), so it can never go out of sync with +either by hand-typing. The **verdict** for each subject cannot be generated the same way: it required +a human reading of `HCLoader.cs`, a file in a different repository, and is embedded in the generator +script as a researched table. The script's only automated guarantees are that every mechanically- +extracted subject has a recorded verdict (missing one is a hard failure, not a silent default), that +no verdict is stale (recorded for a subject that no longer exists), and that the output has no +duplicate subjects — exactly the internal-shape guarantees `FieldworksProducibilityLedgerTests.cs` +re-checks against the checked-in file. + +**The weakness this cannot fix.** Every other ledger in this document is computed from files that live +*in this repository* (the DTD, the engine source, the fixture corpus), so a test here can recompute +the ledger from scratch and fail loudly the moment it drifts from the checked-in file — that is what +`CheckedInInterfaceInventoryLedgerIsUpToDate` and its siblings do. This ledger cannot work that way: +its authority, `HCLoader.cs`, lives in the FieldWorks repository, which is not a dependency of this +one and must never become one (a test that opens a sibling checkout on disk breaks for every +contributor who does not have that repo cloned next to this one, and CI has no reason to have it at +all). So `conformance/fieldworks-producibility.tsv` is a **snapshot at a point in time**, not a +continuously verified derivation. If `HCLoader.cs` changes — a new attribute gets wired up, an old one +stops being read — nothing in this repo's test suite will notice. The only tests that exist +(`FieldworksProducibilityLedgerTests.cs`) validate the checked-in file's own internal shape (every +subject present exactly once, every `producible` value recognized, a `Yes` cites at least one site, a +`No` cites what was searched) against sources already inside this repo; they cannot and do not attempt +to re-derive a verdict from the FieldWorks repo. Treat this ledger the way you would treat a citation +to an external paper: trustworthy as of when it was written, and due for a re-read — by hand, not by +CI — whenever `HCLoader.cs` is known to have changed. + +## Gate-keyed obligations: MC/DC over the engine's own 23 gates — the primary claim now + +`conformance/gate-obligations.tsv` (`GateObligationLedger`) is the synthesis of the two sections +above: it takes the engine-gate denominator (23 `FailureReason` gates) and, for each one, demands +the two arms MC/DC requires, evidenced with the engine's own vocabulary rather than inferred from a +DTD attribute's spelling. `what-it-claims.md`'s primary funnel table gives the headline counts; this +section is the mechanics behind them. + +**Why this ledger exists, restated precisely.** `dataflow-obligations.tsv` emits four MC/DC arms per +writer/reader chain but `FindPairedWitness` derives the arm it can certify purely from the reader +attribute's own name (`required*` → `AbsentGatedForm`, `excluded*` → `PresentGatedForm`, anything +else → nothing) — of 346 cells, 28 are even certifiable, and it cannot name a gate the schema fuses +into no single attribute at all (six of the 23 gates have no row there whatsoever — see the +"second denominator" section above). `GateObligationLedger` starts from the engine's 23 gates +instead, so every gate gets a denominator row regardless of what the schema calls it. + +**The two arms, and how each is evidenced.** + +- **Blocked.** A word whose parse fails, whose own trace tree (walked exactly as + `EngineGateWitnessSweep` already walks it) names this gate's `FailureReason` directly, and where + severing the DTD attribute or attributes `EngineGateInventoryLedger.DtdAttributes` maps to this + gate (`InterfaceWitnessGate.Sever`, the same severance primitive `interface-witness.tsv` is built + on) flips that *same* word to a successful parse. This is a strictly stronger claim than a + `dataflow-obligations.tsv` chain pairing: the trace attributes the failure to the gate BY NAME, so + there is no need to infer an arm from an attribute's spelling, and no risk of crediting a flip to + the wrong one of two gates that happen to share an attribute (e.g. `AffixTemplate.final` feeds both + `PartialParse` and the two `NonPartialRule*AfterTemplate` gates — a flip is only credited to the + gate whose own `FailureReason` the blocked word's trace actually contains). +- **Control.** A word — anywhere in the same fixture — where the SAME grammar rule instance that fed + the Blocked arm's gate fires in a *successful* parse (`TraceRuleAttributor` over the rule id + `GrammarRuleIndex` resolves for that XML element), proving the rule can apply at all and that the + Blocked arm's failure is attributable to the gate rather than to a rule that structurally never + runs. Only resolvable when the gated construct sits directly on `MorphologicalRule`, + `CompoundingRule`, or `RealizationalRule` — an `Allomorph`, a co-occurrence rule, or a template/slot + construct (`AffixTemplate`, `Slot`) has no "Applied" trace event to check a rule id against at all, + the same documented gap `FailureRuleAttributor`'s own doc comment records for allomorph identity. + When the writer element is not one of those three, the Control arm is reported `NotEvidenced` + naming exactly that limitation — never guessed, and never silently downgraded to "Unknown". + +**The two layer verdicts, and why a miss says WHERE.** Every obligation also carries: + +- **`xml_reachable`** — whether any DTD attribute or element reaches the gate at all. Read directly + off `EngineGateInventoryLedger.DtdAttributes`: `-` means no attribute, but five of its six `-` + entries ARE still reachable via element content (`Environments` via child elements, `Pattern`/ + `HeadPattern`/`NonHeadPattern` via `PhoneticSequence` content, `DisjunctiveAllomorph` via allomorph + sibling order) and are marked `xml_reachable=Yes` on that basis. Only `SurfaceFormMismatch` is + `xml_reachable=No`: it is a pure engine-internal reconstruction check (`Morpher`'s confirming- + synthesis shape comparison) with no grammar attribute or element input at all. +- **`flex_producible`** — FieldWorks' own HCLoader capability, read straight from + `fieldworks-producibility.tsv` (treated as fixed, per that file's own doc comment — this ledger + does not re-derive or drift-check it). Only `ObligatorySyntacticFeatures` is `flex_producible=No`. + +An obligation is `worth_covering` only when both are `Yes` — 21 of 23 gates (42 of 46 obligations) +today. A gate that IS worth covering can still be `NotEvidenced` for reasons that have nothing to do +with either layer, and each is named distinctly rather than collapsed together: + +- **Unreached in the current corpus.** 6 of the 7 `Unreached` gates from `engine-gate-inventory.tsv` + are worth covering but no fixture triggers them at all yet (the seventh, `ObligatorySyntacticFeatures`, + is also `flex_producible=No`, so it is excluded before reaching this check). No candidate word + exists to evidence either arm from, so both are `NotEvidenced` naming the corpus gap directly. +- **No severance primitive for a bare element-content gate.** `Environments`, `DisjunctiveAllomorph`, + and `Pattern` are `xml_reachable=Yes` via element content and ARE witnessed by the corpus, but this + ledger has no isolable way to sever "this one rule's `PhoneticSequence` shape" or "this allomorph's + sibling order" without touching unrelated rules — a real tooling gap, named as exactly that, not + attempted and not guessed. +- **Severance found, but the trace never names this gate for the flipped word.** The gate's + `FailureReason` may fire only as routine noise against a candidate structurally unrelated to a + word's final result (`FailureRuleAttributor`'s own documented phenomenon) — severing the attribute + can still flip an unrelated word's outcome for a different reason, and this ledger refuses to credit + that as evidence for THIS gate. +- **Control-only: the writer element is not rule-indexed.** Even when the Blocked arm IS evidenced, + the Control arm reports `NotEvidenced` by name whenever the gated construct's element + (`Allomorph`, `MorphologicalInput`, `AffixTemplate`, `PhonologicalSubrule`, a co-occurrence rule) + is not one of the three `GrammarRuleIndex` can resolve. `HeadProdRestrictMprFeatures` is the one + gate today whose blocking attribute (`CompoundingRule.headProdRestrictionsMprFeatures`) sits + directly on a `CompoundingRule` element, so it is the only gate with both arms `Evidenced` — + contrasting it against, say, `BoundRoot`'s `Allomorph`-rooted Control arm is the check that the + Control arm's limitation is about the ELEMENT KIND, not a broken mechanism (see + `GateObligationLedgerTests.OnlyHeadProdRestrictMprFeaturesHasBothArmsEvidenced`). + +**Where the severance evidence comes from.** For every DTD attribute that is also an `IDREF`/`IDREFS` +attribute (`interface-inventory.tsv`'s own scope), `GateObligationLedger` reads the already-computed +`interface-witness.tsv` rather than re-running the engine. For the small number of gates whose DTD +attribute is boolean (`Allomorph.isBound`, `Slot.optional`, `AffixTemplate.final`, +`MorphologicalRule.partial`, `*.multipleApplication`) — never an `IDREF`, so `interface-witness.tsv` +never covers them — it falls back to a fresh `InterfaceWitnessGate.Evaluate` run, the exact same +severance primitive, just not already cached in a checked-in file. Either way, the attribution check +(does the candidate word's own baseline trace name this gate) is always a fresh, in-process traced +parse — one per fixture, shared across every gate that touches it, so a corpus-wide sweep costs one +traced pass per fixture rather than one per (gate, fixture) pair. + +**Cost, and why the tests read the checked-in file.** `GateObligationLedger.Compute` runs a real +traced engine sweep (one parse per word, per fixture any worth-covering gate triggers) plus a +severance re-parse per Blocked-arm candidate — the same order of cost as +`EngineGateInventoryLedger.Compute`. `GateObligationLedgerTests`' assertions all read +`GateObligationLedger.Read` (the checked-in file); only `CheckedInGateObligationLedgerIsUpToDate` +recomputes, and it is `[Explicit]` — the same convention `EngineGateInventoryLedgerTests` already +established, and the same one `dataflow-obligations.tsv`'s own tests do NOT need, because +`DataflowObligationLedger.Compute` never runs the engine at all (it only re-derives schema-derived +chains and reads already-checked-in witness data). diff --git a/conformance/docs/how-it-works.md b/conformance/docs/how-it-works.md new file mode 100644 index 000000000..1c0094e82 --- /dev/null +++ b/conformance/docs/how-it-works.md @@ -0,0 +1,110 @@ +# How it works: an operator's reference + +Every regenerable file under `conformance/` in one place: what it holds, the exact command that +regenerates it, and which test gates it against drift. Commands are quoted verbatim from +`src/SIL.Machine.Morphology.HermitCrab.Conformance/Program.cs`'s own `--help` text and argument +parser — run `dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --help` to +get the same text live. Every command below takes `--fixtures conformance` +and (for the flags in the second table) an implicit `--repository-root` it discovers automatically +from the current directory; pass `--repository-root ` explicitly if you're running from +somewhere else. + +Two command shapes, non-writing and writing, exist for every ledger below: the bare flag +(`--interface-inventory`) recomputes and diffs against the checked-in file, exiting nonzero if stale +— this is what a drift test runs. The `--write-*` variant recomputes and overwrites the checked-in +file. Regenerating never flips a run's own exit code to green: every one of these prints its +findings *before* writing, specifically so that regenerating a stale ledger can never be mistaken for +having fixed whatever made it stale. + +## Coverage report (fast, no engine reference needed) + +| file | regenerate | gated by | +|---|---|---| +| `coverage.csv` | `dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --coverage-report` | printed construct-coverage check in the same run (fails the run if any in-scope `constructs.txt` entry has zero coverage) | +| `rules.csv` | same command (both are written together) | printed dead-rule check in the same run (fails if any `grammar.xml` rule id is exercised by zero words) | + +`coverage.csv` is one row per (language, word, construct); `rules.csv` is one row per (language, rule +id, exercising words) — a rule with an empty `words` column is a dead rule. + +## Semantic coverage (the four layers of `how-it-is-computed.md`) + +| file | regenerate | gated by | cost | +|---|---|---|---| +| `semantic-coverage-baseline.txt` | `--write-coverage-baseline` | `--semantic-coverage` (no `[Explicit]` — cheap: reads the DTD and every `grammar.xml`, no re-parsing) | cheap | +| `semantic-coverage-counterfactuals.tsv` | `--write-counterfactual` | `--counterfactual`, and pinned against drift by `CounterfactualGateTests.cs` | **expensive** — re-parses every fixture once per surface it declares; the `[Explicit("re-parses every fixture once per surface")]` test is not part of a default run | +| `semantic-coverage-evidence.tsv` | `--write-coverage-evidence` | `--coverage-evidence`, pinned by `EvidenceLedgerFreshnessTests.cs` | **expensive** — `[Explicit("re-parses every fixture once per Surface item plus once per Ordering adjacent pair")]`; always run `--write-counterfactual` first, since this command reads the Surface ledger back off disk rather than recomputing it | +| `interface-inventory.tsv` | `--write-interface-inventory` | `--interface-inventory`, pinned by `InterfaceInventoryLedgerTests.cs` | cheap — resolves declared IDREFs against the corpus, no re-parsing | +| `interface-witness.tsv` | `--write-coverage-traceability` (see below — bundled) | `--coverage-traceability`, pinned by `InterfaceWitnessLedgerTests.cs` | **expensive** — `[Explicit("re-parses every present interface x fixture pair; ~2-3 minutes")]`, one severance re-parse per present interface × fixture | +| `interaction-chains.tsv` | `--write-interaction-chains` | `--interaction-chains`, pinned by `InteractionChainLedgerTests.cs` | cheap — a static co-occurrence/junction computation over `interface-inventory.tsv` and the DTD, no re-parsing | +| `dataflow-obligations.tsv` | `--write-dataflow-obligations` | `--dataflow-obligations`, pinned by `DataflowObligationLedgerTests.cs` | cheap — derived from `interaction-chains.tsv`, no re-parsing | +| `construct-claim-corroboration.tsv` | `--write-coverage-traceability` (bundled) | `--coverage-traceability`, pinned by `ConstructClaimCorroborationTests.cs` | cheap — a structural join against `interface-witness.tsv`, already computed; the test itself notes "no reparse, so this runs on every pass rather than needing `[Explicit]`" | +| `grammar-coverage-ledger.tsv` | `--write-coverage-traceability` (bundled) | `--coverage-traceability`, pinned by `GrammarCoverageLedgerTests.cs` | cheap — joins three already-checked-in ledgers, no re-parse of its own | +| `fold-in-candidates.tsv` | `--write-coverage-traceability` (bundled) | `--coverage-traceability`, pinned by `FoldInCandidateLedgerTests.cs` | cheap — reads `semantic-coverage-counterfactuals.tsv` back rather than reparsing | +| `evidence-cards/*.md`, `evidence-cards/index.tsv` | `--write-evidence-cards` | `--evidence-cards` | cheap — purely a rendering of already-checked-in ledger facts; never recomputes anything itself, so its only failure mode is going stale relative to what it renders | +| `generated/hc-conformance-manifest.v1.json` | `--generate-manifest` | `--check-manifest`, pinned by `ConformanceManifestTests.cs` | cheap — hashes and validates every fixture, no engine parsing | + +**`--write-coverage-traceability` writes four files in one invocation**, and its non-writing form +(`--coverage-traceability`) is the one expensive step in this group: it re-sweeps +`interface-witness.tsv` (the severance sweep above) and then performs three cheap joins on top of the +freshly swept result — `grammar-coverage-ledger.tsv`, `construct-claim-corroboration.tsv`, and +`fold-in-candidates.tsv`. Because even the *check* (non-writing) path re-runs the severance sweep, +this whole command is, in `Program.cs`'s own words, "a deliberate, occasional command — never part of +ordinary CI — not a cheap drift check." Run it by hand when you need those four files current, not as +a routine gate. + +**`rule-interaction-pairs.tsv`** (`--write-rule-interaction-pairs`, checked by +`--rule-interaction-pairs`) is cheap to regenerate — a structural enumeration of pipeline-permitted +rule pairs per stratum, no re-parsing — but is **not** one of the four coverage layers and is not a +coverage denominator at all; see `how-it-is-computed.md` and `decisions-and-lessons.md` for why. It +exists purely as a per-grammar pruning tool (which adjacent rule pairs are even worth a counterfactual +run), and has no completeness gate of its own beyond the drift check. + +## Files that are checked, not generated + +Three files in this group are **hand-authored** — a person writes and edits them — and are validated +mechanically rather than produced by a `--write-*` flag: + +- **`semantic-coverage-proofs.tsv`** — impossibility proofs. Each row names a proof kind + (`dtd-default`, `no-consumer`, `not-in-signature`, `blocked-by-defect`, …) the gate *recomputes* + from the engine/DTD rather than trusting the prose; a stale or rejected proof fails + `--counterfactual`'s completeness check, reported as `STALE PROOF` / `REJECTED PROOF`. +- **`semantic-coverage-presence-waivers.txt`** — surfaces knowingly counted as covered on presence + alone, with the reason written next to each. `--write-coverage-baseline`'s run requires this list + to equal the recomputed presence-only set exactly (`UNWAIVED` / `STALE PRESENCE WAIVER` findings), + so a waiver cannot silently accumulate and a fixed line must be deleted by hand. +- **`semantic-catalog.yaml`** — the curated semantic inventory scope. There is no `--write-*` flag for + it at all: `--propose-semantic-catalog` prints a review-only proposal to stdout and explicitly + "never changes `conformance/semantic-catalog.yaml`" (`Program.cs`'s own usage text). A human reviews + the proposal and edits the checked-in catalog by hand; `--semantic-coverage` then audits the + checked-in file for internal consistency (an unmapped surface fails the audit) but never rewrites + it. + +`words.yaml` and `grammar.xml` themselves are, of course, also hand-authored — that is the entire +point of the suite — and are validated on every `--generate-manifest`/`--check-manifest` run against +`schema/words.schema.json` and `HermitCrabInput.dtd` respectively, before anything is written. + +## Non-ledger contents of `conformance/` + +- **`adapters/hc-dotnet-wrapper.sh`** — a one-line wrapper making C#'s own reference tool + (`hc.dll`) satisfy the 3-positional-argument `batch` adapter contract it doesn't natively expose + (`PROTOCOL.md` section 7). Not needed for self-check mode; only for pointing `--adapter` at `hc.dll` + itself. +- **`skills/`** — the agent-facing authoring/review loop (`author-coverage-cell`, + `review-coverage-claim`, `measure-authoring-quality`, `revise-coverage-harness`) used to fill + `dataflow-obligations.tsv` gaps. Its own `README.md` in that directory is the reference; it produces + `words.yaml` content and coverage claims, never a ledger, and its output is subject to every gate + above like any other authored fixture content. + +## Running the harness itself (not a ledger — the conformance run proper) + +``` +# self-check: in-process C# oracle against every fixture +dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --include-pathological + +# adapter mode: materializes words.txt/expected.tsv to temp, runs an external engine +dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --fixtures conformance --adapter "" +``` + +`--include-pathological` is required to run the one `budget_ms` fixture; omitted, it's excluded and +reported as such rather than silently skipped without comment. Neither of these two invocations +writes or checks any ledger — they run the conformance fixtures themselves, per `PROTOCOL.md`. diff --git a/conformance/docs/pipeline-design.md b/conformance/docs/pipeline-design.md new file mode 100644 index 000000000..dcb3b4e4d --- /dev/null +++ b/conformance/docs/pipeline-design.md @@ -0,0 +1,203 @@ +# The coverage pipeline: inventory, evidence, proof, completeness + +The claim this pipeline has to support is not "we ran a lot of tests". It is: **here is the inventory of +what must be covered, and here, per item, is the example and the counter-example.** Every part below +exists to make that claim mechanically checkable rather than asserted. + +## Contract + +For every item in the inventory, exactly one of these must hold, and the gate recomputes which: + +1. **Evidence** — a counter-example: the item is neutralized in a copy of a fixture's grammar and a + recorded outcome changes. +2. **Proof** — an impossibility claim of a named kind, re-verified at gate time. + +Nothing else passes. An item with neither fails the build. An item with both fails the build, because a +proof that outlives its own evidence is stale by definition. + +Three properties the contract depends on, each already paid for once: + +- **Neutralization is exhaustive, not arbitrary.** An enum value is neutralized against EVERY declared + sibling, not one. Trying a single arbitrary sibling silently reports "no difference" when the sibling + chosen happens to be a synonym, which is a statement about our tooling wearing the costume of a + statement about the engine. +- **A counter-example names its word.** Evidence proven with a probe word that is not in the fixture's + `words.yaml` is not evidence, because the sweep never parses it. +- **"I could not look" never reads as "nothing there."** A timeout is not a pass, and an unobservable + mutation is not a proof. + +## Data model + +``` +CoverageItem the inventory: what we have committed to cover + id stable, content-derived + kind Surface | Ordering | Interaction + origin dtd-element | dtd-enum | adjacent-transposition | rule-pair + fixture where it is expected to be evidenced + +Evidence produced mechanically, never hand-written + itemId + fixture which fixture supplied the evidence + exampleWord the word, present in that fixture's words.yaml + exampleOutcome its outcome with the item intact + counterexampleKind Word | LoadFailure | None + counterexampleOutcome + mutation exactly what changed, including WHICH sibling + verdict Evidenced | RequiredByDtd | RequiredByLoader | EvidencedJointly + | Unobservable | Timeout + +Proof only where evidence is impossible + itemId + kind dtd-default | no-consumer | not-in-signature | blocked-by-defect + | disjoint-domains | unordered-invariant | inactive-member + | pos-disjoint | template-masked | never-fires | feature-value-disjoint + check what the gate RECOMPUTES; never free prose +``` + +The last seven kinds above are Ordering-only, recomputed fresh from the checked-in grammar on every gate +run rather than read from a file: `disjoint-domains` (an earlier rule's effect cannot reach a later rule's +sensitive set), `unordered-invariant` (the pair's own Stratum compiles to a cascade that tries every rule +regardless of position), `inactive-member` (one member of the pair either carries `isActive="no"` itself, +so its list position is never read, or -- for an AffixTemplateSlots pair -- is an active Slot whose +referenced `morphologicalRules` all fail to resolve to an active rule, including a Slot with no such +attribute at all, so the Slot contributes no morpheme wherever it sits), `pos-disjoint` (the two rules' +`requiredPartsOfSpeech` cannot both be satisfied by one root), `template-masked` (an AffixTemplateSlots +pair whose owning Stratum is unordered AND every rule referenced by every Slot of that template is also in +the Stratum's own `morphologicalRules` list, so the cascade already reproduces everything the template can +produce and slot order is invariant), `never-fires` (a `PhonologicalRule`'s shared `PhoneticInput`, or +every one of its active subrules' `LeftEnvironment`/`RightEnvironment`, names a natural class that resolves +to zero active segments -- counting only active `FeatureValue`/`SegmentDefinition` declarations, mirroring +the loader -- so the rule can never fire and its list position is a no-op regardless of which sibling it +sits next to), and `feature-value-disjoint` (two `PhonologicalRule`s whose active subrules are gated by +disjoint `Environment` natural classes, where neither rule's output segment is a member of the other's +environment class or its `PhoneticInput` class, so at most one can ever match a given site and neither can +create a new site for the other -- the case `disjoint-domains` alone cannot certify because the two rules +may share the same input class, which looks like an overlap until the environments are shown mutually +exclusive). + +`Kind` stays on `CoverageItem` and off `Evidence` — an item's kind is a property of the item, not of one +piece of evidence for it — so a ledger row is a join of the two. + +**A proof's `check` must be recomputed, and the recomputation must be about the GRAMMAR, not about the +fixture's words.** The distinction is the whole contract. "No word in this fixture triggers the rule" is +the GAP condition — it cannot distinguish independence from test words too weak to tell — and writing it +in the `check` column converts an untested item into a proven one. A proof says two rules cannot interact +in any grammar of this shape; if adding a word could falsify it, it was never a proof. + +`label-symmetry` was removed rather than kept. Its only use claimed that alpha-variable names are +interchangeable labels; that was false, because alpha variables unify across every `VariableFeature` a +rule declares, so renaming one to collide with another reverses which words parse. The check was weak in a +specific and repeatable way: it never required the two values to CO-OCCUR in a grammar before believing +they were interchangeable. + +`counterexampleKind` is the field that stops a weaker result from hiding inside a strong headline. +`LoadFailure` says the mutant would not load — real evidence that the item is structurally required, but +NOT a word-level contrast, and the two must never be summed into one number without saying so. + +## Generators + +The inventory is generated, never hand-maintained; a hand-edited inventory is one that shrinks to fit +whatever happens to pass. + +| Generator | Source | Items | +|---|---|---| +| Surface | the DTD's elements and enumerated attribute values | 194 | +| Ordering | adjacent transpositions of each ordered list | 146 | +| Interaction | rule pairs whose domains structurally overlap | 58 of 1,305 (see below) | + +That cell read "≤ 627 pairs" until 2026-08-14. The figure could not be reproduced from any +checked-in artifact and no committed computation yields it; it appears to be a design-time +upper-bound estimate, in the same family as the 1,465 and 1,342 estimates corrected elsewhere. +The measured value is the ledger's `Overlaps` count: 58 of 1,305 rows, against 30 `Disjoint` and +1,217 `Undetermined`. + +**This "Interaction" row is `conformance/rule-interaction-pairs.tsv`'s generator, and it is a +per-grammar pruning device, not a coverage denominator.** The row count grows with the fixture set +(1,305 rows currently, 1,217 `Undetermined` by construction) and must never be cited as bounding the +interaction space. The actual mechanical denominators above the surface/ordering layers are the +integration/edge layer (`conformance/interface-inventory.tsv`, DTD-derived, 60 interfaces) and the +integration/chain layer (in progress), both sized from the DTD and engine rather than from how many +pairs the current corpus happens to contain. + +**Ordering is n−1 per list, not n! and not C(n,2).** Adjacent transpositions generate the symmetric group, +so pinning every adjacent swap pins the total order. The two 16-rule lists in the corpus cost 15 items +each rather than 2×10¹³ permutations. A non-adjacent swap decomposes into adjacent ones and buys nothing. + +**An unobservable swap must prove independence, not pass by silence.** That is what the +`disjoint-domains` proof kind is for, and it has to cover feeding and bleeding, not only the input +pattern a rule matches: the earlier rule's EFFECT (its output segments, plus its own input segments, +since consuming or altering a segment can destroy an environment as surely as producing one can create +it) and the later rule's SENSITIVE set (its input segments, plus every segment reachable from its +`Environment`/`LeftEnvironment`/`RightEnvironment` templates) must not intersect, recomputed from the +grammar at gate time. An earlier check that compared only output against input missed exactly this: +`mpr-gated-exception`'s `prNasalAssimAlveolar`/`prObstruentDeletion` pair was certified `disjoint-domains` +because the outputs and inputs alone never intersect, but `prObstruentDeletion` only fires inside a +`LeftEnvironment` of nasal segments, and `prNasalAssimAlveolar`'s output IS nasal -- classic feeding, and +empirically confirmed (swapping the pair changes `menulik` from a real parse to no parse at all). +Otherwise "swapping these changed nothing" is indistinguishable from "our words are too weak to tell". + +**Interaction is the 3-leg necessity check** already built for joint mutation — disable A, disable B, +disable both — because interaction is exactly `effect(A∧B) ≠ effect(A) ∘ effect(B)`. Pairs whose domains +cannot overlap are pruned by the same static check that backs `disjoint-domains`. + +## Completeness + +One gate, recomputed from the fixtures on every run: + +- every generated item resolves to Evidence-with-a-counter-example or a Proof that re-verifies; +- no Proof names an item that is now evidenced, or an item no longer in the inventory; +- the checked-in ledger matches a fresh recompute; +- coverage counts are reported per `counterexampleKind`, never as a single blended total. + +## The five pilot candidates + +Chosen to exercise every branch of the contract, not five of the easy one. If the pipeline handles these +five it handles the shape of the whole inventory; if it handles only the first, it proves nothing. + +| # | Item | Kind | Branch exercised | +|---|---|---|---| +| 1 | `dtd:element/AffixTemplates` in `loader-isactive-breadth` | Surface | Word counter-example, parse to no-parse (`'takul': ok::TA+KUL\|takul -> ok::-`) | +| 2 | `dtd:element/AllomorphCoOccurrenceRules` in `morphotactic-attribute-breadth` | Surface | Word counter-example, the OTHER direction: no-parse to parse (`'sol': ok::- -> ok::SOL\|sol`) | +| 3 | `dtd:element/AffixTemplate` in `diacritic-segments` | Surface | `counterexampleKind = LoadFailure` — the weaker class that must not blend into the headline | +| 4 | `prAlpha`/`prHighTrigger` adjacent swap in `feature-system-breadth` | Ordering | Generated item, not DTD-derived; needs `disjoint-domains` if no delta | +| 5 | `dtd:enum/Stratum/cyclicity/cyclic` | Surface | The Proof branch — no evidence exists and none should be manufactured | + +Candidate 2 matters because a counter-example that only ever removes a parse would leave the pipeline +untested against evidence that ADDS one, and 47 of the corpus's deltas are that direction. + +## Cost + +Measured, not estimated: bare process startup is 110-150ms, a 4-word fixture evaluates in 350-380ms, a +27-word fixture in 460ms. The sweep runs one evaluation per surface PER FIXTURE — about 1540 of them, +not 194 — and 1540 x 0.35s reconciles the observed 541s. + +Startup is therefore only ~30% of a mutant's cost, and batching alone lands at 230-340ms, missing a +200ms target. Three levers, in order of what they actually buy: + +1. **Stop at the first differing word.** Every mutant currently parses every word in the fixture, but + `Evidenced` needs exactly ONE counter-example. `Unobservable` still parses everything, which is + correct: it is the verdict that must look everywhere before claiming there is nothing to see. +2. **Stop at the first fixture that evidences a surface.** ~1540 evaluations for 194 surfaces is ~8x + redundancy, and the ledger already keeps only the strongest verdict per surface. +3. **Batch mutants per child process**, amortizing startup toward zero. + +The child process itself is not negotiable — it is what bounds memory after abandoned in-process work +took this machine to 37GB committed. Batching keeps the kill at batch granularity with a per-mutant +watchdog inside; a batch that hangs is killed and retried one-at-a-time, so the safety property survives +and only the pathological case pays the old price. + +Levers 1 and 2 shrink the NUMBER of parses rather than the cost of each. Both change what the ledger +records, so each must state plainly that it stopped early and why — a run that quietly skips work reads +exactly like a run that covered it. + +**Measured, and it retires the 200ms target.** Over the 138-item ordering sweep: 201.6s wall clock for 158 +evaluations, averaging 1276ms, against 350-460ms measured on small fixtures — the spread is fixture size, +with `deep-optional-affix-nesting` alone at 7.6s. Lever 1 was measured directly rather than projected: over +the 31 evidenced items, 202 of 578 words could have been skipped, **34.9%** — and only on evidenced items, +which are 22% of the total. Batching removes ~120ms of ~1276ms, roughly 10%. + +So 200ms per evaluation is NOT reachable for whole-fixture evaluation: process startup alone is 110-150ms +of it, and the parse itself exceeds the remainder on every fixture measured. Realistic is 250-350ms for +typical fixtures, and large ones will never approach it. The honest lever is not making each evaluation +faster but running fewer of them — stopping at the first fixture that evidences a surface, since ~1540 +evaluations currently cover 194 surfaces. diff --git a/conformance/docs/severance-mechanics.md b/conformance/docs/severance-mechanics.md new file mode 100644 index 000000000..43a428f01 --- /dev/null +++ b/conformance/docs/severance-mechanics.md @@ -0,0 +1,117 @@ +# Severance mechanics: what the tool can and cannot show you + +Read this before attempting a coverage obligation. Every fact here was discovered the expensive way, +by an author spending most of a budget rediscovering it. None of it is guessable from the ledgers. + +## What severance is + +`InterfaceWitnessGate.Sever` removes **one attribute's value from every element of that name in the +fixture**, then reparses. That is the whole primitive. Three consequences that decide most +obligations: + +**It is fixture-wide, not per-element.** Severing `LexicalEntry.partOfSpeech` strips it from all +fifteen entries at once. So severance can *unblock* a word as easily as block one: remove the payload +a gate reads and the gate stops applying, so a word that failed may now parse. Reasoning about +severance as if it removed the payload from one entry makes a same-word fail-to-pass flip look +impossible when it is routine. This is the single most common wrong conclusion. + +**Removing a gate's input makes the gate vacuous, not false.** Every MPR and stem-name check in the +engine is guarded on a non-empty set — `Subrules[i].RequiredMprFeatures.Count > 0 && !IsMatch(...)`. +Sever the attribute and the condition is skipped entirely. That is why a witness is a *flip*, not a +polarity change. + +**It cannot add a value, and it cannot touch element content.** Anything reached only through child +elements — `RequiredEnvironments`, `ExcludedEnvironments`, `PhoneticSequence`, allomorph ordering — has +no severance primitive at all. `Environments`, `Pattern` and `DisjunctiveAllomorph` are unwitnessable +today for this reason, and no word fixes that. + +## Attributes that can never be severed + +Removing a DTD `#REQUIRED` attribute makes the grammar invalid, so the mutant throws and the row is +recorded `RequiredByDtd` — never `Evidenced`, whatever word you try. There are 46 such declarations; +the ones that block obligations are: + +| attribute | element | +|---|---| +| `primaryMorpheme`, `otherMorphemes` | `MorphemeCoOccurrenceRule` | +| `primaryAllomorph`, `otherAllomorphs` | `AllomorphCoOccurrenceRule` | +| `partsOfSpeech` | (see the DTD for the declaring element) | + +Both co-occurrence gates are therefore **unwitnessable by authoring**. Their every attribute is either +`#REQUIRED` or already equal to its own DTD default. Covering them needs a different severance lever +— whole-element removal — not a cleverer word. + +## Control arms need a rule id, and most elements do not have one + +A `Control` arm must name the rule that fired successfully, and `GrammarRuleIndex` maps a fired rule +back to a `grammar.xml` id for exactly these element names: + +`MorphologicalRule`, `RealizationalRule`, `CompoundingRule`, `PhonologicalRule`, `MetathesisRule`, +plus pseudo-ids for `MorphemeCoOccurrenceRule` / `AllomorphCoOccurrenceRule`. + +`GrammarRuleIndex.ResolveAncestorRuleId` extends this by walking up from `MorphologicalInput` or +`PhonologicalSubrule` to their nearest rule-element ancestor -- per the DTD, a `MorphologicalInput` is +always nested under a `MorphologicalRule`/`RealizationalRule` and a `PhonologicalSubrule` always under +a `PhonologicalRule`, so both always resolve this way. `Allomorph` and `AffixTemplate` do **not**, +and never will by ancestor-walking: an `Allomorph` is always a child of `LexicalEntry`, never of any +rule, and an `AffixTemplate` sits directly under `Stratum` with no `id` attribute of its own either +(the DTD never declares one) -- there is no rule, and no identity of its own, to attribute a Control +arm to. An obligation whose gated construct sits on one of those two genuinely cannot have its Control +arm attributed, no matter what control word exists in the corpus -- this is a structural fact about the +schema, not a tooling gap. + +## Three engine behaviours that look like something else + +**`outputPartOfSpeech` overrides; it does not set.** Severing it does not blank the derived word's +category — it stops the override, so the stem reverts to its pre-derivation category. An +`AbsentGatedForm` through that writer therefore needs a reader that rejects the *pre-derivation* +category, which is a different grammar shape from the one you would first reach for. + +**Stem names compare by object identity** (`SynthesisAffixProcessRule.cs:106`, +`RequiredStemName != input.RootAllomorph.StemName`). A fixture declaring one `StemName` can never +produce a same-word flip on both sides, because there is no second identity to contrast with. Two +`StemName` elements are a precondition, not a nicety. + +**Compounding gates come in two independent tiers, both reading `input.MprFeatures`.** Rule-level +`HeadProdRestrictionsMprFeatures` (`SynthesisCompoundingRule.cs:116`) is checked once before any +subrule; subrule-level `RequiredMprFeatures`/`ExcludedMprFeatures` (`:137`, `:154`) are checked per +subrule inside a loop whose output is the union of every subrule that applies. If one attribute feeds +both tiers, severing it collapses both and neither can be observed alone. If two subrules partition a +single binary feature exhaustively, one of them always applies and the inner gate can never be the +sole cause of a failure. + +## Producibility does not compose along a chain + +`fieldworks-producibility.tsv` is keyed per ATTRIBUTE, and that is weaker than it looks. Two attributes +can each be producible while the chain between them is not, because HCLoader may populate them from +different FLEx fields that can never hold the same value. + +The measured case: `MorphologicalOutput.MPRFeatures` is producible (`HCLoader.cs:969`, from +`msa.ToInflectionClassRA`/`ToProdRestrictRC`) and `MorphologicalInput.excludedMPRFeatures` is producible +(`HCLoader.cs:1717`) -- but `:1717` draws only from `slot.ReferringObjects.OfType()`, +FieldWorks' own mechanism for blocking a slot on irregularly inflected forms. So an affix conferring a +flag that a sibling affix excludes is NOT producible, even though both ends are. + +The same reader IS reachable from a lexical entry: `HCLoader.cs:746` puts the inflType feature on an +irregular variant's entry, and `:1717` excludes that same feature on the slot. That is why +`LexicalEntry.* -> MorphologicalInput.excludedMPRFeatures` is genuine and the affix-sourced version is +not. + +So when a chain's producibility matters, check that the writer's FLEx source field and the reader's are +the same channel. The per-attribute ledger cannot tell you this, and no automated gate in this +repository can either -- it requires reading HCLoader. + +## A Timeout is a statement about the machine + +A `Timeout` verdict means the mutant did not finish inside the budget on the machine that ran it. It +is not a property of the grammar. Four rows once recorded `Timeout`, were argued to be genuinely slow +rather than load-dependent, and later resolved on a quieter machine — two of them to `Evidenced`, +having suppressed real coverage for as long as they stood. Treat a reappearance as a signal to +re-sweep, never as a verdict to record or reason from. + +## Before you start + +Run `conformance/tools/check-obligation-feasibility.ps1 -Obligation `. It answers, mechanically, +whether the attribute is severable, whether writer and reader co-occur in a fixture, and whether the +Control arm can be attributed at all. An obligation that fails those checks is not an authoring task, +and no amount of word-writing changes that. diff --git a/conformance/docs/what-it-claims.md b/conformance/docs/what-it-claims.md new file mode 100644 index 000000000..8a934a626 --- /dev/null +++ b/conformance/docs/what-it-claims.md @@ -0,0 +1,191 @@ +# What this suite claims + +Every number here was read from a checked-in ledger in this directory. None is estimated, and each +names the file it came from so you can recompute it. + +## The claim + +**An engine that produces the expected parse for every case in this suite has correctly implemented +every construct the suite demonstrably covers — where "demonstrably covers" means: removing the +construct changes a parse.** + +That last clause is the whole claim, and it is narrower than it sounds. Read the next section before +relying on it. + +## The primary funnel: gate-keyed obligations (23 engine gates, 46 obligations) + +**This is the headline number now.** `gate-obligations.tsv` is keyed to +`SIL.Machine.Morphology.HermitCrab.FailureReason` — HermitCrab's own 23-member enumeration +(excluding `None`) of the decisions it makes when declining to apply or unapply something — rather +than to a DTD attribute pair. Every gate contributes exactly two obligations, the two arms MC/DC +demands: **Blocked** (a word fails, the engine's own trace names this exact gate as why, and severing +the construct that feeds the gate flips that same word to a successful parse) and **Control** (the +same grammar rule instance fires in a different, successful parse, proving the rule can apply at all +and that the Blocked arm's failure is attributable to the gate, not to a rule that never runs). + +| | count | +|---|---| +| gates | 23 | +| obligations (gates × 2 arms) | 46 | +| worth covering (`xml_reachable`=Yes and `flex_producible`=Yes) | 42 | +| arms evidenced | **14** (9 Blocked, 5 Control) | +| gates with *both* arms evidenced | **5** (`ExcludedMprFeatures`, `HeadProdRestrictMprFeatures`, `HeadRequiredSyntacticFeatureStruct`, `RequiredMprFeatures`, `RequiredSyntacticFeatureStruct`) | + +**Why this ledger, not `dataflow-obligations.tsv`, is now the primary claim.** The older ledger +enumerates four MC/DC arms per writer/reader chain but its generator can certify at most one of them +per chain (see "342 gaps, but only 14 an author can pick up" below) — of 346 enumerated cells, 28 are +even certifiable, and only 9 are satisfied. Worse, it has no row at all for six of the engine's 23 +gates, because its cells are DTD-attribute write/read pairs and those six gates are not that shape +(`PartialParse`, `BoundRoot`, `MaxApplicationCount`, `DisjunctiveAllomorph`, `Environments`, +`SurfaceFormMismatch` — see `how-it-is-computed.md`'s engine-gate-inventory section). Keying the +denominator to the engine's own 23 gates instead fixes both problems at once: every gate gets a row +regardless of whether the schema names it with an attribute, and the Blocked arm's evidence is +stronger than the old chain pairing because the engine's own trace *names* the failure reason, +rather than the old generator inferring an arm from an attribute's spelling. + +**Both ledgers are published; they measure different things.** `dataflow-obligations.tsv` still +answers its own question honestly — whether a specific WRITER/READER PAYLOAD PAIR survives full MC/DC +treatment for the 40 chains `interaction-chains.tsv` derives from the DTD — and neither its file nor +its tests are going away. `gate-obligations.tsv` answers a different, now-primary question: whether +each of the engine's 23 own decision points is independently shown to matter. Read +`how-it-is-computed.md`'s gate-obligations section for the full mechanics, including exactly which +9 obligations are evidenced today and why the rest are not (a corpus gap the current fixtures never +trigger, a construct FieldWorks' HCLoader can never produce, an element-content gate with no +severance primitive built yet, or a rule element `GrammarRuleIndex` cannot resolve to a fired-rule +id for the Control arm) — every one of those reasons is named in the row's own evidence text, never +collapsed to a bare "Unknown". + +## The DTD-attribute-pair layers (kept, no longer the headline) + +The four layers below were this suite's original, and until now only, coverage measurement. They are +still computed, still tested, and still meaningful for the narrower question they ask (does a +specific *schema-legal construct* do anything) — but see the section above for why the gate-keyed +ledger, not this one, is the number to cite as the suite's primary claim. + +## Coverage is measured in four layers + +| layer | denominator | demonstrated | source | +|---|---|---|---| +| Unit surfaces | 264 grammar-observable | **110** | `semantic-coverage-counterfactuals.tsv` | +| Interface edges | 60 declared, 44 present | **19** | `interface-inventory.tsv`, `interface-witness.tsv` | +| Interaction chains | 40 declared, 26 exercised | **9** paired | `interaction-chains.tsv` | +| Obligation cells | 346 enumerated, 18 worth covering | **9** | `dataflow-obligations.tsv`, `fieldworks-producibility.tsv` | +| Gate arms (MC/DC) | 46, 42 worth covering | **14** | `gate-obligations.tsv` | + +Each layer is stricter than the one above, so the numbers fall as the demand rises. The unit layer +asks "does this knob do anything." The cell layer asks "is there a named word whose parse flips when +this exact payload is severed, with a control proving the rule was capable of firing." Nine cells meet +that bar today. + +**The suite does not claim 346/346.** It claims 9, and it publishes every other cell as a named gap that +cannot be quietly absorbed. + +One row changed what it measures, not just its number. The interaction-chain row used to report the +chains whose writer and reader are each evidenced *somewhere* -- a weak reading, since two separate +words can satisfy it. That figure is 23 today. The row now reports chains with a same-word PAIRED +witness, which is 9 and is the bar the obligation layer actually uses. The weaker number is still +derivable from `interface-witness.tsv` if anyone wants it; it is simply not what this table claims. + +### 337 gaps, but only 9 an author can pick up + +That 342 is honest as a count and misleading as a work list. + +`DataflowObligationLedger` emits four MC/DC arms per chain, and `FindPairedWitness` can certify +exactly one of them. It reads the arm's direction off the reader attribute's *name*: a `required*` +reader blocks on absence, so the arm it can certify is `AbsentGatedForm`; an `excluded*` reader +blocks on presence, so it is `PresentGatedForm`. Any other reader name returns nothing at all. + +| cells | count | can the generator ever mark it Satisfied? | +|---|---|---| +| the one certifiable arm on each chain with a `required*`/`excluded*` reader | 28 | yes | +| the other three arms on those same chains | 84 | no | +| all four arms on the 12 chains reading `head*`/`nonHead*` | 48 | no -- polarity is unreadable from the name | +| Mutator cells | 182 | no -- the detectors prove a structural precondition, never a word's outcome | +| ConditionExtension cells | 4 | no | + +So 28 of the 346 are certifiable at all. Then the third constraint layer applies: +`fieldworks-producibility.tsv` marks **10 of those 28 as constructs HCLoader cannot emit**, so no +FieldWorks project could ever exercise them and a witness would prove nothing about real use -- +six through `CompoundingRule.outputProdRestrictionsMprFeatures` as writer, six through the +`HeadMorphologicalInput` MPR readers. + +**That leaves 18 cells worth covering, of which 9 are satisfied and 9 are outstanding -- but one of the +nine should not be counted.** An adversarial review found that +`MorphologicalOutput.MPRFeatures -> MorphologicalInput.excludedMPRFeatures` has a genuine behavioural +witness on a chain FieldWorks cannot produce: HCLoader populates that reader only from its own +irregular-form blocking mechanism, never from an affix output. So the defensible figure is **8 of 18**, +and the ninth is retained in the corpus as an engine test with its coverage claim withdrawn. See +`severance-mechanics.md`, "Producibility does not compose along a chain" -- the per-attribute +producibility ledger cannot express this, and no automated gate here can catch it. The funnel +is the honest form of this number: + +| | cells | +|---|---| +| enumerated by the generator | 346 | +| certifiable by it at all | 28 | +| also producible by FieldWorks | 18 | +| satisfied today | **9** | + +Do not read the other 318 as phantom. A control arm is a real obligation -- this suite's own rule is +that a gated form proves nothing without one -- and the twelve `head*`/`nonHead*` chains gate real +behaviour. What those 318 lack is a **certifier**, not a reason to exist. The distinction this ledger +does not yet draw, and should, is between "unsatisfied" and "nothing can currently establish this", +because only the first is work someone can pick up. + +## Presence is not coverage + +The single most important distinction here, and the one this suite got wrong five times before +getting it right. + +A construct can be *present* in a grammar, referenced correctly, load cleanly — and still change no +parse when removed. Such a construct is invisible to any engine that compares parses, so it cannot +be part of a claim that transfers to another implementation. `interface-inventory.tsv` therefore +labels its 42 as **present**, structural only, and defers to `interface-witness.tsv` for what is +actually witnessed. The gap between 42 and 15 is exactly the size of the mistake. + +Of the unit layer's 264: 110 carry a real parse-time witness (`Evidenced` plus `EvidencedJointly`), +66 are `RequiredByDtd` — the grammar will not load without them, which re-derives the DTD's own +content model and proves nothing about semantics — and 13 are `RequiredByLoader`, which is genuine +loader behaviour but still not a parse-time difference. + +## What is expressible and never read by the engine + +Eleven surfaces across three feature areas are legal in the DTD and consulted by no engine code +path. A grammar using them loads and behaves as though they were absent: + +- **Cyclic strata and simultaneous phonological rule order** — `Stratum/cyclicity="cyclic"`, + `Stratum/phonologicalRuleOrder="simultaneous"`. +- **Syntactic subcategorization** — six surfaces, the whole feature unimplemented end to end. +- **Cross-word phonological context** — `PreviousWord`, `NextWord`, `Null`. + +This list is machine-derived from the proof ledgers and gated, so it cannot silently drift. See +`../README.md` for the full statement. + +## What the criteria cannot express + +Two hazard classes sit outside the data-flow and MC/DC criteria entirely, and are pinned only by +hand-crafted fixtures: + +- **Order dependence under an unordered stratum.** The criteria are existentially quantified — one + witnessed interleaving discharges a pair — so a second interleaving can still fail with the ledger + green. +- **The analysis direction.** Chains are derived and judged in the synthesis direction only. Nothing + in the chain layer speaks to unapplication. + +## What is not claimed at all + +- That HermitCrab is correct. Every gate here validates the **test suite**, never the engine. An + unwitnessed obligation is a statement about this corpus. +- That the fixture set is minimal, or that its 33 grammars are the right 33. +- That a passing engine is correct on grammars unlike these. The fixtures are synthetic and small by + design; scale is deliberately not tested here. +- That the hand-crafted fixtures are exhaustive for the hazards they pin. They were arrived at by + analysis and experience, and there is no denominator behind them. + +## Host configuration + +Every expected result was generated under specific `Morpher` settings — `MaxStemCount`, +`DeletionReapplications`, `MaxAlternatives`, `MergeEquivalentAnalyses`, and the entry/rule selectors. +`DeletionReapplications` in particular changes *which parses are found*, not merely how fast. An +engine choosing different values may diverge on a fixture that is otherwise green. See `PROTOCOL.md` +section 8. diff --git a/conformance/docs/what-it-is.md b/conformance/docs/what-it-is.md new file mode 100644 index 000000000..811ab4040 --- /dev/null +++ b/conformance/docs/what-it-is.md @@ -0,0 +1,193 @@ +# What this suite is + +An engine-agnostic conformance suite for morphological/phonological parsers: a set of grammars and +words with pre-computed correct answers, plus the machinery that justifies calling that answer set +complete. `what-it-claims.md` covers the second half. This document covers the first: the fixture +format, what a case is, and why the corpus is split into `languages/` and `edge-cases/`. + +## Shape + +``` +conformance/ + languages// grammar.xml + words.yaml -- typologically-selected synthetic languages + edge-cases// grammar.xml + words.yaml -- micro-grammars for things no shared grammar hosts + HermitCrabInput.dtd the published grammar DTD (byte-identical to the library's embedded copy) + schema/ JSON Schema for words.yaml and the manifest + generated/ the versioned JSON manifest a consumer imports + adapters/ wrapper scripts for engines whose CLI predates the adapter protocol + evidence-cards/ one rendered Markdown card per obligation cell (see how-it-is-computed.md) + skills/ the agent skills that author and review coverage claims + PROTOCOL.md the adapter contract: CLI shape, TSV format, signature algorithm +``` + +Per `conformance/generated/hc-conformance-manifest.v1.json`, today that is **33 fixtures — 8 under +`languages/`, 25 under `edge-cases/` — holding 446 words in total**, computed by summing the +manifest's own `caseCount` field per fixture rather than counted by hand. Regenerate the manifest +with `hc-conformance --generate-manifest`; `--check-manifest` fails the build if the checked-in file +has drifted from what a fresh scan produces. + +## The fixture contract: exactly two authored files + +Every fixture is exactly two files, and there is no third, generated restatement of either: + +- **`grammar.xml`** — a `HermitCrabInput` XML document, validated against `HermitCrabInput.dtd`. It + is the authoritative grammar: parts of speech, phonological feature system, character definitions, + strata, morphological and phonological rules. This is also the reference *representation* — the + one every fixture ships, and the one the C# founding oracle read to produce every case's ground + truth. An engine that cannot consume XML directly names an alternate grammar representation instead + (`PROTOCOL.md` section 6); `grammar.xml` remains the source of truth either way. +- **`words.yaml`** — the single canonical authored format for ground truth. Front matter + (`language`, `inspired_by`, `sources`, `requires`, optionally `budget_ms` and `expect_crash`) + followed by a `words` list, one entry per case. Validated against `schema/words.schema.json` + (`hc-conformance-words/v1`). + +An earlier product, `hc-conformance-corpus/v1`, duplicated `words.yaml`'s ground truth into a +generated 409KB JSON file — and that file carried *less* than the 383KB of authored source it was +built from, because the authored comments hold reasoning (why a fixture exists, what it pins) that +JSON cannot express. It has been deleted, along with its schema. What a manifest genuinely +contributes is provenance and integrity, not case data, so that is the only generated artifact that +survives: `generated/hc-conformance-manifest.v1.json` (`schema/conformance-manifest.schema.json`), +one entry per fixture carrying `fixtureId`, `category`, `displayLanguage`, both files' paths and +SHA-256 hashes, `caseCount`, and `expectedCrash`. A consumer reads the manifest to discover fixtures +and verify integrity, then reads `grammar.xml` and `words.yaml` directly for the grammar and the +cases themselves. + +## What a case is + +A case is one entry in `words.yaml`'s `words` list: a literal word string, a `note` explaining what +it pins, and exactly one of three outcomes. The simplest case is a bare-root control with a single +trivial parse: + +```yaml +- word: ka + note: Bare head root, number=sg, class=a. + parses: + - signature: "KA|ka" + rules: [] +``` + +A case exercising more machinery carries a longer `rules:` chain and its own `gloss`: + +```yaml +- word: menulik + note: >- + TULIK + mrNPfx: underlying "meN+tulik" -- the placeholder nasal assimilates to alveolar "n" + ..., then the now-real "n" triggers prObstruentDeletion ... -- "mentulik" -> "menulik". + parses: + - signature: "NPFX+TULIK|menulik" + rules: [mrNPfx, prNasalAssimAlveolar, prObstruentDeletion] +``` + +(`conformance/edge-cases/compounding-breadth/words.yaml`, `conformance/edge-cases/mpr-gated-exception/words.yaml`.) + +A word carrying **more than one** distinct analysis lists more than one entry under `parses:` — the +signature algorithm (`PROTOCOL.md` section 3) treats a word's full analysis set as a multiset of +`|` strings, so ambiguity is represented directly as multiple list items, not +as a separate field. + +Per-parse fields: `signature` and `rules` are required (`rules` is the traced list of rule ids the +oracle actually applied, checked against a live trace — not merely declared); `gloss` is optional +prose; `exercises` optionally names which constructs (`constructs.txt` vocabulary) this specific +parse demonstrates, distinct from the word-level `exercises` naming what the word as a whole +demonstrates; `guess` marks a parse only reachable via root-guessing (see below). + +Two more per-word fields worth knowing: + +- **`neutralizes`** — names a construct (an id from the grammar) whose deactivation this word is + designed to observe. A word can observe a deactivation either by failing (paired with + `blocked_by`) or by parsing *differently* once the construct is gone — the schema admits either + outcome, because the point is what the word demonstrates about removing something, not which + polarity that removal produces. +- **`claimed_cells`** — a word's declaration that it witnesses one specific cell of + `dataflow-obligations.tsv` (see `how-it-is-computed.md`). Checked mechanically against that ledger + and never trusted at face value. + +## `expect_fail`, `expect_skip`, and `expect_crash` + +Three distinct ways a word's expected outcome can be "not a parse": + +| | means | oracle status | schema constraint | +|---|---|---|---| +| `expect_fail: true` | well-formed input, the grammar legitimately produces **zero** analyses | `ok`, signature `-` | `parses` must be empty; if paired with `blocked_by`, names the rule(s) responsible | +| `expect_skip: true` | the word contains a character the grammar's character-definition table never declares | `SKIPPED` | `parses` must be empty; mutually exclusive with `expect_fail` | +| `expect_crash: true` (fixture-level) | the founding oracle itself did not complete — it crashed while loading or parsing | no result row at all, only a `STARTED` sentinel | fixture must declare exactly one case | + +`expect_fail` and `expect_skip` are both legitimate, "ok" outcomes for the harness, and the schema +refuses a word marked as both — an engine returning `SKIPPED` where `ok`/`-` was expected (or vice +versa) is a genuine status mismatch, not a fuzzy match. A concrete `expect_skip` case: +`edge-cases/loader-pattern-shapes/words.yaml`'s word `bit` — `"i"` is never declared in that +grammar's character table, so the C# oracle throws `InvalidShapeException` rather than returning a +zero-analysis `ok`, and the fixture pins `SKIPPED` rather than `expect_fail` to keep that distinction +honest. + +`expect_crash` is the strongest and strangest of the three: for a crash fixture, the engine under +test is expected to **also** crash (not necessarily with the same exception) to count as a **pass** +— reproducing the founding oracle's crash is what conforming means here. If the engine crashes +without `expect_crash` set, that is always a fail; if `expect_crash` is set and the engine returns a +normal result instead of crashing, that is *also* a fail, even though the engine's behavior is +arguably better than the oracle's — `PROTOCOL.md` section 2 is explicit that this pins an +implementation limitation of the founding oracle, not a linguistic fact. Two fixtures do this today +(`edge-cases/metathesis-comparison-crash`, `edge-cases/simultaneous-epenthesis-cascade`, per the +manifest's `expectedCrash` field), and each keeps its `words.txt` to a single word, since nothing +after a crash is ever reached. + +One more fixture-level field: `budget_ms`, present only on +`edge-cases/deep-optional-affix-nesting/words.yaml` (`budget_ms: 15000`) — a wall-clock ceiling for a +pathological word whose correct answer is a large but fully tractable analysis set (924 distinct +analyses for one word). A fixture carrying `budget_ms` is excluded from a default self-check run and +only exercised with `--include-pathological`, because it is deliberately expensive, not because its +answer is in doubt. + +## The `guess` parse, and its adapter-mode gap + +A parse marked `guess: true` is only reachable through `Morpher`'s root-guessing path +(`LexicalGuess`), which the CLI's own `batch` command has no flag to enable — so a `guess: true` +parse can only ever be checked by the harness's in-process self-check mode, never by an external +adapter driven through the documented `batch` contract. Adapter-mode materialization omits any word +carrying a `guess: true` parse from the generated `words.txt`/`expected.tsv` entirely, so such words +are asserted by self-check only and an adapter run neither sees them nor can be falsely failed by +them (`languages/polysynthetic-stratal-derivation-chain/words.yaml` has a worked example: a guessed +shape reachable at two different strata renders as the same signature listed twice, since a +signature multiset does not dedupe). + +## `languages/` versus `edge-cases/` + +The corpus is split into two directories that answer different questions, and the split is +deliberate rather than a filing convenience. + +**`languages/`** holds 8 dense, synthetic grammars, each simulating a distinct typological profile — +invented lexemes and segment inventories, no orthographic claim about any real language — where +ordinary words exercise several constructs at once rather than probing one mechanism in isolation: + +| Directory | Simulates | +|---|---| +| `suffixing-vowel-harmony` | Long-distance backness harmony, long agglutinative suffix chains, consonant-gradation allomorphy | +| `templatic-root-modification` | Templatic root-and-pattern morphology, stem names, OCP co-occurrence, simultaneous rewrite | +| `suffixing-extension-slot-ordering` | Realizational rules, MPR groups, verbal reduplication, post-nasal mutation, CARP-style extension ordering | +| `metathesis-phase-isolation` | Infix, circumfix, reduplication, metathesis, subtractive truncation | +| `polysynthetic-stratal-derivation-chain` | Derivation-then-inflection recursion across strata, incorporation-style compounding, guessed stems | +| `suffixing-evidential-adjacency-chain` | Evidential suffix chain, morpheme-adjacency co-occurrence, phonology-free | +| `prefixal-discontinuous-slot-dependency` | Left-edge position-class template, fused/discontinuous slot dependencies | +| `fusional-realizational-morphology` | Inflection classes, syncretism, ablaut as sole exponent, realizational blocking/suppletion | + +(Table per `conformance/README.md`.) `how-it-is-computed.md` shows why this half of the split matters +beyond typological breadth: of the interfaces the whole corpus actually exercises, the large majority +are reached by one of these eight, not by a fabricated fixture — realistic grammars carry most of the +suite's real evidentiary weight, and the fabricated half exists for what realistic grammars cannot +host. + +**`edge-cases/`** holds 25 micro-grammars for things no shared, realistic grammar can host +faithfully: loader/XML-semantics probes (`loader-isactive`, `loader-pattern-shapes`, +`loader-default-symbol`), an `expect_crash` pin, a `budget_ms` pathological stress case, and +allomorphy/rewrite pins whose exact rule shape a naturalistic grammar wouldn't contain (e.g. +`mpr-gated-exception`'s deliberately-isolated MPR-feature exclusion, or +`metathesis-comparison-crash`, reduced down from a larger fixture specifically to isolate one +engine-internal comparison defect). Each is deliberately narrow — most declare `requires: []` or a +short, purpose-built grammar — because its entire job is to pin one specific hazard cleanly, not to +read as a plausible grammar. + +Neither directory subsumes the other. A construct that can occur naturally belongs in a +`languages/` grammar, extended rather than duplicated, because a realistic grammar that grows a +realistic feature buys coverage *and* keeps that feature interacting with everything else the +grammar already does; an edge-case fixture is the fallback for what cannot be made to occur +naturally at all. diff --git a/conformance/edge-cases/alpha-variable-name-collision/grammar.xml b/conformance/edge-cases/alpha-variable-name-collision/grammar.xml new file mode 100644 index 000000000..02c8d7a14 --- /dev/null +++ b/conformance/edge-cases/alpha-variable-name-collision/grammar.xml @@ -0,0 +1,139 @@ + + + + + + AlphaVariableNameCollision + + n + + + + back + + +bk + -bk + + + + round + + -rd + +rd + + + + + Main + + + i + + + + + y + + + + + a + + + + + u + + + + + + + + vowels + + + + + + + doubleAlphaFlip + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Main + + + au + AU + au + + + + + + diff --git a/conformance/edge-cases/alpha-variable-name-collision/words.yaml b/conformance/edge-cases/alpha-variable-name-collision/words.yaml new file mode 100644 index 000000000..4c199389c --- /dev/null +++ b/conformance/edge-cases/alpha-variable-name-collision/words.yaml @@ -0,0 +1,38 @@ +# Two co-occurring VariableFeature declarations in one rule. See grammar.xml's header for the full +# argument: this fixture exists to challenge semantic-coverage-proofs.tsv's label-symmetry claim for +# dtd:enum/VariableFeature/name/%CE%B1, not to close a gap in the ordinary sense. Checked in here is +# the CORRECT baseline (distinct names, "α" and "β"); the collision variant (renaming one to match +# the other, exactly the counterfactual mutation) is not part of this checked-in grammar -- it was +# hand-applied to a scratch copy and re-run against the same oracle, and produced the OPPOSITE +# result for both words below. That is the finding: the label-symmetry proof does not hold in +# general, only for every fixture the automated sweep happens to have measured so far (each of which +# has at most one VariableFeature reachable per rule application). +# +# Oracle: the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over a Debug build +# of src/SIL.Machine.Morphology.HermitCrab.Tool). Every signature is transcribed from that run. + +language: AlphaVariableNameCollision +inspired_by: ["synthetic two-variable alpha-agreement probe (not modeling any real language)"] +sources: + - "conformance/semantic-coverage-proofs.tsv, dtd:enum/VariableFeature/name/%CE%B1 label-symmetry challenge" +requires: [phonology] +words: + - word: au + note: >- + The raw underlying shape. prDoubleAlpha fires obligatorily on any two adjacent vowels, so this + exact string is not a valid surface form: "a" (back) must flip to front and "u" (round) must + flip to unrounded. + expect_fail: true + exercises: + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: ia + note: >- + AU's correctly-rewritten surface form: "a" (back, round-) flips backness only, becoming "i" + (front, round-); "u" (back, round+) flips roundness only, becoming "a" (back, round-). The two + flips are independent under the DECLARED (non-colliding) variable names. + parses: + - signature: "AU|ia" + rules: [prDoubleAlpha] + exercises: + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" diff --git a/conformance/edge-cases/bistratal-overlapping-segment-representation/grammar.xml b/conformance/edge-cases/bistratal-overlapping-segment-representation/grammar.xml new file mode 100644 index 000000000..48d02f02e --- /dev/null +++ b/conformance/edge-cases/bistratal-overlapping-segment-representation/grammar.xml @@ -0,0 +1,59 @@ + + + + + BistratalOverlappingSegmentRepresentation + Any + + + Inner + + a + b + i + s + + + + Outer + + d + e + s + + + + + Inner + + + basi + ROOT1 + root1 + + + abis + ROOT2 + root2 + + + + + Outer + + + des + ROOT3 + root3 + + + sed + ROOT4 + root4 + + + + + + + diff --git a/conformance/edge-cases/bistratal-overlapping-segment-representation/words.yaml b/conformance/edge-cases/bistratal-overlapping-segment-representation/words.yaml new file mode 100644 index 000000000..e2f13b9b2 --- /dev/null +++ b/conformance/edge-cases/bistratal-overlapping-segment-representation/words.yaml @@ -0,0 +1,67 @@ +# Synthetic construct-shaped mimic -- see STAGING.md and grammar.xml's own header comment. Oracle: +# pangloss (`pg_parse::Morpher`, driven directly -- see STAGING.md's "Verification" section), NOT the +# C# founding oracle -- authored and verified against this repo's own Rust engine only. Signatures +# below are transcribed verbatim from that run, not hand-derived. + +language: BistratalOverlappingSegmentRepresentation +inspired_by: ["synthetic bistratal shared-representation probe (not modeling any real language)"] +sources: + - "docs/conformance/representative-typology-basis.md S1.2.5 (Multi-table: shared-representation-across-tables configuration)" +requires: [] +words: + - word: des + note: >- + ROOT3, entered on the Outer stratum (table t2), whose own "s" segment ("cs2") is the fixture's + divergent-identity witness -- SAME spelling as t1's own "s" ("cs1"), DIFFERENT + SegmentDefinition/identity. A plain positive control proving the Outer stratum's own lexicon + works normally despite the shared representation. + provenance: "docs/conformance/representative-typology-basis.md S1.2.5" + parses: + - signature: "ROOT3|des" + rules: [] + exercises: + - "CharacterDefinitionTable: more than one table, one per stratum" + + - word: sed + note: ROOT4, also Outer-stratum, also using t2's own "s" -- a second positive control (different root, same table). + provenance: "docs/conformance/representative-typology-basis.md S1.2.5" + parses: + - signature: "ROOT4|sed" + rules: [] + exercises: + - "CharacterDefinitionTable: more than one table, one per stratum" + + - word: basi + note: >- + ROOT1, entered on the Inner stratum (table t1) -- its own "s" is "cs1", a DIFFERENT segment + from t2's "cs2" despite the identical spelling ("s" shared across BOTH tables is exactly + what makes `Grammar::char_tables` non-pairwise-disjoint, per multi_table_detail's own check). + Per pg_parse::Morpher's own surface-tokenization convention (mirroring `pg_foma::emit:: + surface_table`'s "last stratum's table" rule), the initial input string is segmented ONLY + against the grammar's LAST stratum's table (t2 here) -- t2 never declares "a"/"b"/"i" at all, + so a bare Inner-stratum root can never itself be a complete, tokenizable surface word in this + architecture (matching `tests/two_table_symbol_divergence.rs`'s own documented "a bare, + unaffixed root declared on a NON-final stratum... is never a complete surface word by itself" + finding for the analogous disjoint-table case) -- an architectural fact about multi-stratum + derivation generally, NOT a MultiTable-shared-representation-specific bug. Pinned honestly as + SKIPPED (invalid shape), not silently omitted. + provenance: "rust/crates/pg-foma/tests/two_table_symbol_divergence.rs module doc" + expect_skip: true + exercises: + - "CharacterDefinitionTable: more than one table, one per stratum" + + - word: abis + note: ROOT2, also Inner-stratum -- same architectural non-reachability as basi. + provenance: "rust/crates/pg-foma/tests/two_table_symbol_divergence.rs module doc" + expect_skip: true + exercises: + - "CharacterDefinitionTable: more than one table, one per stratum" + + - word: eds + note: >- + A well-formed string over t2's OWN alphabet (e, d, s all legitimate t2 segments) that is + simply not any lexical entry's own shape -- a plain negative control proving t2's inventory + coverage alone doesn't manufacture spurious analyses. + expect_fail: true + exercises: + - "CharacterDefinitionTable: more than one table, one per stratum" diff --git a/conformance/edge-cases/compounding-breadth/grammar.xml b/conformance/edge-cases/compounding-breadth/grammar.xml new file mode 100644 index 000000000..c8d1dfb08 --- /dev/null +++ b/conformance/edge-cases/compounding-breadth/grammar.xml @@ -0,0 +1,240 @@ + + + + + + CompoundingBreadth + + n + + other + + + + number + + sg + pl + + + + + + class + + a + b + + + + + Main + + a + u + i + k + t + m + p + + + + Any + + + + Main + + + + joinTwice + + + + + + + + + + + + + + + + + + + + + + + + joinInsert + + + + + + + + + + + + + + i + + + + + + + + + + joinNever + + + + + + + + + + + + + + m + + + + + + joinDecoy + + + + + + + + + + + + + + p + + + + + + tplSuf + + + + mi + + + TPLSUF + + + + + ka + + + KA + ka + + + tu + + + TU + tu + + + + ki + + + KI + ki + + + + ti + + + TI + ti + + + + ku + + + KU + ku + + + + pa + + + PA + pa + + + + + + diff --git a/conformance/edge-cases/compounding-breadth/words.yaml b/conformance/edge-cases/compounding-breadth/words.yaml new file mode 100644 index 000000000..a10cfdf5e --- /dev/null +++ b/conformance/edge-cases/compounding-breadth/words.yaml @@ -0,0 +1,146 @@ +# Compounding breadth. See grammar.xml's header, especially on why the patterns are bounded. +# +# Oracle: the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over a Debug build +# of src/SIL.Machine.Morphology.HermitCrab.Tool). Every signature is transcribed from that run. +# +# Seven discriminating negative controls, each isolating one declaration: +# kaki NonHeadRequiredHeadFeatures: "ki" is number=sg where the rule requires a plural non-head. +# kati NonHeadRequiredFootFeatures: "ti" is class=b where the rule requires class=a. +# kamtu CompoundingRule@multipleApplication="0" on crNever, which would join with an "m". +# kaptu CompoundingRule@isActive="no" on crDecoy, which would join with a "p". +# kaitu CompoundingSubrule@isActive="no" on crJoinInsert's own subrule, which would join with an "i". +# kutu HeadRequiredHeadFeatures: "ku" is number=pl where the rule requires a singular head. +# patu HeadRequiredFootFeatures: "pa" is class=b where the rule requires a class=a head. +# +# kaitu is deliberately NOT a second subrule inside crJoin. An earlier draft put the "i"-inserting +# decoy there, and hand-mutating a copy showed it can never be evidenced that way: a CompoundingRule +# with two active subrules only ever finds an unapplication through the FIRST one declared, regardless +# of which one the counterfactual activates. crJoinInsert gives the decoy its own rule instead, with no +# second subrule to be shadowed by. + +language: CompoundingBreadth +inspired_by: ["synthetic compounding-constraint probe (not modeling any real language)"] +sources: + - "conformance/semantic-coverage-baseline.txt compounding todo entries" +requires: [] +words: + - word: ka + note: Bare head root, number=sg, class=a. + parses: + - signature: "KA|ka" + rules: [] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: tu + note: Bare non-head root, number=pl, class=a. + parses: + - signature: "TU|tu" + rules: [] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: katu + note: >- + The compound crJoin admits: singular class-a head, plural class-a non-head. All four + head/non-head required-feature elements are satisfied here. + parses: + - signature: "KA+TU|katu" + rules: [crJoin] + exercises: + - "CompoundingRule" + + - word: katumi + note: >- + THE distinguishing row for CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech: + KA+TU compounded (crJoin, outputPartOfSpeech="posOther") then attempting mrTplSuf ("-mi") -- + mrTplSuf requires posN, and crJoin's compound is posOther, a genuine CONFLICT, so mrTplSuf can + never apply to it. This is NOT a vacuous-absence trick (SynthesisCompoundingRule.cs seeds the + output's syntactic features from the HEAD's own required POS -- posN here -- before + outputPartOfSpeech's PriorityUnion overwrites it, so a compound's result is never actually + "unset"): removing crJoin's own outputPartOfSpeech (the writer) lets that seeded posN survive + unoverwritten, which is EXACTLY what mrTplSuf requires, so it applies. Removing mrTplSuf's own + requiredPartsOfSpeech (the reader) instead lets it apply regardless of part of speech. Either + severance reaches the identical successful parse independently. katu (above) is the control + showing the compound is otherwise well-formed without mrTplSuf. + expect_fail: true + blocked_by: [crJoin] + exercises: + - "CompoundingRule" + claimed_cells: + - cell: "PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm" + severing: >- + either crJoin's own CompoundingRule.outputPartOfSpeech="posOther" (the writer) or + mrTplSuf's own MorphologicalRule.requiredPartsOfSpeech="posN" gate (the reader) -- severing + either alone unblocks this word + before: "ok::-" + after: "ok::KA+TU+TPLSUF|katumi" + distinct_from: katu + proof: >- + katumi is KA+TU (crJoin's compound, tagged posOther) attempting mrTplSuf; with both + constructs intact the part-of-speech conflict (posOther vs. mrTplSuf's own required posN) + blocks it, so this has zero parses. Removing either the writer (crJoin's own + outputPartOfSpeech, so the compound's output keeps the head's own seeded posN instead of + being overwritten to posOther) or the reader (mrTplSuf's requiredPartsOfSpeech) lets the + rule apply anyway, producing KA+TU+TPLSUF|katumi -- the AbsentGatedForm arm: the required + part of speech is ABSENT (overwritten away, though never from KA's own declaration) and the + rule's requirement GATES on it. + + - word: kaki + note: Negative control for NonHeadRequiredHeadFeatures. "ki" is singular, not plural. + expect_fail: true + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: kati + note: Negative control for NonHeadRequiredFootFeatures. "ti" is class=b, not class=a. + expect_fail: true + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: kamtu + note: >- + Negative control for CompoundingRule@multipleApplication="0". crNever would join with an "m" at + the junction, and a rule capped at zero applications can never appear in a traced rule list, so + this failing word is its only possible evidence. + expect_fail: true + blocked_by: [crNever] + neutralizes: + - crNever + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: kaptu + note: Negative control for CompoundingRule@isActive="no". crDecoy would join with a "p". + expect_fail: true + blocked_by: [crDecoy] + neutralizes: + - crDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: kaitu + note: >- + Negative control for CompoundingSubrule@isActive="no". crJoinInsert's own (sole) subrule would + join with an "i"; inactive, it never contributes an analysis, so this surface form is refused. + expect_fail: true + neutralizes: + - CompoundingSubrule + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: kutu + note: >- + Negative control for HeadRequiredHeadFeatures. "ku" is number=pl, but crJoin (and crJoinInsert) + require a singular head, so no rule can use it as a head. + expect_fail: true + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: patu + note: >- + Negative control for HeadRequiredFootFeatures. "pa" is class=b, but crJoin (and crJoinInsert) + require a class=a head, so no rule can use it as a head. + expect_fail: true + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" diff --git a/conformance/edge-cases/deep-optional-affix-nesting/grammar.xml b/conformance/edge-cases/deep-optional-affix-nesting/grammar.xml new file mode 100644 index 000000000..b909b080e --- /dev/null +++ b/conformance/edge-cases/deep-optional-affix-nesting/grammar.xml @@ -0,0 +1,211 @@ + + + + + PathologicalDeepOptionalAffixNesting + + + v + + + Main + + x + k + + + + Any + + + + Main + + + p1 + + + + x + + + P1 + + + p2 + + + + x + + + P2 + + + p3 + + + + x + + + P3 + + + p4 + + + + x + + + P4 + + + p5 + + + + x + + + P5 + + + p6 + + + + x + + + P6 + + + p7 + + + + x + + + P7 + + + p8 + + + + x + + + P8 + + + p9 + + + + x + + + P9 + + + p10 + + + + x + + + P10 + + + p11 + + + + x + + + P11 + + + p12 + + + + x + + + P12 + + + + + deepOptionalTemplate + + slot1 + + + slot2 + + + slot3 + + + slot4 + + + slot5 + + + slot6 + + + slot7 + + + slot8 + + + slot9 + + + slot10 + + + slot11 + + + slot12 + + + + + + k + K + + + + + + diff --git a/conformance/edge-cases/deep-optional-affix-nesting/words.yaml b/conformance/edge-cases/deep-optional-affix-nesting/words.yaml new file mode 100644 index 000000000..53079403f --- /dev/null +++ b/conformance/edge-cases/deep-optional-affix-nesting/words.yaml @@ -0,0 +1,1924 @@ +# Converted from conformance/pathological/deep-optional-affix-nesting (v1, removed after the v1->v2 +# migration's parity proof). grammar.xml is the same file, unmodified: 12 independent, all-optional +# AffixTemplate prefix slots (P1..P12), each inserting +# the literal character "x" via InsertSegments+CopyFromInput, requiredPartsOfSpeech="posV" throughout, +# no PhonologicalRule/MetathesisRule element anywhere -- so RequiresDerivation mechanically derives +# requires: [] (this fixture is morphotactics-only, not phonology). +# +# What this pins (v1 manifest.json's provenance, carried forward verbatim below): per +# SynthesisAffixTemplateRule.ApplySlots, an all-optional slot chain explores the FULL powerset of +# "which slots fired" (2^12 = 4096 subsets) -- and because every slot inserts the identical character, +# any two subsets of the same size k produce byte-identical surface text but remain DISTINCT analyses +# (distinct MorphemeId chains, hence distinct signature strings). A word with k leading x's therefore +# has exactly C(12,k) equally-valid analyses. The three words below hit the two boundary cases (k=0, +# k=12, each exactly 1 analysis) and the combinatorial-blowup midpoint (k=6, C(12,6) = 924 analyses, +# oracle-confirmed) -- expected.tsv's own v1 ground truth for "xxxxxxk" is the full 924-entry +# semicolon-joined signature list, translated below into 924 individual `parses:` entries (one per +# distinct slot subset) rather than hand-derived from scratch, per the task's "expected parses come +# from the v1 expected.tsv (translate to signature form), verify against the oracle" instruction -- +# hand-deriving 924 combinatorial variants would be mechanical transcription of a well-understood +# combinatorial fact (which slots fired), not five hand-reasoned words, so this edge-case (unlike +# prefixal-discontinuous-slot-dependency) is generated from the checked-in oracle output and then self-check-verified, +# not authored blind. Every declared (signature, rules) pair below was verified against the live +# oracle by the self-check gate (RunAllWords) before this file was committed. +# +# budget_ms below (15000, copied verbatim from v1's manifest.json budget.wallClockMs) is why this +# fixture is EXCLUDED from a default self-check run (RunnerV2.RunOneSelfCheck: `isPathological = +# fixture.Words.BudgetMs.HasValue`, skipped unless --include-pathological) and only exercised with +# that flag -- same isolation discipline as v1's own pathological category. + +language: PathologicalDeepOptionalAffixNesting +inspired_by: ["synthetic pathological-complexity probe (not modeling any real language)"] +sources: + - "docs/conformance-framework-plan.md section 4.5 (pathological category); F3 worked example" +requires: [] +budget_ms: 15000 +words: + - word: "k" + note: >- + The zero-prefix boundary case: no optional slot fires (the "skip everything" path through + ApplySlots), giving exactly ONE analysis, C(12,0) = 1. Confirms the template's all-optional + chain still permits the bare root. + provenance: "F3 worked example (pathological category): 12 independent all-optional affix-template prefix slots inserting an identical literal character, producing C(12,k) equally-valid analyses for a k-x-prefixed word (924 for k=6, confirmed against the live oracle: 3 words, ~2.0s total wall-clock on this branch's un-optimized plain-master engine)" + parses: + - signature: "K|k" + rules: [] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: "xxxxxxk" + note: >- + The combinatorial-blowup case: 6 leading x's admit C(12,6) = 924 distinct subsets of the 12 + slots that could have produced them (confirmed exactly against the live oracle: 924 + semicolon-joined entries in v1's own expected.tsv signature column for this row, translated + 1:1 into the 924 `parses:` entries below). Every one of the 924 analyses is equally + linguistically valid under this grammar -- there is no mechanism here to prefer one subset + over another, so a conforming engine MUST enumerate all of them. This is the fixture's actual + pathological content: not a crash or a hang, but a combinatorially large, fully tractable, + exactly-specified analysis SET that any conforming engine must reproduce in full within the + budget_ms wall-clock budget. + provenance: "F3 worked example (pathological category): 12 independent all-optional affix-template prefix slots inserting an identical literal character, producing C(12,k) equally-valid analyses for a k-x-prefixed word (924 for k=6, confirmed against the live oracle: 3 words, ~2.0s total wall-clock on this branch's un-optimized plain-master engine)" + parses: + - signature: "P10+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P10+P6+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP6, mrP4, mrP3, mrP2, mrP1] + - signature: "P10+P6+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP6, mrP5, mrP3, mrP2, mrP1] + - signature: "P10+P6+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP6, mrP5, mrP4, mrP2, mrP1] + - signature: "P10+P6+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP6, mrP5, mrP4, mrP3, mrP1] + - signature: "P10+P6+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP6, mrP5, mrP4, mrP3, mrP2] + - signature: "P10+P7+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP4, mrP3, mrP2, mrP1] + - signature: "P10+P7+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP5, mrP3, mrP2, mrP1] + - signature: "P10+P7+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP5, mrP4, mrP2, mrP1] + - signature: "P10+P7+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP5, mrP4, mrP3, mrP1] + - signature: "P10+P7+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP7, mrP5, mrP4, mrP3, mrP2] + - signature: "P10+P7+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP3, mrP2, mrP1] + - signature: "P10+P7+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP4, mrP2, mrP1] + - signature: "P10+P7+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP4, mrP3, mrP1] + - signature: "P10+P7+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP4, mrP3, mrP2] + - signature: "P10+P7+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP5, mrP2, mrP1] + - signature: "P10+P7+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP5, mrP3, mrP1] + - signature: "P10+P7+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP5, mrP3, mrP2] + - signature: "P10+P7+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP5, mrP4, mrP1] + - signature: "P10+P7+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP5, mrP4, mrP2] + - signature: "P10+P7+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP7, mrP6, mrP5, mrP4, mrP3] + - signature: "P10+P8+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP4, mrP3, mrP2, mrP1] + - signature: "P10+P8+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP5, mrP3, mrP2, mrP1] + - signature: "P10+P8+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP5, mrP4, mrP2, mrP1] + - signature: "P10+P8+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP5, mrP4, mrP3, mrP1] + - signature: "P10+P8+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP5, mrP4, mrP3, mrP2] + - signature: "P10+P8+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP3, mrP2, mrP1] + - signature: "P10+P8+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP4, mrP2, mrP1] + - signature: "P10+P8+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP4, mrP3, mrP1] + - signature: "P10+P8+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP4, mrP3, mrP2] + - signature: "P10+P8+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP5, mrP2, mrP1] + - signature: "P10+P8+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP5, mrP3, mrP1] + - signature: "P10+P8+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP5, mrP3, mrP2] + - signature: "P10+P8+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP5, mrP4, mrP1] + - signature: "P10+P8+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP5, mrP4, mrP2] + - signature: "P10+P8+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP8, mrP6, mrP5, mrP4, mrP3] + - signature: "P10+P8+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP3, mrP2, mrP1] + - signature: "P10+P8+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP4, mrP2, mrP1] + - signature: "P10+P8+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP4, mrP3, mrP1] + - signature: "P10+P8+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP4, mrP3, mrP2] + - signature: "P10+P8+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP5, mrP2, mrP1] + - signature: "P10+P8+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP5, mrP3, mrP1] + - signature: "P10+P8+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP5, mrP3, mrP2] + - signature: "P10+P8+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP5, mrP4, mrP1] + - signature: "P10+P8+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP5, mrP4, mrP2] + - signature: "P10+P8+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP5, mrP4, mrP3] + - signature: "P10+P8+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP2, mrP1] + - signature: "P10+P8+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP3, mrP1] + - signature: "P10+P8+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP3, mrP2] + - signature: "P10+P8+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP4, mrP1] + - signature: "P10+P8+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP4, mrP2] + - signature: "P10+P8+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP4, mrP3] + - signature: "P10+P8+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP5, mrP1] + - signature: "P10+P8+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP5, mrP2] + - signature: "P10+P8+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP5, mrP3] + - signature: "P10+P8+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP10, mrP8, mrP7, mrP6, mrP5, mrP4] + - signature: "P10+P9+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP4, mrP3, mrP2, mrP1] + - signature: "P10+P9+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP5, mrP3, mrP2, mrP1] + - signature: "P10+P9+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP5, mrP4, mrP2, mrP1] + - signature: "P10+P9+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP5, mrP4, mrP3, mrP1] + - signature: "P10+P9+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP5, mrP4, mrP3, mrP2] + - signature: "P10+P9+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP3, mrP2, mrP1] + - signature: "P10+P9+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP4, mrP2, mrP1] + - signature: "P10+P9+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP4, mrP3, mrP1] + - signature: "P10+P9+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP4, mrP3, mrP2] + - signature: "P10+P9+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP5, mrP2, mrP1] + - signature: "P10+P9+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP5, mrP3, mrP1] + - signature: "P10+P9+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP5, mrP3, mrP2] + - signature: "P10+P9+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP5, mrP4, mrP1] + - signature: "P10+P9+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP5, mrP4, mrP2] + - signature: "P10+P9+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP6, mrP5, mrP4, mrP3] + - signature: "P10+P9+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP3, mrP2, mrP1] + - signature: "P10+P9+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP4, mrP2, mrP1] + - signature: "P10+P9+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP4, mrP3, mrP1] + - signature: "P10+P9+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP4, mrP3, mrP2] + - signature: "P10+P9+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP5, mrP2, mrP1] + - signature: "P10+P9+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP5, mrP3, mrP1] + - signature: "P10+P9+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP5, mrP3, mrP2] + - signature: "P10+P9+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP5, mrP4, mrP1] + - signature: "P10+P9+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP5, mrP4, mrP2] + - signature: "P10+P9+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP5, mrP4, mrP3] + - signature: "P10+P9+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP2, mrP1] + - signature: "P10+P9+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP3, mrP1] + - signature: "P10+P9+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP3, mrP2] + - signature: "P10+P9+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP4, mrP1] + - signature: "P10+P9+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP4, mrP2] + - signature: "P10+P9+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP4, mrP3] + - signature: "P10+P9+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP5, mrP1] + - signature: "P10+P9+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP5, mrP2] + - signature: "P10+P9+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP5, mrP3] + - signature: "P10+P9+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP10, mrP9, mrP7, mrP6, mrP5, mrP4] + - signature: "P10+P9+P8+P3+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP3, mrP2, mrP1] + - signature: "P10+P9+P8+P4+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP4, mrP2, mrP1] + - signature: "P10+P9+P8+P4+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP4, mrP3, mrP1] + - signature: "P10+P9+P8+P4+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP4, mrP3, mrP2] + - signature: "P10+P9+P8+P5+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP5, mrP2, mrP1] + - signature: "P10+P9+P8+P5+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP5, mrP3, mrP1] + - signature: "P10+P9+P8+P5+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP5, mrP3, mrP2] + - signature: "P10+P9+P8+P5+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP5, mrP4, mrP1] + - signature: "P10+P9+P8+P5+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP5, mrP4, mrP2] + - signature: "P10+P9+P8+P5+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP5, mrP4, mrP3] + - signature: "P10+P9+P8+P6+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP2, mrP1] + - signature: "P10+P9+P8+P6+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP3, mrP1] + - signature: "P10+P9+P8+P6+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP3, mrP2] + - signature: "P10+P9+P8+P6+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP4, mrP1] + - signature: "P10+P9+P8+P6+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP4, mrP2] + - signature: "P10+P9+P8+P6+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP4, mrP3] + - signature: "P10+P9+P8+P6+P5+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP5, mrP1] + - signature: "P10+P9+P8+P6+P5+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP5, mrP2] + - signature: "P10+P9+P8+P6+P5+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP5, mrP3] + - signature: "P10+P9+P8+P6+P5+P4+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP6, mrP5, mrP4] + - signature: "P10+P9+P8+P7+P2+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP2, mrP1] + - signature: "P10+P9+P8+P7+P3+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP3, mrP1] + - signature: "P10+P9+P8+P7+P3+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP3, mrP2] + - signature: "P10+P9+P8+P7+P4+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP4, mrP1] + - signature: "P10+P9+P8+P7+P4+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP4, mrP2] + - signature: "P10+P9+P8+P7+P4+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP4, mrP3] + - signature: "P10+P9+P8+P7+P5+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP5, mrP1] + - signature: "P10+P9+P8+P7+P5+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP5, mrP2] + - signature: "P10+P9+P8+P7+P5+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP5, mrP3] + - signature: "P10+P9+P8+P7+P5+P4+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP5, mrP4] + - signature: "P10+P9+P8+P7+P6+P1+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP6, mrP1] + - signature: "P10+P9+P8+P7+P6+P2+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP6, mrP2] + - signature: "P10+P9+P8+P7+P6+P3+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP6, mrP3] + - signature: "P10+P9+P8+P7+P6+P4+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP6, mrP4] + - signature: "P10+P9+P8+P7+P6+P5+K|xxxxxxk" + rules: [mrP10, mrP9, mrP8, mrP7, mrP6, mrP5] + - signature: "P11+P10+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP4, mrP3, mrP2, mrP1] + - signature: "P11+P10+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP5, mrP3, mrP2, mrP1] + - signature: "P11+P10+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP5, mrP4, mrP2, mrP1] + - signature: "P11+P10+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP5, mrP4, mrP3, mrP1] + - signature: "P11+P10+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP5, mrP4, mrP3, mrP2] + - signature: "P11+P10+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP3, mrP2, mrP1] + - signature: "P11+P10+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP4, mrP2, mrP1] + - signature: "P11+P10+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP4, mrP3, mrP1] + - signature: "P11+P10+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP4, mrP3, mrP2] + - signature: "P11+P10+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP5, mrP2, mrP1] + - signature: "P11+P10+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP5, mrP3, mrP1] + - signature: "P11+P10+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP5, mrP3, mrP2] + - signature: "P11+P10+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP5, mrP4, mrP1] + - signature: "P11+P10+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP5, mrP4, mrP2] + - signature: "P11+P10+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP6, mrP5, mrP4, mrP3] + - signature: "P11+P10+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP3, mrP2, mrP1] + - signature: "P11+P10+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP4, mrP2, mrP1] + - signature: "P11+P10+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP4, mrP3, mrP1] + - signature: "P11+P10+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP4, mrP3, mrP2] + - signature: "P11+P10+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP5, mrP2, mrP1] + - signature: "P11+P10+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP5, mrP3, mrP1] + - signature: "P11+P10+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP5, mrP3, mrP2] + - signature: "P11+P10+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP5, mrP4, mrP1] + - signature: "P11+P10+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP5, mrP4, mrP2] + - signature: "P11+P10+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP5, mrP4, mrP3] + - signature: "P11+P10+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP2, mrP1] + - signature: "P11+P10+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP3, mrP1] + - signature: "P11+P10+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP3, mrP2] + - signature: "P11+P10+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP4, mrP1] + - signature: "P11+P10+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP4, mrP2] + - signature: "P11+P10+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP4, mrP3] + - signature: "P11+P10+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP5, mrP1] + - signature: "P11+P10+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP5, mrP2] + - signature: "P11+P10+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP5, mrP3] + - signature: "P11+P10+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP7, mrP6, mrP5, mrP4] + - signature: "P11+P10+P8+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP3, mrP2, mrP1] + - signature: "P11+P10+P8+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP4, mrP2, mrP1] + - signature: "P11+P10+P8+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP4, mrP3, mrP1] + - signature: "P11+P10+P8+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP4, mrP3, mrP2] + - signature: "P11+P10+P8+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP5, mrP2, mrP1] + - signature: "P11+P10+P8+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP5, mrP3, mrP1] + - signature: "P11+P10+P8+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP5, mrP3, mrP2] + - signature: "P11+P10+P8+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP5, mrP4, mrP1] + - signature: "P11+P10+P8+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP5, mrP4, mrP2] + - signature: "P11+P10+P8+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP5, mrP4, mrP3] + - signature: "P11+P10+P8+P6+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP2, mrP1] + - signature: "P11+P10+P8+P6+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP3, mrP1] + - signature: "P11+P10+P8+P6+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP3, mrP2] + - signature: "P11+P10+P8+P6+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP4, mrP1] + - signature: "P11+P10+P8+P6+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP4, mrP2] + - signature: "P11+P10+P8+P6+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP4, mrP3] + - signature: "P11+P10+P8+P6+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP5, mrP1] + - signature: "P11+P10+P8+P6+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP5, mrP2] + - signature: "P11+P10+P8+P6+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP5, mrP3] + - signature: "P11+P10+P8+P6+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP6, mrP5, mrP4] + - signature: "P11+P10+P8+P7+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP2, mrP1] + - signature: "P11+P10+P8+P7+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP3, mrP1] + - signature: "P11+P10+P8+P7+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP3, mrP2] + - signature: "P11+P10+P8+P7+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP4, mrP1] + - signature: "P11+P10+P8+P7+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP4, mrP2] + - signature: "P11+P10+P8+P7+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP4, mrP3] + - signature: "P11+P10+P8+P7+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP5, mrP1] + - signature: "P11+P10+P8+P7+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP5, mrP2] + - signature: "P11+P10+P8+P7+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP5, mrP3] + - signature: "P11+P10+P8+P7+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP5, mrP4] + - signature: "P11+P10+P8+P7+P6+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP6, mrP1] + - signature: "P11+P10+P8+P7+P6+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP6, mrP2] + - signature: "P11+P10+P8+P7+P6+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP6, mrP3] + - signature: "P11+P10+P8+P7+P6+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP6, mrP4] + - signature: "P11+P10+P8+P7+P6+P5+K|xxxxxxk" + rules: [mrP11, mrP10, mrP8, mrP7, mrP6, mrP5] + - signature: "P11+P10+P9+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP3, mrP2, mrP1] + - signature: "P11+P10+P9+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP4, mrP2, mrP1] + - signature: "P11+P10+P9+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP4, mrP3, mrP1] + - signature: "P11+P10+P9+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP4, mrP3, mrP2] + - signature: "P11+P10+P9+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP5, mrP2, mrP1] + - signature: "P11+P10+P9+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP5, mrP3, mrP1] + - signature: "P11+P10+P9+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP5, mrP3, mrP2] + - signature: "P11+P10+P9+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP5, mrP4, mrP1] + - signature: "P11+P10+P9+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP5, mrP4, mrP2] + - signature: "P11+P10+P9+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP5, mrP4, mrP3] + - signature: "P11+P10+P9+P6+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP2, mrP1] + - signature: "P11+P10+P9+P6+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP3, mrP1] + - signature: "P11+P10+P9+P6+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP3, mrP2] + - signature: "P11+P10+P9+P6+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP4, mrP1] + - signature: "P11+P10+P9+P6+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP4, mrP2] + - signature: "P11+P10+P9+P6+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP4, mrP3] + - signature: "P11+P10+P9+P6+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP5, mrP1] + - signature: "P11+P10+P9+P6+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP5, mrP2] + - signature: "P11+P10+P9+P6+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP5, mrP3] + - signature: "P11+P10+P9+P6+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP6, mrP5, mrP4] + - signature: "P11+P10+P9+P7+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP2, mrP1] + - signature: "P11+P10+P9+P7+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP3, mrP1] + - signature: "P11+P10+P9+P7+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP3, mrP2] + - signature: "P11+P10+P9+P7+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP4, mrP1] + - signature: "P11+P10+P9+P7+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP4, mrP2] + - signature: "P11+P10+P9+P7+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP4, mrP3] + - signature: "P11+P10+P9+P7+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP5, mrP1] + - signature: "P11+P10+P9+P7+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP5, mrP2] + - signature: "P11+P10+P9+P7+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP5, mrP3] + - signature: "P11+P10+P9+P7+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP5, mrP4] + - signature: "P11+P10+P9+P7+P6+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP6, mrP1] + - signature: "P11+P10+P9+P7+P6+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP6, mrP2] + - signature: "P11+P10+P9+P7+P6+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP6, mrP3] + - signature: "P11+P10+P9+P7+P6+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP6, mrP4] + - signature: "P11+P10+P9+P7+P6+P5+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP7, mrP6, mrP5] + - signature: "P11+P10+P9+P8+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP2, mrP1] + - signature: "P11+P10+P9+P8+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP3, mrP1] + - signature: "P11+P10+P9+P8+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP3, mrP2] + - signature: "P11+P10+P9+P8+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP4, mrP1] + - signature: "P11+P10+P9+P8+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP4, mrP2] + - signature: "P11+P10+P9+P8+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP4, mrP3] + - signature: "P11+P10+P9+P8+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP5, mrP1] + - signature: "P11+P10+P9+P8+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP5, mrP2] + - signature: "P11+P10+P9+P8+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP5, mrP3] + - signature: "P11+P10+P9+P8+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP5, mrP4] + - signature: "P11+P10+P9+P8+P6+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP6, mrP1] + - signature: "P11+P10+P9+P8+P6+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP6, mrP2] + - signature: "P11+P10+P9+P8+P6+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP6, mrP3] + - signature: "P11+P10+P9+P8+P6+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP6, mrP4] + - signature: "P11+P10+P9+P8+P6+P5+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP6, mrP5] + - signature: "P11+P10+P9+P8+P7+P1+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP7, mrP1] + - signature: "P11+P10+P9+P8+P7+P2+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP7, mrP2] + - signature: "P11+P10+P9+P8+P7+P3+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP7, mrP3] + - signature: "P11+P10+P9+P8+P7+P4+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP7, mrP4] + - signature: "P11+P10+P9+P8+P7+P5+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP7, mrP5] + - signature: "P11+P10+P9+P8+P7+P6+K|xxxxxxk" + rules: [mrP11, mrP10, mrP9, mrP8, mrP7, mrP6] + - signature: "P11+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P11+P6+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP6, mrP4, mrP3, mrP2, mrP1] + - signature: "P11+P6+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP6, mrP5, mrP3, mrP2, mrP1] + - signature: "P11+P6+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP6, mrP5, mrP4, mrP2, mrP1] + - signature: "P11+P6+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP6, mrP5, mrP4, mrP3, mrP1] + - signature: "P11+P6+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP6, mrP5, mrP4, mrP3, mrP2] + - signature: "P11+P7+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP4, mrP3, mrP2, mrP1] + - signature: "P11+P7+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP5, mrP3, mrP2, mrP1] + - signature: "P11+P7+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP5, mrP4, mrP2, mrP1] + - signature: "P11+P7+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP5, mrP4, mrP3, mrP1] + - signature: "P11+P7+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP7, mrP5, mrP4, mrP3, mrP2] + - signature: "P11+P7+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP3, mrP2, mrP1] + - signature: "P11+P7+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP4, mrP2, mrP1] + - signature: "P11+P7+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP4, mrP3, mrP1] + - signature: "P11+P7+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP4, mrP3, mrP2] + - signature: "P11+P7+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP5, mrP2, mrP1] + - signature: "P11+P7+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP5, mrP3, mrP1] + - signature: "P11+P7+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP5, mrP3, mrP2] + - signature: "P11+P7+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP5, mrP4, mrP1] + - signature: "P11+P7+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP5, mrP4, mrP2] + - signature: "P11+P7+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP7, mrP6, mrP5, mrP4, mrP3] + - signature: "P11+P8+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP4, mrP3, mrP2, mrP1] + - signature: "P11+P8+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP5, mrP3, mrP2, mrP1] + - signature: "P11+P8+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP5, mrP4, mrP2, mrP1] + - signature: "P11+P8+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP5, mrP4, mrP3, mrP1] + - signature: "P11+P8+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP5, mrP4, mrP3, mrP2] + - signature: "P11+P8+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP3, mrP2, mrP1] + - signature: "P11+P8+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP4, mrP2, mrP1] + - signature: "P11+P8+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP4, mrP3, mrP1] + - signature: "P11+P8+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP4, mrP3, mrP2] + - signature: "P11+P8+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP5, mrP2, mrP1] + - signature: "P11+P8+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP5, mrP3, mrP1] + - signature: "P11+P8+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP5, mrP3, mrP2] + - signature: "P11+P8+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP5, mrP4, mrP1] + - signature: "P11+P8+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP5, mrP4, mrP2] + - signature: "P11+P8+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP8, mrP6, mrP5, mrP4, mrP3] + - signature: "P11+P8+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP3, mrP2, mrP1] + - signature: "P11+P8+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP4, mrP2, mrP1] + - signature: "P11+P8+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP4, mrP3, mrP1] + - signature: "P11+P8+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP4, mrP3, mrP2] + - signature: "P11+P8+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP5, mrP2, mrP1] + - signature: "P11+P8+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP5, mrP3, mrP1] + - signature: "P11+P8+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP5, mrP3, mrP2] + - signature: "P11+P8+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP5, mrP4, mrP1] + - signature: "P11+P8+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP5, mrP4, mrP2] + - signature: "P11+P8+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP5, mrP4, mrP3] + - signature: "P11+P8+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP2, mrP1] + - signature: "P11+P8+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP3, mrP1] + - signature: "P11+P8+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP3, mrP2] + - signature: "P11+P8+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP4, mrP1] + - signature: "P11+P8+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP4, mrP2] + - signature: "P11+P8+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP4, mrP3] + - signature: "P11+P8+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP5, mrP1] + - signature: "P11+P8+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP5, mrP2] + - signature: "P11+P8+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP5, mrP3] + - signature: "P11+P8+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP8, mrP7, mrP6, mrP5, mrP4] + - signature: "P11+P9+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP4, mrP3, mrP2, mrP1] + - signature: "P11+P9+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP5, mrP3, mrP2, mrP1] + - signature: "P11+P9+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP5, mrP4, mrP2, mrP1] + - signature: "P11+P9+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP5, mrP4, mrP3, mrP1] + - signature: "P11+P9+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP5, mrP4, mrP3, mrP2] + - signature: "P11+P9+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP3, mrP2, mrP1] + - signature: "P11+P9+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP4, mrP2, mrP1] + - signature: "P11+P9+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP4, mrP3, mrP1] + - signature: "P11+P9+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP4, mrP3, mrP2] + - signature: "P11+P9+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP5, mrP2, mrP1] + - signature: "P11+P9+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP5, mrP3, mrP1] + - signature: "P11+P9+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP5, mrP3, mrP2] + - signature: "P11+P9+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP5, mrP4, mrP1] + - signature: "P11+P9+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP5, mrP4, mrP2] + - signature: "P11+P9+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP6, mrP5, mrP4, mrP3] + - signature: "P11+P9+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP3, mrP2, mrP1] + - signature: "P11+P9+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP4, mrP2, mrP1] + - signature: "P11+P9+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP4, mrP3, mrP1] + - signature: "P11+P9+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP4, mrP3, mrP2] + - signature: "P11+P9+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP5, mrP2, mrP1] + - signature: "P11+P9+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP5, mrP3, mrP1] + - signature: "P11+P9+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP5, mrP3, mrP2] + - signature: "P11+P9+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP5, mrP4, mrP1] + - signature: "P11+P9+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP5, mrP4, mrP2] + - signature: "P11+P9+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP5, mrP4, mrP3] + - signature: "P11+P9+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP2, mrP1] + - signature: "P11+P9+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP3, mrP1] + - signature: "P11+P9+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP3, mrP2] + - signature: "P11+P9+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP4, mrP1] + - signature: "P11+P9+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP4, mrP2] + - signature: "P11+P9+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP4, mrP3] + - signature: "P11+P9+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP5, mrP1] + - signature: "P11+P9+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP5, mrP2] + - signature: "P11+P9+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP5, mrP3] + - signature: "P11+P9+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP9, mrP7, mrP6, mrP5, mrP4] + - signature: "P11+P9+P8+P3+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP3, mrP2, mrP1] + - signature: "P11+P9+P8+P4+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP4, mrP2, mrP1] + - signature: "P11+P9+P8+P4+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP4, mrP3, mrP1] + - signature: "P11+P9+P8+P4+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP4, mrP3, mrP2] + - signature: "P11+P9+P8+P5+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP5, mrP2, mrP1] + - signature: "P11+P9+P8+P5+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP5, mrP3, mrP1] + - signature: "P11+P9+P8+P5+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP5, mrP3, mrP2] + - signature: "P11+P9+P8+P5+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP5, mrP4, mrP1] + - signature: "P11+P9+P8+P5+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP5, mrP4, mrP2] + - signature: "P11+P9+P8+P5+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP5, mrP4, mrP3] + - signature: "P11+P9+P8+P6+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP2, mrP1] + - signature: "P11+P9+P8+P6+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP3, mrP1] + - signature: "P11+P9+P8+P6+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP3, mrP2] + - signature: "P11+P9+P8+P6+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP4, mrP1] + - signature: "P11+P9+P8+P6+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP4, mrP2] + - signature: "P11+P9+P8+P6+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP4, mrP3] + - signature: "P11+P9+P8+P6+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP5, mrP1] + - signature: "P11+P9+P8+P6+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP5, mrP2] + - signature: "P11+P9+P8+P6+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP5, mrP3] + - signature: "P11+P9+P8+P6+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP6, mrP5, mrP4] + - signature: "P11+P9+P8+P7+P2+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP2, mrP1] + - signature: "P11+P9+P8+P7+P3+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP3, mrP1] + - signature: "P11+P9+P8+P7+P3+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP3, mrP2] + - signature: "P11+P9+P8+P7+P4+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP4, mrP1] + - signature: "P11+P9+P8+P7+P4+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP4, mrP2] + - signature: "P11+P9+P8+P7+P4+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP4, mrP3] + - signature: "P11+P9+P8+P7+P5+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP5, mrP1] + - signature: "P11+P9+P8+P7+P5+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP5, mrP2] + - signature: "P11+P9+P8+P7+P5+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP5, mrP3] + - signature: "P11+P9+P8+P7+P5+P4+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP5, mrP4] + - signature: "P11+P9+P8+P7+P6+P1+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP6, mrP1] + - signature: "P11+P9+P8+P7+P6+P2+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP6, mrP2] + - signature: "P11+P9+P8+P7+P6+P3+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP6, mrP3] + - signature: "P11+P9+P8+P7+P6+P4+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP6, mrP4] + - signature: "P11+P9+P8+P7+P6+P5+K|xxxxxxk" + rules: [mrP11, mrP9, mrP8, mrP7, mrP6, mrP5] + - signature: "P12+P10+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P10+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP5, mrP3, mrP2, mrP1] + - signature: "P12+P10+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP5, mrP4, mrP2, mrP1] + - signature: "P12+P10+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP5, mrP4, mrP3, mrP1] + - signature: "P12+P10+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP5, mrP4, mrP3, mrP2] + - signature: "P12+P10+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP3, mrP2, mrP1] + - signature: "P12+P10+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP4, mrP2, mrP1] + - signature: "P12+P10+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP4, mrP3, mrP1] + - signature: "P12+P10+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP4, mrP3, mrP2] + - signature: "P12+P10+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP5, mrP2, mrP1] + - signature: "P12+P10+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP5, mrP3, mrP1] + - signature: "P12+P10+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP5, mrP3, mrP2] + - signature: "P12+P10+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP5, mrP4, mrP1] + - signature: "P12+P10+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP5, mrP4, mrP2] + - signature: "P12+P10+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP6, mrP5, mrP4, mrP3] + - signature: "P12+P10+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP3, mrP2, mrP1] + - signature: "P12+P10+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP4, mrP2, mrP1] + - signature: "P12+P10+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP4, mrP3, mrP1] + - signature: "P12+P10+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP4, mrP3, mrP2] + - signature: "P12+P10+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP5, mrP2, mrP1] + - signature: "P12+P10+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP5, mrP3, mrP1] + - signature: "P12+P10+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP5, mrP3, mrP2] + - signature: "P12+P10+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP5, mrP4, mrP1] + - signature: "P12+P10+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP5, mrP4, mrP2] + - signature: "P12+P10+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP5, mrP4, mrP3] + - signature: "P12+P10+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP2, mrP1] + - signature: "P12+P10+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP3, mrP1] + - signature: "P12+P10+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP3, mrP2] + - signature: "P12+P10+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP4, mrP1] + - signature: "P12+P10+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP4, mrP2] + - signature: "P12+P10+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP4, mrP3] + - signature: "P12+P10+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP5, mrP1] + - signature: "P12+P10+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP5, mrP2] + - signature: "P12+P10+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP5, mrP3] + - signature: "P12+P10+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP7, mrP6, mrP5, mrP4] + - signature: "P12+P10+P8+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP3, mrP2, mrP1] + - signature: "P12+P10+P8+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP4, mrP2, mrP1] + - signature: "P12+P10+P8+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP4, mrP3, mrP1] + - signature: "P12+P10+P8+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP4, mrP3, mrP2] + - signature: "P12+P10+P8+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP5, mrP2, mrP1] + - signature: "P12+P10+P8+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP5, mrP3, mrP1] + - signature: "P12+P10+P8+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP5, mrP3, mrP2] + - signature: "P12+P10+P8+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP5, mrP4, mrP1] + - signature: "P12+P10+P8+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP5, mrP4, mrP2] + - signature: "P12+P10+P8+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP5, mrP4, mrP3] + - signature: "P12+P10+P8+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP2, mrP1] + - signature: "P12+P10+P8+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP3, mrP1] + - signature: "P12+P10+P8+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP3, mrP2] + - signature: "P12+P10+P8+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP4, mrP1] + - signature: "P12+P10+P8+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP4, mrP2] + - signature: "P12+P10+P8+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP4, mrP3] + - signature: "P12+P10+P8+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP5, mrP1] + - signature: "P12+P10+P8+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP5, mrP2] + - signature: "P12+P10+P8+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP5, mrP3] + - signature: "P12+P10+P8+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP6, mrP5, mrP4] + - signature: "P12+P10+P8+P7+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP2, mrP1] + - signature: "P12+P10+P8+P7+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP3, mrP1] + - signature: "P12+P10+P8+P7+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP3, mrP2] + - signature: "P12+P10+P8+P7+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP4, mrP1] + - signature: "P12+P10+P8+P7+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP4, mrP2] + - signature: "P12+P10+P8+P7+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP4, mrP3] + - signature: "P12+P10+P8+P7+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP5, mrP1] + - signature: "P12+P10+P8+P7+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP5, mrP2] + - signature: "P12+P10+P8+P7+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP5, mrP3] + - signature: "P12+P10+P8+P7+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP5, mrP4] + - signature: "P12+P10+P8+P7+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP6, mrP1] + - signature: "P12+P10+P8+P7+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP6, mrP2] + - signature: "P12+P10+P8+P7+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP6, mrP3] + - signature: "P12+P10+P8+P7+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP6, mrP4] + - signature: "P12+P10+P8+P7+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP10, mrP8, mrP7, mrP6, mrP5] + - signature: "P12+P10+P9+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP3, mrP2, mrP1] + - signature: "P12+P10+P9+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP4, mrP2, mrP1] + - signature: "P12+P10+P9+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP4, mrP3, mrP1] + - signature: "P12+P10+P9+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP4, mrP3, mrP2] + - signature: "P12+P10+P9+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP5, mrP2, mrP1] + - signature: "P12+P10+P9+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP5, mrP3, mrP1] + - signature: "P12+P10+P9+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP5, mrP3, mrP2] + - signature: "P12+P10+P9+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP5, mrP4, mrP1] + - signature: "P12+P10+P9+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP5, mrP4, mrP2] + - signature: "P12+P10+P9+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP5, mrP4, mrP3] + - signature: "P12+P10+P9+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP2, mrP1] + - signature: "P12+P10+P9+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP3, mrP1] + - signature: "P12+P10+P9+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP3, mrP2] + - signature: "P12+P10+P9+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP4, mrP1] + - signature: "P12+P10+P9+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP4, mrP2] + - signature: "P12+P10+P9+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP4, mrP3] + - signature: "P12+P10+P9+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP5, mrP1] + - signature: "P12+P10+P9+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP5, mrP2] + - signature: "P12+P10+P9+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP5, mrP3] + - signature: "P12+P10+P9+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP6, mrP5, mrP4] + - signature: "P12+P10+P9+P7+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP2, mrP1] + - signature: "P12+P10+P9+P7+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP3, mrP1] + - signature: "P12+P10+P9+P7+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP3, mrP2] + - signature: "P12+P10+P9+P7+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP4, mrP1] + - signature: "P12+P10+P9+P7+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP4, mrP2] + - signature: "P12+P10+P9+P7+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP4, mrP3] + - signature: "P12+P10+P9+P7+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP5, mrP1] + - signature: "P12+P10+P9+P7+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP5, mrP2] + - signature: "P12+P10+P9+P7+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP5, mrP3] + - signature: "P12+P10+P9+P7+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP5, mrP4] + - signature: "P12+P10+P9+P7+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP6, mrP1] + - signature: "P12+P10+P9+P7+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP6, mrP2] + - signature: "P12+P10+P9+P7+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP6, mrP3] + - signature: "P12+P10+P9+P7+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP6, mrP4] + - signature: "P12+P10+P9+P7+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP7, mrP6, mrP5] + - signature: "P12+P10+P9+P8+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP2, mrP1] + - signature: "P12+P10+P9+P8+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP3, mrP1] + - signature: "P12+P10+P9+P8+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP3, mrP2] + - signature: "P12+P10+P9+P8+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP4, mrP1] + - signature: "P12+P10+P9+P8+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP4, mrP2] + - signature: "P12+P10+P9+P8+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP4, mrP3] + - signature: "P12+P10+P9+P8+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP5, mrP1] + - signature: "P12+P10+P9+P8+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP5, mrP2] + - signature: "P12+P10+P9+P8+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP5, mrP3] + - signature: "P12+P10+P9+P8+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP5, mrP4] + - signature: "P12+P10+P9+P8+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP6, mrP1] + - signature: "P12+P10+P9+P8+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP6, mrP2] + - signature: "P12+P10+P9+P8+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP6, mrP3] + - signature: "P12+P10+P9+P8+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP6, mrP4] + - signature: "P12+P10+P9+P8+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP6, mrP5] + - signature: "P12+P10+P9+P8+P7+P1+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP7, mrP1] + - signature: "P12+P10+P9+P8+P7+P2+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP7, mrP2] + - signature: "P12+P10+P9+P8+P7+P3+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP7, mrP3] + - signature: "P12+P10+P9+P8+P7+P4+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP7, mrP4] + - signature: "P12+P10+P9+P8+P7+P5+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP7, mrP5] + - signature: "P12+P10+P9+P8+P7+P6+K|xxxxxxk" + rules: [mrP12, mrP10, mrP9, mrP8, mrP7, mrP6] + - signature: "P12+P11+P10+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP3, mrP2, mrP1] + - signature: "P12+P11+P10+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP4, mrP2, mrP1] + - signature: "P12+P11+P10+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP4, mrP3, mrP1] + - signature: "P12+P11+P10+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP4, mrP3, mrP2] + - signature: "P12+P11+P10+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP5, mrP2, mrP1] + - signature: "P12+P11+P10+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP5, mrP3, mrP1] + - signature: "P12+P11+P10+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP5, mrP3, mrP2] + - signature: "P12+P11+P10+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP5, mrP4, mrP1] + - signature: "P12+P11+P10+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP5, mrP4, mrP2] + - signature: "P12+P11+P10+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP5, mrP4, mrP3] + - signature: "P12+P11+P10+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP2, mrP1] + - signature: "P12+P11+P10+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP3, mrP1] + - signature: "P12+P11+P10+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP3, mrP2] + - signature: "P12+P11+P10+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP4, mrP1] + - signature: "P12+P11+P10+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP4, mrP2] + - signature: "P12+P11+P10+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP4, mrP3] + - signature: "P12+P11+P10+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP5, mrP1] + - signature: "P12+P11+P10+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP5, mrP2] + - signature: "P12+P11+P10+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP5, mrP3] + - signature: "P12+P11+P10+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP6, mrP5, mrP4] + - signature: "P12+P11+P10+P7+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP2, mrP1] + - signature: "P12+P11+P10+P7+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP3, mrP1] + - signature: "P12+P11+P10+P7+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP3, mrP2] + - signature: "P12+P11+P10+P7+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP4, mrP1] + - signature: "P12+P11+P10+P7+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP4, mrP2] + - signature: "P12+P11+P10+P7+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP4, mrP3] + - signature: "P12+P11+P10+P7+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP5, mrP1] + - signature: "P12+P11+P10+P7+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP5, mrP2] + - signature: "P12+P11+P10+P7+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP5, mrP3] + - signature: "P12+P11+P10+P7+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP5, mrP4] + - signature: "P12+P11+P10+P7+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP6, mrP1] + - signature: "P12+P11+P10+P7+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP6, mrP2] + - signature: "P12+P11+P10+P7+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP6, mrP3] + - signature: "P12+P11+P10+P7+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP6, mrP4] + - signature: "P12+P11+P10+P7+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP7, mrP6, mrP5] + - signature: "P12+P11+P10+P8+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP2, mrP1] + - signature: "P12+P11+P10+P8+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP3, mrP1] + - signature: "P12+P11+P10+P8+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP3, mrP2] + - signature: "P12+P11+P10+P8+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP4, mrP1] + - signature: "P12+P11+P10+P8+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP4, mrP2] + - signature: "P12+P11+P10+P8+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP4, mrP3] + - signature: "P12+P11+P10+P8+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP5, mrP1] + - signature: "P12+P11+P10+P8+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP5, mrP2] + - signature: "P12+P11+P10+P8+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP5, mrP3] + - signature: "P12+P11+P10+P8+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP5, mrP4] + - signature: "P12+P11+P10+P8+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP6, mrP1] + - signature: "P12+P11+P10+P8+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP6, mrP2] + - signature: "P12+P11+P10+P8+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP6, mrP3] + - signature: "P12+P11+P10+P8+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP6, mrP4] + - signature: "P12+P11+P10+P8+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP6, mrP5] + - signature: "P12+P11+P10+P8+P7+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP7, mrP1] + - signature: "P12+P11+P10+P8+P7+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP7, mrP2] + - signature: "P12+P11+P10+P8+P7+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP7, mrP3] + - signature: "P12+P11+P10+P8+P7+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP7, mrP4] + - signature: "P12+P11+P10+P8+P7+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP7, mrP5] + - signature: "P12+P11+P10+P8+P7+P6+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP8, mrP7, mrP6] + - signature: "P12+P11+P10+P9+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP2, mrP1] + - signature: "P12+P11+P10+P9+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP3, mrP1] + - signature: "P12+P11+P10+P9+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP3, mrP2] + - signature: "P12+P11+P10+P9+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP4, mrP1] + - signature: "P12+P11+P10+P9+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP4, mrP2] + - signature: "P12+P11+P10+P9+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP4, mrP3] + - signature: "P12+P11+P10+P9+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP5, mrP1] + - signature: "P12+P11+P10+P9+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP5, mrP2] + - signature: "P12+P11+P10+P9+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP5, mrP3] + - signature: "P12+P11+P10+P9+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP5, mrP4] + - signature: "P12+P11+P10+P9+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP6, mrP1] + - signature: "P12+P11+P10+P9+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP6, mrP2] + - signature: "P12+P11+P10+P9+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP6, mrP3] + - signature: "P12+P11+P10+P9+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP6, mrP4] + - signature: "P12+P11+P10+P9+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP6, mrP5] + - signature: "P12+P11+P10+P9+P7+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP7, mrP1] + - signature: "P12+P11+P10+P9+P7+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP7, mrP2] + - signature: "P12+P11+P10+P9+P7+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP7, mrP3] + - signature: "P12+P11+P10+P9+P7+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP7, mrP4] + - signature: "P12+P11+P10+P9+P7+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP7, mrP5] + - signature: "P12+P11+P10+P9+P7+P6+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP7, mrP6] + - signature: "P12+P11+P10+P9+P8+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP1] + - signature: "P12+P11+P10+P9+P8+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP2] + - signature: "P12+P11+P10+P9+P8+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP3] + - signature: "P12+P11+P10+P9+P8+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP4] + - signature: "P12+P11+P10+P9+P8+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP5] + - signature: "P12+P11+P10+P9+P8+P6+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP6] + - signature: "P12+P11+P10+P9+P8+P7+K|xxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP7] + - signature: "P12+P11+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P11+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP5, mrP3, mrP2, mrP1] + - signature: "P12+P11+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP5, mrP4, mrP2, mrP1] + - signature: "P12+P11+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP5, mrP4, mrP3, mrP1] + - signature: "P12+P11+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP5, mrP4, mrP3, mrP2] + - signature: "P12+P11+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP3, mrP2, mrP1] + - signature: "P12+P11+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP4, mrP2, mrP1] + - signature: "P12+P11+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP4, mrP3, mrP1] + - signature: "P12+P11+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP4, mrP3, mrP2] + - signature: "P12+P11+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP5, mrP2, mrP1] + - signature: "P12+P11+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP5, mrP3, mrP1] + - signature: "P12+P11+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP5, mrP3, mrP2] + - signature: "P12+P11+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP5, mrP4, mrP1] + - signature: "P12+P11+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP5, mrP4, mrP2] + - signature: "P12+P11+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP6, mrP5, mrP4, mrP3] + - signature: "P12+P11+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP3, mrP2, mrP1] + - signature: "P12+P11+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP4, mrP2, mrP1] + - signature: "P12+P11+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP4, mrP3, mrP1] + - signature: "P12+P11+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP4, mrP3, mrP2] + - signature: "P12+P11+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP5, mrP2, mrP1] + - signature: "P12+P11+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP5, mrP3, mrP1] + - signature: "P12+P11+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP5, mrP3, mrP2] + - signature: "P12+P11+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP5, mrP4, mrP1] + - signature: "P12+P11+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP5, mrP4, mrP2] + - signature: "P12+P11+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP5, mrP4, mrP3] + - signature: "P12+P11+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP2, mrP1] + - signature: "P12+P11+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP3, mrP1] + - signature: "P12+P11+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP3, mrP2] + - signature: "P12+P11+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP4, mrP1] + - signature: "P12+P11+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP4, mrP2] + - signature: "P12+P11+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP4, mrP3] + - signature: "P12+P11+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP5, mrP1] + - signature: "P12+P11+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP5, mrP2] + - signature: "P12+P11+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP5, mrP3] + - signature: "P12+P11+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP7, mrP6, mrP5, mrP4] + - signature: "P12+P11+P8+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP3, mrP2, mrP1] + - signature: "P12+P11+P8+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP4, mrP2, mrP1] + - signature: "P12+P11+P8+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP4, mrP3, mrP1] + - signature: "P12+P11+P8+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP4, mrP3, mrP2] + - signature: "P12+P11+P8+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP5, mrP2, mrP1] + - signature: "P12+P11+P8+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP5, mrP3, mrP1] + - signature: "P12+P11+P8+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP5, mrP3, mrP2] + - signature: "P12+P11+P8+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP5, mrP4, mrP1] + - signature: "P12+P11+P8+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP5, mrP4, mrP2] + - signature: "P12+P11+P8+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP5, mrP4, mrP3] + - signature: "P12+P11+P8+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP2, mrP1] + - signature: "P12+P11+P8+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP3, mrP1] + - signature: "P12+P11+P8+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP3, mrP2] + - signature: "P12+P11+P8+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP4, mrP1] + - signature: "P12+P11+P8+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP4, mrP2] + - signature: "P12+P11+P8+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP4, mrP3] + - signature: "P12+P11+P8+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP5, mrP1] + - signature: "P12+P11+P8+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP5, mrP2] + - signature: "P12+P11+P8+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP5, mrP3] + - signature: "P12+P11+P8+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP6, mrP5, mrP4] + - signature: "P12+P11+P8+P7+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP2, mrP1] + - signature: "P12+P11+P8+P7+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP3, mrP1] + - signature: "P12+P11+P8+P7+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP3, mrP2] + - signature: "P12+P11+P8+P7+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP4, mrP1] + - signature: "P12+P11+P8+P7+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP4, mrP2] + - signature: "P12+P11+P8+P7+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP4, mrP3] + - signature: "P12+P11+P8+P7+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP5, mrP1] + - signature: "P12+P11+P8+P7+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP5, mrP2] + - signature: "P12+P11+P8+P7+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP5, mrP3] + - signature: "P12+P11+P8+P7+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP5, mrP4] + - signature: "P12+P11+P8+P7+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP6, mrP1] + - signature: "P12+P11+P8+P7+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP6, mrP2] + - signature: "P12+P11+P8+P7+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP6, mrP3] + - signature: "P12+P11+P8+P7+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP6, mrP4] + - signature: "P12+P11+P8+P7+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP8, mrP7, mrP6, mrP5] + - signature: "P12+P11+P9+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP3, mrP2, mrP1] + - signature: "P12+P11+P9+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP4, mrP2, mrP1] + - signature: "P12+P11+P9+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP4, mrP3, mrP1] + - signature: "P12+P11+P9+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP4, mrP3, mrP2] + - signature: "P12+P11+P9+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP5, mrP2, mrP1] + - signature: "P12+P11+P9+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP5, mrP3, mrP1] + - signature: "P12+P11+P9+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP5, mrP3, mrP2] + - signature: "P12+P11+P9+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP5, mrP4, mrP1] + - signature: "P12+P11+P9+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP5, mrP4, mrP2] + - signature: "P12+P11+P9+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP5, mrP4, mrP3] + - signature: "P12+P11+P9+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP2, mrP1] + - signature: "P12+P11+P9+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP3, mrP1] + - signature: "P12+P11+P9+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP3, mrP2] + - signature: "P12+P11+P9+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP4, mrP1] + - signature: "P12+P11+P9+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP4, mrP2] + - signature: "P12+P11+P9+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP4, mrP3] + - signature: "P12+P11+P9+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP5, mrP1] + - signature: "P12+P11+P9+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP5, mrP2] + - signature: "P12+P11+P9+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP5, mrP3] + - signature: "P12+P11+P9+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP6, mrP5, mrP4] + - signature: "P12+P11+P9+P7+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP2, mrP1] + - signature: "P12+P11+P9+P7+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP3, mrP1] + - signature: "P12+P11+P9+P7+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP3, mrP2] + - signature: "P12+P11+P9+P7+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP4, mrP1] + - signature: "P12+P11+P9+P7+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP4, mrP2] + - signature: "P12+P11+P9+P7+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP4, mrP3] + - signature: "P12+P11+P9+P7+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP5, mrP1] + - signature: "P12+P11+P9+P7+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP5, mrP2] + - signature: "P12+P11+P9+P7+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP5, mrP3] + - signature: "P12+P11+P9+P7+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP5, mrP4] + - signature: "P12+P11+P9+P7+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP6, mrP1] + - signature: "P12+P11+P9+P7+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP6, mrP2] + - signature: "P12+P11+P9+P7+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP6, mrP3] + - signature: "P12+P11+P9+P7+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP6, mrP4] + - signature: "P12+P11+P9+P7+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP7, mrP6, mrP5] + - signature: "P12+P11+P9+P8+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP2, mrP1] + - signature: "P12+P11+P9+P8+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP3, mrP1] + - signature: "P12+P11+P9+P8+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP3, mrP2] + - signature: "P12+P11+P9+P8+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP4, mrP1] + - signature: "P12+P11+P9+P8+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP4, mrP2] + - signature: "P12+P11+P9+P8+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP4, mrP3] + - signature: "P12+P11+P9+P8+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP5, mrP1] + - signature: "P12+P11+P9+P8+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP5, mrP2] + - signature: "P12+P11+P9+P8+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP5, mrP3] + - signature: "P12+P11+P9+P8+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP5, mrP4] + - signature: "P12+P11+P9+P8+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP6, mrP1] + - signature: "P12+P11+P9+P8+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP6, mrP2] + - signature: "P12+P11+P9+P8+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP6, mrP3] + - signature: "P12+P11+P9+P8+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP6, mrP4] + - signature: "P12+P11+P9+P8+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP6, mrP5] + - signature: "P12+P11+P9+P8+P7+P1+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP7, mrP1] + - signature: "P12+P11+P9+P8+P7+P2+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP7, mrP2] + - signature: "P12+P11+P9+P8+P7+P3+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP7, mrP3] + - signature: "P12+P11+P9+P8+P7+P4+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP7, mrP4] + - signature: "P12+P11+P9+P8+P7+P5+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP7, mrP5] + - signature: "P12+P11+P9+P8+P7+P6+K|xxxxxxk" + rules: [mrP12, mrP11, mrP9, mrP8, mrP7, mrP6] + - signature: "P12+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P6+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP6, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P6+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP6, mrP5, mrP3, mrP2, mrP1] + - signature: "P12+P6+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP6, mrP5, mrP4, mrP2, mrP1] + - signature: "P12+P6+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP6, mrP5, mrP4, mrP3, mrP1] + - signature: "P12+P6+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP6, mrP5, mrP4, mrP3, mrP2] + - signature: "P12+P7+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P7+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP5, mrP3, mrP2, mrP1] + - signature: "P12+P7+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP5, mrP4, mrP2, mrP1] + - signature: "P12+P7+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP5, mrP4, mrP3, mrP1] + - signature: "P12+P7+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP7, mrP5, mrP4, mrP3, mrP2] + - signature: "P12+P7+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP3, mrP2, mrP1] + - signature: "P12+P7+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP4, mrP2, mrP1] + - signature: "P12+P7+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP4, mrP3, mrP1] + - signature: "P12+P7+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP4, mrP3, mrP2] + - signature: "P12+P7+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP5, mrP2, mrP1] + - signature: "P12+P7+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP5, mrP3, mrP1] + - signature: "P12+P7+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP5, mrP3, mrP2] + - signature: "P12+P7+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP5, mrP4, mrP1] + - signature: "P12+P7+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP5, mrP4, mrP2] + - signature: "P12+P7+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP7, mrP6, mrP5, mrP4, mrP3] + - signature: "P12+P8+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P8+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP5, mrP3, mrP2, mrP1] + - signature: "P12+P8+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP5, mrP4, mrP2, mrP1] + - signature: "P12+P8+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP5, mrP4, mrP3, mrP1] + - signature: "P12+P8+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP5, mrP4, mrP3, mrP2] + - signature: "P12+P8+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP3, mrP2, mrP1] + - signature: "P12+P8+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP4, mrP2, mrP1] + - signature: "P12+P8+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP4, mrP3, mrP1] + - signature: "P12+P8+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP4, mrP3, mrP2] + - signature: "P12+P8+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP5, mrP2, mrP1] + - signature: "P12+P8+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP5, mrP3, mrP1] + - signature: "P12+P8+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP5, mrP3, mrP2] + - signature: "P12+P8+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP5, mrP4, mrP1] + - signature: "P12+P8+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP5, mrP4, mrP2] + - signature: "P12+P8+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP8, mrP6, mrP5, mrP4, mrP3] + - signature: "P12+P8+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP3, mrP2, mrP1] + - signature: "P12+P8+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP4, mrP2, mrP1] + - signature: "P12+P8+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP4, mrP3, mrP1] + - signature: "P12+P8+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP4, mrP3, mrP2] + - signature: "P12+P8+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP5, mrP2, mrP1] + - signature: "P12+P8+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP5, mrP3, mrP1] + - signature: "P12+P8+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP5, mrP3, mrP2] + - signature: "P12+P8+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP5, mrP4, mrP1] + - signature: "P12+P8+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP5, mrP4, mrP2] + - signature: "P12+P8+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP5, mrP4, mrP3] + - signature: "P12+P8+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP2, mrP1] + - signature: "P12+P8+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP3, mrP1] + - signature: "P12+P8+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP3, mrP2] + - signature: "P12+P8+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP4, mrP1] + - signature: "P12+P8+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP4, mrP2] + - signature: "P12+P8+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP4, mrP3] + - signature: "P12+P8+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP5, mrP1] + - signature: "P12+P8+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP5, mrP2] + - signature: "P12+P8+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP5, mrP3] + - signature: "P12+P8+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP8, mrP7, mrP6, mrP5, mrP4] + - signature: "P12+P9+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP4, mrP3, mrP2, mrP1] + - signature: "P12+P9+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP5, mrP3, mrP2, mrP1] + - signature: "P12+P9+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP5, mrP4, mrP2, mrP1] + - signature: "P12+P9+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP5, mrP4, mrP3, mrP1] + - signature: "P12+P9+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP5, mrP4, mrP3, mrP2] + - signature: "P12+P9+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP3, mrP2, mrP1] + - signature: "P12+P9+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP4, mrP2, mrP1] + - signature: "P12+P9+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP4, mrP3, mrP1] + - signature: "P12+P9+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP4, mrP3, mrP2] + - signature: "P12+P9+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP5, mrP2, mrP1] + - signature: "P12+P9+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP5, mrP3, mrP1] + - signature: "P12+P9+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP5, mrP3, mrP2] + - signature: "P12+P9+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP5, mrP4, mrP1] + - signature: "P12+P9+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP5, mrP4, mrP2] + - signature: "P12+P9+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP6, mrP5, mrP4, mrP3] + - signature: "P12+P9+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP3, mrP2, mrP1] + - signature: "P12+P9+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP4, mrP2, mrP1] + - signature: "P12+P9+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP4, mrP3, mrP1] + - signature: "P12+P9+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP4, mrP3, mrP2] + - signature: "P12+P9+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP5, mrP2, mrP1] + - signature: "P12+P9+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP5, mrP3, mrP1] + - signature: "P12+P9+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP5, mrP3, mrP2] + - signature: "P12+P9+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP5, mrP4, mrP1] + - signature: "P12+P9+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP5, mrP4, mrP2] + - signature: "P12+P9+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP5, mrP4, mrP3] + - signature: "P12+P9+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP2, mrP1] + - signature: "P12+P9+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP3, mrP1] + - signature: "P12+P9+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP3, mrP2] + - signature: "P12+P9+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP4, mrP1] + - signature: "P12+P9+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP4, mrP2] + - signature: "P12+P9+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP4, mrP3] + - signature: "P12+P9+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP5, mrP1] + - signature: "P12+P9+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP5, mrP2] + - signature: "P12+P9+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP5, mrP3] + - signature: "P12+P9+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP9, mrP7, mrP6, mrP5, mrP4] + - signature: "P12+P9+P8+P3+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP3, mrP2, mrP1] + - signature: "P12+P9+P8+P4+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP4, mrP2, mrP1] + - signature: "P12+P9+P8+P4+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP4, mrP3, mrP1] + - signature: "P12+P9+P8+P4+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP4, mrP3, mrP2] + - signature: "P12+P9+P8+P5+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP5, mrP2, mrP1] + - signature: "P12+P9+P8+P5+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP5, mrP3, mrP1] + - signature: "P12+P9+P8+P5+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP5, mrP3, mrP2] + - signature: "P12+P9+P8+P5+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP5, mrP4, mrP1] + - signature: "P12+P9+P8+P5+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP5, mrP4, mrP2] + - signature: "P12+P9+P8+P5+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP5, mrP4, mrP3] + - signature: "P12+P9+P8+P6+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP2, mrP1] + - signature: "P12+P9+P8+P6+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP3, mrP1] + - signature: "P12+P9+P8+P6+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP3, mrP2] + - signature: "P12+P9+P8+P6+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP4, mrP1] + - signature: "P12+P9+P8+P6+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP4, mrP2] + - signature: "P12+P9+P8+P6+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP4, mrP3] + - signature: "P12+P9+P8+P6+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP5, mrP1] + - signature: "P12+P9+P8+P6+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP5, mrP2] + - signature: "P12+P9+P8+P6+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP5, mrP3] + - signature: "P12+P9+P8+P6+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP6, mrP5, mrP4] + - signature: "P12+P9+P8+P7+P2+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP2, mrP1] + - signature: "P12+P9+P8+P7+P3+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP3, mrP1] + - signature: "P12+P9+P8+P7+P3+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP3, mrP2] + - signature: "P12+P9+P8+P7+P4+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP4, mrP1] + - signature: "P12+P9+P8+P7+P4+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP4, mrP2] + - signature: "P12+P9+P8+P7+P4+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP4, mrP3] + - signature: "P12+P9+P8+P7+P5+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP5, mrP1] + - signature: "P12+P9+P8+P7+P5+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP5, mrP2] + - signature: "P12+P9+P8+P7+P5+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP5, mrP3] + - signature: "P12+P9+P8+P7+P5+P4+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP5, mrP4] + - signature: "P12+P9+P8+P7+P6+P1+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP6, mrP1] + - signature: "P12+P9+P8+P7+P6+P2+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP6, mrP2] + - signature: "P12+P9+P8+P7+P6+P3+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP6, mrP3] + - signature: "P12+P9+P8+P7+P6+P4+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP6, mrP4] + - signature: "P12+P9+P8+P7+P6+P5+K|xxxxxxk" + rules: [mrP12, mrP9, mrP8, mrP7, mrP6, mrP5] + - signature: "P6+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP6, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P7+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP7, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P7+P6+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP7, mrP6, mrP4, mrP3, mrP2, mrP1] + - signature: "P7+P6+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP7, mrP6, mrP5, mrP3, mrP2, mrP1] + - signature: "P7+P6+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP7, mrP6, mrP5, mrP4, mrP2, mrP1] + - signature: "P7+P6+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP7, mrP6, mrP5, mrP4, mrP3, mrP1] + - signature: "P7+P6+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP7, mrP6, mrP5, mrP4, mrP3, mrP2] + - signature: "P8+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P8+P6+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP6, mrP4, mrP3, mrP2, mrP1] + - signature: "P8+P6+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP6, mrP5, mrP3, mrP2, mrP1] + - signature: "P8+P6+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP6, mrP5, mrP4, mrP2, mrP1] + - signature: "P8+P6+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP8, mrP6, mrP5, mrP4, mrP3, mrP1] + - signature: "P8+P6+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP8, mrP6, mrP5, mrP4, mrP3, mrP2] + - signature: "P8+P7+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP4, mrP3, mrP2, mrP1] + - signature: "P8+P7+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP5, mrP3, mrP2, mrP1] + - signature: "P8+P7+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP5, mrP4, mrP2, mrP1] + - signature: "P8+P7+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP5, mrP4, mrP3, mrP1] + - signature: "P8+P7+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP8, mrP7, mrP5, mrP4, mrP3, mrP2] + - signature: "P8+P7+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP3, mrP2, mrP1] + - signature: "P8+P7+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP4, mrP2, mrP1] + - signature: "P8+P7+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP4, mrP3, mrP1] + - signature: "P8+P7+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP4, mrP3, mrP2] + - signature: "P8+P7+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP5, mrP2, mrP1] + - signature: "P8+P7+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP5, mrP3, mrP1] + - signature: "P8+P7+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP5, mrP3, mrP2] + - signature: "P8+P7+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP5, mrP4, mrP1] + - signature: "P8+P7+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP5, mrP4, mrP2] + - signature: "P8+P7+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP8, mrP7, mrP6, mrP5, mrP4, mrP3] + - signature: "P9+P5+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP5, mrP4, mrP3, mrP2, mrP1] + - signature: "P9+P6+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP6, mrP4, mrP3, mrP2, mrP1] + - signature: "P9+P6+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP6, mrP5, mrP3, mrP2, mrP1] + - signature: "P9+P6+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP6, mrP5, mrP4, mrP2, mrP1] + - signature: "P9+P6+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP6, mrP5, mrP4, mrP3, mrP1] + - signature: "P9+P6+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP6, mrP5, mrP4, mrP3, mrP2] + - signature: "P9+P7+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP4, mrP3, mrP2, mrP1] + - signature: "P9+P7+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP5, mrP3, mrP2, mrP1] + - signature: "P9+P7+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP5, mrP4, mrP2, mrP1] + - signature: "P9+P7+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP5, mrP4, mrP3, mrP1] + - signature: "P9+P7+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP7, mrP5, mrP4, mrP3, mrP2] + - signature: "P9+P7+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP3, mrP2, mrP1] + - signature: "P9+P7+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP4, mrP2, mrP1] + - signature: "P9+P7+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP4, mrP3, mrP1] + - signature: "P9+P7+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP4, mrP3, mrP2] + - signature: "P9+P7+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP5, mrP2, mrP1] + - signature: "P9+P7+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP5, mrP3, mrP1] + - signature: "P9+P7+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP5, mrP3, mrP2] + - signature: "P9+P7+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP5, mrP4, mrP1] + - signature: "P9+P7+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP5, mrP4, mrP2] + - signature: "P9+P7+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP9, mrP7, mrP6, mrP5, mrP4, mrP3] + - signature: "P9+P8+P4+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP4, mrP3, mrP2, mrP1] + - signature: "P9+P8+P5+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP5, mrP3, mrP2, mrP1] + - signature: "P9+P8+P5+P4+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP5, mrP4, mrP2, mrP1] + - signature: "P9+P8+P5+P4+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP5, mrP4, mrP3, mrP1] + - signature: "P9+P8+P5+P4+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP5, mrP4, mrP3, mrP2] + - signature: "P9+P8+P6+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP3, mrP2, mrP1] + - signature: "P9+P8+P6+P4+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP4, mrP2, mrP1] + - signature: "P9+P8+P6+P4+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP4, mrP3, mrP1] + - signature: "P9+P8+P6+P4+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP4, mrP3, mrP2] + - signature: "P9+P8+P6+P5+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP5, mrP2, mrP1] + - signature: "P9+P8+P6+P5+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP5, mrP3, mrP1] + - signature: "P9+P8+P6+P5+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP5, mrP3, mrP2] + - signature: "P9+P8+P6+P5+P4+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP5, mrP4, mrP1] + - signature: "P9+P8+P6+P5+P4+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP5, mrP4, mrP2] + - signature: "P9+P8+P6+P5+P4+P3+K|xxxxxxk" + rules: [mrP9, mrP8, mrP6, mrP5, mrP4, mrP3] + - signature: "P9+P8+P7+P3+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP3, mrP2, mrP1] + - signature: "P9+P8+P7+P4+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP4, mrP2, mrP1] + - signature: "P9+P8+P7+P4+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP4, mrP3, mrP1] + - signature: "P9+P8+P7+P4+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP4, mrP3, mrP2] + - signature: "P9+P8+P7+P5+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP5, mrP2, mrP1] + - signature: "P9+P8+P7+P5+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP5, mrP3, mrP1] + - signature: "P9+P8+P7+P5+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP5, mrP3, mrP2] + - signature: "P9+P8+P7+P5+P4+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP5, mrP4, mrP1] + - signature: "P9+P8+P7+P5+P4+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP5, mrP4, mrP2] + - signature: "P9+P8+P7+P5+P4+P3+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP5, mrP4, mrP3] + - signature: "P9+P8+P7+P6+P2+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP2, mrP1] + - signature: "P9+P8+P7+P6+P3+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP3, mrP1] + - signature: "P9+P8+P7+P6+P3+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP3, mrP2] + - signature: "P9+P8+P7+P6+P4+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP4, mrP1] + - signature: "P9+P8+P7+P6+P4+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP4, mrP2] + - signature: "P9+P8+P7+P6+P4+P3+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP4, mrP3] + - signature: "P9+P8+P7+P6+P5+P1+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP5, mrP1] + - signature: "P9+P8+P7+P6+P5+P2+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP5, mrP2] + - signature: "P9+P8+P7+P6+P5+P3+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP5, mrP3] + - signature: "P9+P8+P7+P6+P5+P4+K|xxxxxxk" + rules: [mrP9, mrP8, mrP7, mrP6, mrP5, mrP4] + + - word: "xxxxxxxxxxxxk" + note: >- + The all-slots-fired boundary case, the mirror image of "k": with all 12 x's present, every + single slot must have fired (no other subset of size 12 exists out of 12), so C(12,12) = 1 -- + back down to exactly one analysis, confirming the combinatorics collapse correctly at the + other extreme. Morph order is P12..P1..K because each later-firing slot's InsertSegments + prepends its "x" further to the left than every slot that fired before it (confirmed against + v1's own expected.tsv). + provenance: "F3 worked example (pathological category): 12 independent all-optional affix-template prefix slots inserting an identical literal character, producing C(12,k) equally-valid analyses for a k-x-prefixed word (924 for k=6, confirmed against the live oracle: 3 words, ~2.0s total wall-clock on this branch's un-optimized plain-master engine)" + parses: + - signature: "P12+P11+P10+P9+P8+P7+P6+P5+P4+P3+P2+P1+K|xxxxxxxxxxxxk" + rules: [mrP12, mrP11, mrP10, mrP9, mrP8, mrP7, mrP6, mrP5, mrP4, mrP3, mrP2, mrP1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" diff --git a/conformance/edge-cases/diacritic-segments/grammar.xml b/conformance/edge-cases/diacritic-segments/grammar.xml new file mode 100644 index 000000000..a9db50d81 --- /dev/null +++ b/conformance/edge-cases/diacritic-segments/grammar.xml @@ -0,0 +1,192 @@ + + + + + LatinDiacriticProbe + + + + root + + + + Main + + + a + c + e + f + g + k + l + o + s + t + + é + ö + ñ + î + + + + + + Any + + + + Diacritic + + + + + + + + + Main + + + + plural + + + + + + + + + + + + + s + + + + + PL + PL + + + + diminutive + + + + + + + + + + + + + ta + + + + + + + + + + + + + + + + DIM + DIM + + + + + suffixTemplate + + + suffix1 + + + + + + + + + año + + + YEAR + year + + + + + + café + + + COFFEE + coffee + + + + + + göl + + + LAKE + lake + + + + + + kelî + + + WORD + word + + + + + + diff --git a/conformance/edge-cases/diacritic-segments/words.yaml b/conformance/edge-cases/diacritic-segments/words.yaml new file mode 100644 index 000000000..789212307 --- /dev/null +++ b/conformance/edge-cases/diacritic-segments/words.yaml @@ -0,0 +1,201 @@ +# What this pins: PanGloss's hc-foma engine (an alternative FST-based analyzer, not part of this +# repo) was found to return ZERO parses for any word containing a precomposed Latin diacritic (ñ, +# é, ö, î), while the default engine (ported from this repo's own C# HermitCrab) and Cyrillic text +# both parse those words fine. The bug is in hc-foma's own byte/token handling around Unicode +# NFD-decomposition, not in HermitCrab or in the grammar-model constructs any of this suite's 8 +# typological languages exercise (they use invented lexemes with plain ASCII segment inventories by +# design, so none of them can host this trigger naturalistically) -- per conformance/README.md's +# growth policy, this is therefore an edge-case (option 3: "engine-internal... a rule shape no real +# grammar would contain"), not a new word in an existing language. +# +# grammar.xml defines 4 roots, each carrying exactly one precomposed diacritic segment (é, ö, ñ, î +# -- the bug report's exact set) at a different position: +# - año (ñ MEDIAL, not stem-final) / göl (ö MEDIAL, not stem-final) +# - café (é stem-FINAL) / kelî (î stem-FINAL) +# Two optional, mutually-exclusive suffix rules exercise the affixed case (the actual bug affected +# both bare AND affixed diacritic-bearing words alike): +# - rPl ("-s"): unconditional, applies after any root regardless of its final segment. +# - rDim ("-ta"): GATED by a LeftEnvironment requiring the stem's final segment to be a member of +# ncDiacritic. This is the real regression pin, not just a copy-through check: café/kelî +# (diacritic-final) satisfy the gate and take "-ta"; año/göl (diacritic MEDIAL, not final) do +# not, so the SAME rule correctly fires on one pair and fails on the other. A byte/NFD-handling +# bug that mishandles diacritic segments could plausibly get one direction right and the other +# wrong (e.g. losing the segment's NaturalClass membership entirely -- the gate never fires even +# where it should -- or over-matching -- the gate wrongly fires where it shouldn't). +# One more word ("gül", built on "ü", a diacritic NOT declared anywhere in this grammar's +# CharacterDefinitionTable) pins the SKIPPED path: an undeclared diacritic must still surface as a +# clean InvalidShapeException/SKIPPED, not a silent zero-analysis "ok" or a crash. +# +# All signatures below are hand-derived (no multi-character segment representations exist in this +# grammar, so no HermitCrabExtensions.ToRegexString parenthesization applies -- see +# conformance/PROTOCOL.md section 3's addendum) and self-check-verified against the C# oracle before +# being checked in, per this suite's authoring discipline (signatures are authored-and-verified, +# never blindly regenerated). + +language: LatinDiacriticProbe +inspired_by: ["synthetic Latin-diacritic-segment probe (not modeling any real language)"] +sources: + - "PanGloss hc-foma engine: precomposed Latin diacritics (é/ö/ñ/î) yielding zero parses (NFD-decomposition / byte-handling bug in the alternative FST engine, not in HermitCrab)" +requires: [] +words: + - word: año + note: >- + Bare root, diacritic (ñ) MEDIAL -- not stem-final. Plain control: no affix rule fires (the + optional suffix slot is simply skipped), surface is the root unmutated. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "YEAR|año" + gloss: year + rules: [] + exercises: [] + + - word: café + note: >- + Bare root, diacritic (é) stem-FINAL. Plain control: no affix rule fires, surface is the root + unmutated. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "COFFEE|café" + gloss: coffee + rules: [] + exercises: [] + + - word: göl + note: >- + Bare root, diacritic (ö) MEDIAL -- not stem-final. Plain control: no affix rule fires. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "LAKE|göl" + gloss: lake + rules: [] + exercises: [] + + - word: kelî + note: >- + Bare root, diacritic (î) stem-FINAL. Plain control: no affix rule fires. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "WORD|kelî" + gloss: word + rules: [] + exercises: [] + + - word: años + note: >- + año + rPl ("-s"), the unconditional suffix -- exercises the affixed case on a + diacritic-MEDIAL root: rPl does not care about the stem's final segment, so it fires + regardless of where in the stem the diacritic sits. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "YEAR+PL|años" + gloss: year-PL + rules: [rPl] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: cafés + note: >- + café + rPl ("-s") -- the affixed case on a diacritic-FINAL root: the suffix attaches directly + after the diacritic segment itself, exercising CopyFromInput's preservation of a diacritic + segment immediately adjacent to an inserted affix boundary. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "COFFEE+PL|cafés" + gloss: coffee-PL + rules: [rPl] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: göls + note: göl + rPl ("-s"), the diacritic-MEDIAL affixed case, mirroring años. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "LAKE+PL|göls" + gloss: lake-PL + rules: [rPl] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: kelîs + note: kelî + rPl ("-s"), the diacritic-FINAL affixed case, mirroring cafés. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "WORD+PL|kelîs" + gloss: word-PL + rules: [rPl] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: caféta + note: >- + THE distinguishing acceptance row: café + rDim ("-ta"), whose LeftEnvironment gate requires + the stem's final segment to be a ncDiacritic member -- "café" ends in "é", satisfying the + gate, so rDim correctly fires. Pins that a diacritic segment is recognized as a genuine + NaturalClass member at the exact boundary position, not just copied through literally. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "COFFEE+DIM|caféta" + gloss: coffee-DIM + rules: [rDim] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + - "Affix template slots (obligatory/disjunctive/ordering)" + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: kelîta + note: >- + The mirror-image acceptance row: kelî + rDim ("-ta") -- "kelî" ends in "î", satisfying the + LeftEnvironment gate, same as caféta. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + parses: + - signature: "WORD+DIM|kelîta" + gloss: word-DIM + rules: [rDim] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + - "Affix template slots (obligatory/disjunctive/ordering)" + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: añota + note: >- + THE distinguishing rejection row: año + attempted rDim ("-ta") -- "año" ends in "o", NOT a + ncDiacritic member (the "ñ" is medial, not stem-final), so rDim's LeftEnvironment gate fails + and no valid derivation exists. Zero parses. An engine that over-matches (e.g. treats any + stem containing a diacritic ANYWHERE as gate-satisfying, rather than checking the exact + boundary-adjacent segment) would wrongly accept this. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + expect_fail: true + blocked_by: [rDim] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: gölta + note: >- + The mirror-image rejection row: göl + attempted rDim ("-ta") -- "göl" ends in "l", not a + ncDiacritic member ("ö" is medial), so the gate fails the same way as añota. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + expect_fail: true + blocked_by: [rDim] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: gül + note: >- + Built on "ü" (u-umlaut), a diacritic NOT declared anywhere in this grammar's + CharacterDefinitionTable (only é/ö/ñ/î are declared) -- the oracle's real status is SKIPPED + (InvalidShapeException), not a genuine zero-parse "ok". Pins that an undeclared diacritic + still surfaces as a clean SKIPPED rather than a silent "-" or a crash. + provenance: "PanGloss hc-foma Latin-diacritic zero-parse bug" + expect_skip: true + exercises: + - "Boundary markers (CharacterDefinitionTable)" diff --git a/conformance/edge-cases/disjunctive-recheck/grammar.xml b/conformance/edge-cases/disjunctive-recheck/grammar.xml new file mode 100644 index 000000000..c1b988a42 --- /dev/null +++ b/conformance/edge-cases/disjunctive-recheck/grammar.xml @@ -0,0 +1,203 @@ + + + + + DisjunctiveRecheckProbe + + + root + + + + + + ph + + w + a + o + k + t + p + i + z + d + g + r + e + y + + + + + Main + + w + a + o + k + t + p + i + z + d + g + r + e + y + + + + + Any + + + Tclass + + + + Kclass + + + + + + Main + + + + ta-suffix + + + + + + + + + + + + + ta + + + + + TA + + + + d-suffix + + + + + + + + + + + + + za + + + + + + + + + + + + + + + + + + + + + + + + + + da + + + + + D + + + + + + + wok + + + + + + + + + + + + + wak + + walk + + + + pak + + pak + + + + pit + + pit + + + + + gray + grey + + gray + + + + + + diff --git a/conformance/edge-cases/disjunctive-recheck/words.yaml b/conformance/edge-cases/disjunctive-recheck/words.yaml new file mode 100644 index 000000000..ba608a29f --- /dev/null +++ b/conformance/edge-cases/disjunctive-recheck/words.yaml @@ -0,0 +1,180 @@ +# Converted from conformance/allomorphy/disjunctive-recheck (v1, removed after the v1->v2 migration's +# parity proof). grammar.xml is the same file, +# unmodified: deliberately NO element on either MorphologicalRule (ruleT, ruleD) -- the +# v1 fixture pins signatures like "+|wokta" (an empty morph-chain component joined by "+"), which +# would change if a MorphemeId were added, so this fixture cannot gain one without breaking its own +# pin. This exposed a genuine GrammarRuleIndex gap while authoring this conversion (see the +# cross-cutting finding below); fixed in the same commit as this fixture's authoring. +# +# What this pins (from the v1 fixture's README.md/manifest.json, carried forward verbatim): C# +# Allomorph.IsWordValid's second loop (Allomorph.cs:127-152, introduced by history-matrix row 51 +# 987be2fd): a synthesized word is REJECTED when a passed-over disjunctive alternative -- an +# earlier-indexed allomorph of the same morpheme that does not free-fluctuate with the used one -- +# would ALSO have matched (its environments are absent or satisfied at the same morph position, and +# its other constraints hold). +# +# - Root disjunctivity (eWalk): allomorph 0 "wok" requires a following "t"; allomorph 1 "wak" is +# the elsewhere case. ruleT (unconstrained suffix "-ta") supplies the following "t". +# - Affix disjunctivity (ruleD): subrule 0 "-za" requires a preceding "k" (environment-constrained, +# so C#'s synthesis loop does not break after it and subrule 1 "-da" also fires, recording +# subrule 0 as passed-over). Roots pak/pit make the candidate's environment satisfied/unsatisfied. +# - Free-fluctuation escape (eGray): gray/grey, both unconstrained -- identical constraint sets +# free-fluctuate (Allomorph.FreeFluctuatesWith), so the later-indexed "grey" is NOT rejected. +# +# Every segment carries a unique featPh symbol specifically so a SegmentNaturalClass constraint does +# NOT degrade to "any segment" (the allomorphy/strrep-identity fixture is the deliberate opposite +# case) -- this fixture isolates the disjunctive re-check only. +# +# CROSS-CUTTING FINDING (GrammarRuleIndex, affects this fixture AND edge-cases/strrep-identity): +# both ruleT and ruleD genuinely fire during synthesis for several words below (e.g. ruleT fires for +# every "-ta"-suffixed word), but GrammarRuleIndex.ResolveMorphologicalRuleId could not attribute +# them at all before this commit -- it translates a runtime rule back to its grammar.xml id via +# Morpheme.Id (sourced from ), and neither rule declares one (see above). Self-check's +# traced-rules verification (RunnerV2.RunAllWords) therefore reported an empty actual set for every +# parse no matter what fired, which would force a dishonest "rules: []" on parses that visibly use +# ruleT/ruleD -- and separately made both rule ids permanently "dead" in rules.csv (CoverageReportV2 +# computes dead-rule status from declared "rules:"/"blocked_by", not the trace), which the ledger's +# floor forbids introducing. Fixed in GrammarRuleIndex.cs: when a MorphologicalRule/RealizationalRule +# has no at all, its text is registered in the SAME name-keyed fallback dict +# CompoundingRule/PhonologicalRule/MetathesisRule already use -- conservative because it only ever +# gains an entry in the no-MorphemeId case, so all 8 existing language grammars (which assign +# MorphemeId to every rule) are byte-for-byte unaffected. Confirmed empirically: before the fix, a +# draft "rules: [ruleT]" declaration on "wokta" FAILed self-check with "declared rules [ruleT] != +# traced []"; after the fix, the same declaration passes and the traced set is the honest, non-empty +# one used throughout this file. + +language: DisjunctiveRecheckProbe +inspired_by: ["synthetic allomorph-disjunctivity probe (not modeling any real language)"] +sources: + - "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" +requires: [] +words: + - word: wak + note: >- + eWalk's elsewhere allomorph "wak" bare (no suffix) -- allomorph 0 "wok"'s RightEnvironment + (following ncT) fails at word end, so no disjunctive rejection applies. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + parses: + - signature: "|wak" + gloss: walk + rules: [] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: wok + note: The used allomorph's OWN environment fails (no following "t" at all here) -- already-ported #5a own-environment gate, not the re-check this fixture adds. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + expect_fail: true + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: wakta + note: >- + THE distinguishing row (root disjunctivity): root allomorph "wak" (index 1) used with ruleT's + "-ta" suffix, but allomorph 0 "wok" (index 0)'s RightEnvironment (following ncT) is satisfied + at the root's own position (the "t" of "-ta" follows immediately) and the two allomorphs do + NOT free-fluctuate -- the disjunctive re-check REJECTS this synthesis. Zero parses, even + though "wak"+"-ta" concatenates cleanly and ruleT itself has no constraint against it. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + expect_fail: true + blocked_by: [ruleT] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: wokta + note: >- + The mirror-image acceptance: root allomorph "wok" (index 0) used, its OWN RightEnvironment + (following ncT) satisfied by ruleT's "-ta" -- no disjunctive rejection applies (index 0 has no + earlier-indexed alternative to be rejected in favor of). + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + parses: + - signature: "+|wokta" + gloss: walk-TA + rules: [ruleT] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: pak + note: PAK bare root, no suffix -- a plain, unrestricted control (no disjunctive allomorphs at all on this lexical entry). + parses: + - signature: "|pak" + gloss: pak + rules: [] + exercises: [] + + - word: pit + note: PIT bare root, no suffix -- the other plain control root used by the affix-disjunctivity rows below. + parses: + - signature: "|pit" + gloss: pit + rules: [] + exercises: [] + + - word: pakza + note: >- + PAK + ruleD subrule 0 ("-za", environment-constrained: preceding ncK) -- "pak" ends in "k", so + subrule 0's own environment is satisfied and it fires directly (no disjunctive-rejection + question for the USED subrule's own environment; that is the #5a gate, already correct). + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + parses: + - signature: "+|pakza" + gloss: pak-D + rules: [ruleD] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: pakda + note: >- + THE distinguishing row (affix disjunctivity): ruleD subrule 1 ("-da", elsewhere) used on + "pak", but subrule 0's environment (preceding ncK) is ALSO satisfied at the same morph + position (the stem still ends in "k") and subrule 0 was recorded as passed-over during + synthesis (it is environment-constrained, so C#'s loop does not break after it) -- the + disjunctive re-check REJECTS this synthesis. Zero parses. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + expect_fail: true + blocked_by: [ruleD] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: pitza + note: The used subrule's OWN environment fails ("pit" doesn't end in ncK) -- already-ported #5a own-environment gate, not the re-check this fixture adds. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + expect_fail: true + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: pitda + note: >- + The mirror-image acceptance: ruleD subrule 1 ("-da") used on "pit" -- subrule 0's candidate + environment (preceding ncK) fails ("pit" ends in "t", not "k"), so no disjunctive rejection + applies. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + parses: + - signature: "+|pitda" + gloss: pit-D + rules: [ruleD] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: gray + note: eGray's first allomorph "gray", unconstrained, no suffix -- establishes the free-fluctuation pair's baseline before "grey" below. + parses: + - signature: "|gray" + gloss: gray + rules: [] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: grey + note: >- + THE free-fluctuation escape: eGray's second allomorph "grey" -- allomorph 0 "gray" "would + also match" (both are totally unconstrained), but the two have IDENTICAL (empty) constraint + sets, so Allomorph.FreeFluctuatesWith recognizes them as free variants and short-circuits the + disjunctive rejection. "grey" is NOT rejected, unlike wakta/pakda above. + provenance: "W3.2, history row 51 (987be2fd) deferred disjunctive-allomorph re-check half" + parses: + - signature: "|grey" + gloss: gray + rules: [] + exercises: + - "Disjunctive allomorphs / free-fluctuation" diff --git a/conformance/edge-cases/feature-gating-breadth/grammar.xml b/conformance/edge-cases/feature-gating-breadth/grammar.xml new file mode 100644 index 000000000..a4474213d --- /dev/null +++ b/conformance/edge-cases/feature-gating-breadth/grammar.xml @@ -0,0 +1,173 @@ + + + + + + FeatureGatingBreadth + + n + + + + number + + sg + pl + + + + tense + + pres + past + + + + + + stress + + stressed + unstressed + + + + + Main + + a + i + o + u + d + k + l + m + n + t + + + + Any + + + + Main + + + + agreement + + + + ka + + + + + + + AGR + AGR + + Properties on a morphological rule + + + + + loud + + + + no + + + + LOUD + LOUD + + + + emphatic + + + + mu + + + + EMPH + EMPH + + + + past + + + + id + + + + PAST + PAST + + + + + + kal + + + KAL + kal + + + + tun + + + TUN + tun + + + + mol + + + MOL + mol + + + + nal + + + NAL + nal + + + + + + diff --git a/conformance/edge-cases/feature-gating-breadth/words.yaml b/conformance/edge-cases/feature-gating-breadth/words.yaml new file mode 100644 index 000000000..b50e59cc0 --- /dev/null +++ b/conformance/edge-cases/feature-gating-breadth/words.yaml @@ -0,0 +1,153 @@ +# Head and foot feature gating. See grammar.xml's header for why this small grammar exists alongside +# the dense languages/ fixtures that already contain these constructs. +# +# Oracle: the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over a Debug build of +# src/SIL.Machine.Morphology.HermitCrab.Tool). Every signature is transcribed from that run. The whole +# fixture parses in 72ms, which is the point: a mutant that removes one of these constraints stays +# tractable here, where in a dense grammar it does not. +# +# Each gate has its own failing word, so neither is credited by the other: +# tunka RequiredHeadFeatures: "tun" is number=sg where the rule requires plural. +# molka RequiredFootFeatures: "mol" is stress=unstressed where the rule requires stressed. +# nalnomu OutputFootFeatures: mrLoud has no input gate and OVERRIDES an unstressed root's foot +# feature, and mrEmph, downstream, is gated on the overridden value. "nal" starts out +# unstressed, so this word only succeeds because mrLoud's own OutputFootFeatures ran; kal +# (already stressed on its own) could not have shown this, which is why mrAgr's own +# OutputFootFeatures, redundant with what it already requires as input, is not evidenced. + +language: FeatureGatingBreadth +inspired_by: ["synthetic head/foot feature gating probe (not modeling any real language)"] +sources: + - "conformance/semantic-coverage-counterfactuals.tsv unobservable feature-gating surfaces" +requires: [] +words: + - word: kal + note: Bare root, plural and stressed, so it satisfies both of the rule's gates. + parses: + - signature: "KAL|kal" + rules: [] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kalka + note: The agreement suffix attaches only when both the head and the foot gate are satisfied. + parses: + - signature: "KAL+AGR|kalka" + rules: [mrAgr] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: tun + note: Singular root, unaffixed, parses on its own. + parses: + - signature: "TUN|tun" + rules: [] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: tunka + note: >- + Negative control for RequiredHeadFeatures. "tun" is singular, so the plural gate refuses the + suffix even though its foot feature matches. + expect_fail: true + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: mol + note: Plural but unstressed root, unaffixed, parses on its own. + parses: + - signature: "MOL|mol" + rules: [] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: molka + note: >- + Negative control for RequiredFootFeatures. "mol" is unstressed, so the foot gate refuses the + suffix even though its head feature matches. Paired with "tunka" this separates the two gates. + expect_fail: true + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kalid + note: The realizational rule realizes a head feature rather than gating on one. + parses: + - signature: "KAL+PAST|kalid" + rules: [rrPast] + exercises: + - "RealizationalAffixProcessRule" + + - word: kalidka + note: The realizational suffix is outermost, so the agreement suffix cannot follow it. + expect_fail: true + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: nal + note: Bare root, plural but unstressed. + parses: + - signature: "NAL|nal" + rules: [] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: nalno + note: mrLoud has no input gate, so it attaches regardless of the root's own foot feature. + parses: + - signature: "NAL+LOUD|nalno" + rules: [mrLoud] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: nalnomu + note: >- + Positive control for OutputFootFeatures. "nal" starts out unstressed; mrLoud's own + OutputFootFeatures overrides the derived word to stressed, which is the only reason mrEmph's + RequiredFootFeatures gate can then succeed. + neutralizes: + - OutputFootFeatures + parses: + - signature: "NAL+LOUD+EMPH|nalnomu" + rules: [mrLoud, mrEmph] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kalkano + note: >- + KAL + mrAgr ("-ka") + mrLoud ("-no"), in that list order (mrAgr before mrLoud on Stratum + "Main"). The ordering discriminator for the mrAgr~mrLoud adjacent pair: "kalnoka" below is + the same two suffixes reversed, which only parses when the list order is swapped. + parses: + - signature: "KAL+AGR+LOUD|kalkano" + rules: [mrAgr, mrLoud] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kalnoka + note: >- + KAL + mrLoud + mrAgr, the reverse of "kalkano". Zero parses under the shipped list order + (mrAgr mrLoud): only reachable when mrLoud is transposed ahead of mrAgr. + expect_fail: true + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kalmuid + note: >- + KAL + mrEmph ("-mu") + rrPast ("-id"), in that list order (mrEmph before rrPast on Stratum + "Main"). The ordering discriminator for the mrEmph~rrPast adjacent pair: "kalidmu" below is + the same two suffixes reversed, which only parses when the list order is swapped. "kal" is + already stressed on its own, so it satisfies mrEmph's RequiredFootFeatures without needing + mrLoud's override. + parses: + - signature: "KAL+EMPH+PAST|kalmuid" + rules: [mrEmph, rrPast] + exercises: + - "RealizationalAffixProcessRule" + + - word: kalidmu + note: >- + KAL + rrPast + mrEmph, the reverse of "kalmuid". Zero parses under the shipped list order + (mrEmph rrPast): only reachable when rrPast is transposed ahead of mrEmph. + expect_fail: true + exercises: + - "RealizationalAffixProcessRule" diff --git a/conformance/edge-cases/feature-system-breadth/grammar.xml b/conformance/edge-cases/feature-system-breadth/grammar.xml new file mode 100644 index 000000000..30000343c --- /dev/null +++ b/conformance/edge-cases/feature-system-breadth/grammar.xml @@ -0,0 +1,429 @@ + + + + + + FeatureSystemBreadth + + n + + + + high + + +hi + -hi + + + + cons + + +cons + -cons + + + + place + + none + cor + vel + lat + sib + + + + + decoyFeature + + +dec + + + + + + number + + sg + pl + + + + + agreement + + + complexDecoy + + + + Main + + + i + + + + + + a + + + + + + t + + + + + + + + k + + + + + + l + + + + + + s + + + + + + + + iOnly + aOnly + tOnly + kOnly + vowels + sOnly + lOnly + segClassDecoy + + + featClassDecoy + + + + tOrKforOverlap + kOrLforOverlap + Any + + + highConsonant + + + + + + + + raiseBeforeK + + + + + + + + + + + + + + + + + + + phonRuleDecoy + + + + + + + + + + + flipHighBeforeS + + + + + + + + + + + + + + + + + + + + + + + + + + + + swapRightToLeft + + + + + + + + + + + + lowerSAfterHighConsonant + + + + + + + + + + + + + swapOverlapAK + + + + + + + + + + + + kToTdecoy + + + + + + + + + + + + + sToLdecoy + + + + + + + + + + iToAdecoy + + + + + + + + + metathesisDecoy + + + + + + + + + + + + + Main + + + + sufK + + + + k + + + SUF + SUF + + + + + + ak + + + + + + AK + ak + + + + tal + + + + + + TAL + tal + + + at + AT + at + + + + + + ti + TI + ti + + + + tik + TIK + probe.tik + + + ka + KA + ka + + + ask + ASK + ask + + + + + sal + + + + + + + + SAL + sal + + + + tkl + TKL + tkl + + + + ts + TS + ts + + + + + + diff --git a/conformance/edge-cases/feature-system-breadth/words.yaml b/conformance/edge-cases/feature-system-breadth/words.yaml new file mode 100644 index 000000000..d0a4068d1 --- /dev/null +++ b/conformance/edge-cases/feature-system-breadth/words.yaml @@ -0,0 +1,242 @@ +# Feature-system and phonological-rule breadth. See grammar.xml's header for the design. +# +# Oracle: the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over a Debug build +# of src/SIL.Machine.Morphology.HermitCrab.Tool). Every signature is transcribed from that run. +# +# What each control isolates: +# ik prRaise fires: underlying "ak" surfaces with a raised vowel before "k". Also the observation +# that prDecoy is inactive, since prDecoy would turn the "i" straight back into "a" and this +# word would not exist. +# ak the unraised underlying form is NOT a surface word, which is what makes prRaise load-bearing. +# at prRaise's SECOND subrule is inactive; were it loaded it would raise this vowel before "t" +# too and "at" would not parse. NOT a control for the inactive FeatureValue on "t" (see "ts" +# below for that): "ncT" is an explicit SegmentNaturalClass membership list, not a +# feature-value bracket, so it never consults cT's own featHigh value at all. +# isk prAlpha fires with polarity="minus" on the output, flipping the vowel's height before "s". +# ask the unflipped underlying form is not a surface word. +# ka mtDecoy is inactive; were it loaded it would swap this "k a" pair and "ka" would not parse. +# it mtSwap fires right-to-left, swapping the root's "t i" pair. +# ti the unswapped underlying form is not a surface word. +# +# Every segment carries a unique feature bundle deliberately. An earlier draft gave t, k, l and s the +# same bundle and the oracle's own rendering collapsed them into a bracketed alternates class +# ("AK|a[tkls]"), which also gave every word spurious extra analyses. +# +# tkl/tlk/ktl mtSwapOverlap's ncOvA/ncOvB classes deliberately share segment "k", so a 3-segment run +# like "tkl" has two overlapping candidate windows (t-k and k-l). rightToLeftIterative +# (this fixture's declared order) finds the RIGHTMOST window first (k-l), swapping it to +# "tlk"; leftToRightIterative would find the LEFTMOST window first (t-k) instead, giving +# "ktl". Confirmed against the C# oracle with both orders by hand. +# ts prHighTrigger's probe for the decoy FeatureValue on cT: unaffected while cT is hiMinus +# (its declared value); if the decoy activated, cT would ALSO carry hiPlus (the later +# FeatureValue wins, so the earlier hiMinus is simply overwritten -- not a "contradictory +# value" as an earlier draft of this file guessed, and the counterfactual sweep bore that +# out: activating it changed nothing until this word and prHighTrigger existed to consume +# the resulting value). +# salk mrSuffixK's probe for eSal's ExcludedEnvironments: refused here, because aSal is +# excluded before ncK and mrSuffixK's own suffix begins with "k". +# +# ComplexFeature, SymbolicFeature, SegmentNaturalClass and FeatureNaturalClass's own isActive="no" +# declarations (cfDecoy/featDecoy/ncDecoy/ncFDecoy) are freestanding TYPE declarations rather than +# rules: the loader only adds an active one to its lookup dictionary, so any reference to it while +# inactive throws immediately at load time, and no single flip can ever observe one. Each is paired +# with an inactive partner that is its sole referent (eDecCf/prDecFeat/prDecNc/prDecFnc), evidenced +# only by CounterfactualGate.EvaluateJointly's three-run protocol: cfDecoy+eDecCf jointly makes "tal" +# (below) newly parse; featDecoy+prDecFeat and ncFDecoy+prDecFnc jointly change "ik"'s parse; +# ncDecoy+prDecNc jointly changes "sal"'s. + +language: FeatureSystemBreadth +inspired_by: ["synthetic feature-system and rule-deactivation probe (not modeling any real language)"] +sources: + - "conformance/semantic-coverage-baseline.txt feature-system todo entries" +requires: [phonology] +words: + - word: ik + note: >- + prRaise raises the vowel before "k". Also the control for PhonologicalRule@isActive="no": prDecoy + would lower every "i" back to "a", so this surface form could not exist if it were loaded. + neutralizes: + - prDecoy + parses: + - signature: "AK|ik" + rules: [prRaise] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: ak + note: The unraised underlying form is not a surface word, so prRaise is load-bearing. + expect_fail: true + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: at + note: >- + Control for PhonologicalSubrule@isActive="no". The inactive subrule would raise this vowel + before "t". NOT a control for the inactive FeatureValue on "t" (see "ts" for that): "ncT" is a + SegmentNaturalClass membership list and never consults cT's own featHigh value. + neutralizes: + - PhonologicalSubrule + parses: + - signature: "AT|at" + rules: [] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: sal + note: Plain control over the same alphabet, and the allomorph that carries ExcludedEnvironments. + parses: + - signature: "SAL|sal" + rules: [] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: isk + note: >- + prAlpha fires: polarity="minus" on the output takes the opposite value of the variable bound on + the input, so the underlying vowel flips height before "s". + parses: + - signature: "ASK|isk" + rules: [prAlpha] + exercises: + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: ask + note: The unflipped underlying form is not a surface word, so prAlpha is load-bearing. + expect_fail: true + exercises: + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: it + note: >- + mtSwap fires: the root "ti" surfaces with its pair swapped. The rule names the LATER pattern + group as its left switch, which is the only orientation the engine supports; see grammar.xml. + This word evidences the RULE, not its multipleApplicationOrder value, which the counterfactual + sweep finds unobservable here. + parses: + - signature: "TI|it" + rules: [mtSwap] + exercises: + - "MetathesisRule" + + - word: ti + note: The unswapped underlying form is not a surface word, so mtSwap is load-bearing. + expect_fail: true + exercises: + - "MetathesisRule" + + - word: ikt + note: >- + Ordering probe for mtSwap~mtSwapOverlap (TIK, "tik"): mtSwap fires first ("tik" -> "itk"), + bringing "t" newly adjacent to "k"; that window matches mtSwapOverlap's own switch classes + (ncOvA={t,k}, ncOvB={k,l}), so mtSwapOverlap then also fires ("itk" -> "ikt"). This is the + fixture's DECLARED order (mtSwap listed before mtSwapOverlap); see itk below for what the + swapped order produces instead. Two analyses share this surface: the bare TIK root, and TI + + mrSuffixK's "-k" suffix (previously unexercised in this fixture), which happens to reach the + same "tik" before phonology. Both traces additionally carry prRaise: the reverse search also + considers whether this word's "i before k" could be prRaise's own raised "a" (the same + environment AK/ik's own pair exercises below), the same ambiguous-analysis trace-union this + corpus documents elsewhere (see polysynthetic-stratal-derivation-chain's bubu word). + parses: + - signature: "TI+SUF|ikt" + rules: [mrSuffixK, mtSwap, mtSwapOverlap, prRaise] + exercises: + - "MetathesisRule" + - signature: "TIK|ikt" + rules: [mtSwap, mtSwapOverlap, prRaise] + exercises: + - "MetathesisRule" + + - word: itk + note: >- + What mtSwap~mtSwapOverlap SWAPPED would produce from the same TIK root ("tik"): mtSwapOverlap + runs first over the unswapped "tik", where the segment before "k" is still "i" (in neither + ncOvA nor ncOvB), so it does not fire; only mtSwap's own swap happens ("tik" -> "itk"), and + mtSwapOverlap never gets a second look. Not a valid surface form under this fixture's declared + order; the negative control that shows the order actually matters. + expect_fail: true + blocked_by: [mtSwapOverlap] + exercises: + - "MetathesisRule" + + - word: tik + note: The raw underlying shape of TIK, with neither swap applied -- mtSwap is obligatory wherever a "t" is directly followed by "i", so this surface form can never itself be a valid analysis (see ikt). + expect_fail: true + blocked_by: [mtSwap] + exercises: + - "MetathesisRule" + + - word: ka + note: >- + Control for MetathesisRule@isActive="no". mtDecoy would swap this "k a" pair, so the root + surfacing unchanged is what observes its deactivation. + neutralizes: + - mtDecoy + parses: + - signature: "KA|ka" + rules: [] + exercises: + - "MetathesisRule" + + - word: tkl + note: >- + mtSwapOverlap's own raw underlying shape. Its two switch classes (ncOvA={t,k}, ncOvB={k,l}) + share segment "k", so the rule fires obligatorily on one of the two overlapping windows; this + exact string is not a valid surface form. + expect_fail: true + exercises: + - "MetathesisRule" + + - word: tlk + note: >- + mtSwapOverlap's correctly-rewritten surface form under rightToLeftIterative (this fixture's + declared order): scanning right to left, the rightmost window (k-l, positions 2-3) is found + first and swapped, giving "t" + "lk" = "tlk". The leftmost window (t-k) is never reached: it + would need to start at position 1, but position 2 was already consumed by the first swap. + neutralizes: + - mtSwapOverlap + parses: + - signature: "TKL|tlk" + rules: [mtSwapOverlap] + exercises: + - "MetathesisRule" + + - word: ktl + note: >- + What mtSwapOverlap would produce on "tkl" under leftToRightIterative instead: scanning left to + right, the leftmost window (t-k, positions 1-2) is found first and swapped, giving "k" + "tl" = + "ktl". Not a valid surface form under this fixture's declared rightToLeftIterative order; kept + as the negative control that shows direction matters. + expect_fail: true + exercises: + - "MetathesisRule" + + - word: ts + note: >- + prHighTrigger's own probe. "t" (cT) is hiMinus, so it is not a member of ncHighCons and the + rule never fires. + neutralizes: + - prHighTrigger + parses: + - signature: "TS|ts" + rules: [] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: salk + note: >- + mrSuffixK's probe for eSal's ExcludedEnvironments. aSal is excluded whenever followed by ncK, + and mrSuffixK's own suffix begins with "k" (segment cK), so this word has no analysis: not via + aSal (excluded here) and there is no other allomorph for SAL. + expect_fail: true + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: tal + note: >- + Joint control for ComplexFeature@isActive="no". eDecCf is an inactive entry whose + AssignedHeadFeatures names the inactive cfDecoy, so neither alone is observable: activating + cfDecoy leaves nothing referencing it, and activating eDecCf alone dangles its cfDecoy + reference and refuses to load. Only both together admit this word. + expect_fail: true + exercises: + - "Element deactivation (isActive) across loader collections" diff --git a/conformance/edge-cases/free-fluctuating-allomorph-pair/grammar.xml b/conformance/edge-cases/free-fluctuating-allomorph-pair/grammar.xml new file mode 100644 index 000000000..68c6e82f2 --- /dev/null +++ b/conformance/edge-cases/free-fluctuating-allomorph-pair/grammar.xml @@ -0,0 +1,96 @@ + + + + + FreeFluctuatingAllomorphPair + + root + + + + + ph + + pole + kits + + + + + Main + + p + o + l + e + k + i + t + s + + + + Any + Sclass + + + + S + + + + sSuffix + + + + s + + + SSFX + + + + + + + pol + pel + + ALT + alt + + + + + + kit + + + + + + + kot + + ORD + ord + + + + + + diff --git a/conformance/edge-cases/free-fluctuating-allomorph-pair/words.yaml b/conformance/edge-cases/free-fluctuating-allomorph-pair/words.yaml new file mode 100644 index 000000000..9ae8329c3 --- /dev/null +++ b/conformance/edge-cases/free-fluctuating-allomorph-pair/words.yaml @@ -0,0 +1,70 @@ +# Oracle: pangloss (`pg_parse::Morpher`, driven directly via a temporary probe test -- see +# STAGING.md's "Verification" section), NOT the C# founding oracle. Signatures below are +# transcribed verbatim from that run, not hand-derived. + +language: FreeFluctuatingAllomorphPair +inspired_by: ["synthetic allomorph-disjunctivity/free-fluctuation probe (not modeling any real language); a dedicated, minimal analog of edge-cases/disjunctive-recheck's own eGray row"] +sources: + - "rust/crates/pg-foma/src/capability.rs, CharacteristicKind::FreeFluctuation's own doc" + - "machine/conformance/edge-cases/disjunctive-recheck (the free-fluctuation escape half of that fixture, isolated here)" +requires: [] +words: + - word: pol + note: eAlt's first allomorph, unconstrained, bare -- establishes the free-fluctuation pair's baseline before "pel" below. + parses: + - signature: "ALT|pol" + gloss: alt + rules: [] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: pel + note: >- + THE construct-exhibiting row: eAlt's second allomorph -- allomorph 0 "pol" "would also + match" (both are totally unconstrained), but the two have IDENTICAL (empty) constraint + sets, so pg_rules::validity::allomorphs_valid_impl recognizes them as free variants and + short-circuits the disjunctive rejection. "pel" is NOT rejected. + provenance: "capability.rs, CharacteristicKind::FreeFluctuation's own doc (root_constraints_equal / free_fluctuates)" + parses: + - signature: "ALT|pel" + gloss: alt + rules: [] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: kits + note: eOrd's environment-constrained allomorph 0 ("kit", requires a following "s") + ruleS -- allomorph 0's own environment is satisfied, so it fires directly. + parses: + - signature: "ORD+SSFX|kits" + gloss: ord-SSFX + rules: [ruleS] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: kots + note: >- + THE contrastive negative control: eOrd's elsewhere allomorph 1 ("kot") + ruleS -- allomorph + 0's environment (following "s") is ALSO satisfied at the same position, and the two + allomorphs do NOT free-fluctuate (their constraint sets differ), so the disjunctive + re-check REJECTS this synthesis. Zero parses. Sharpens exactly what "free" means in + FreeFluctuation: an engine that treats every multi-allomorph entry as free-fluctuating + (not just ones whose constraints truly compare equal) would wrongly accept this. + expect_fail: true + blocked_by: [ruleS] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: kot + note: eOrd's elsewhere allomorph, bare -- only derivable from allomorph 1 ("kit" has no following "s" here, so allomorph 0 cannot apply). + parses: + - signature: "ORD|kot" + gloss: ord + rules: [] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: kit + note: eOrd's environment-constrained allomorph, bare -- its own RightEnvironment (following "s") fails at word end, and allomorph 1 is spelled "kot", not "kit", so no derivation produces this surface form at all. + expect_fail: true + exercises: + - "Disjunctive allomorphs / free-fluctuation" diff --git a/conformance/edge-cases/loader-default-symbol/grammar.xml b/conformance/edge-cases/loader-default-symbol/grammar.xml new file mode 100644 index 000000000..d2bec7d77 --- /dev/null +++ b/conformance/edge-cases/loader-default-symbol/grammar.xml @@ -0,0 +1,188 @@ + + + + + N2-DefaultSymbol + + + Noun + + + + + + Nasal + + + + - + + + + Length + + - + + + + + + + SegId + + b + t + a + d + + + + + N2 Orthography + + + + + + b + + + + + + + + t + + + + + + + + + a + + + + + + + + d + + + + + + + + + aa + + + + + + + + Oral + + + + Long + + + + + + Lengthen oral segment + + + + + + + + + + + + + + + + + + + main + + + + + + bat + + + bat + + + + + + bdt + + + bdt + + + + + + diff --git a/conformance/edge-cases/loader-default-symbol/words.yaml b/conformance/edge-cases/loader-default-symbol/words.yaml new file mode 100644 index 000000000..0bef653bc --- /dev/null +++ b/conformance/edge-cases/loader-default-symbol/words.yaml @@ -0,0 +1,54 @@ +# Converted from conformance/loader/n2-default-symbol (v1, removed after the v1->v2 migration's +# parity proof). grammar.xml is the same file, unmodified. +# +# What this pins (from the v1 fixture's README.md/manifest.json): C# XmlLanguageLoader.LoadFeature +# reads SymbolicFeature@defaultSymbol into SymbolicFeature.DefaultSymbolID, consumed only when +# useDefaults=true (the four phonological-rule matchers set this) -- for a pattern-pinned feature a +# data node leaves UNSET, substitute the feature's default value and check THAT, instead of treating +# "unset" as vacuously compatible with anything. Feature "nas" here declares +# defaultSymbol="symNasPlus" (+); segment "a" carries no explicit "nas" value; rule "pr1" rewrites +# ncOral (nas=-) targets to ncLong (len=+). +# +# "bat" is the UseDefaults signal: "a"'s effective nas is the default (+), which fails ncOral's +# nas=- pin, so pr1 must NOT fire during the confirming synthesis and the surface stays "bat". A +# defaults-unaware matcher (the pre-fix Rust bug: unconstrained lane overlaps any pin) would instead +# fire the rule, mutate "a" (len=long, char-def identity cleared -> renders as "aa", the only +# len=Long segment), produce surface "baat" != "bat", and report "-" (no parse) where the correct +# behavior is "|bat". +# +# "bdt" is the control (expected zero parses in BOTH engines): "d" is explicitly nas=- (an explicit +# value, not a default fallback), so pr1 legitimately fires on it during the confirming synthesis in +# both engines, and the resynthesized surface is no longer "bdt" -- pins that UseDefaults handling +# does not over-suppress a rule whose pin is satisfied by an explicit value, proving the "bat" +# divergence above is really about defaultSymbol, not some other loader/matcher bug. + +language: N2-DefaultSymbol +inspired_by: ["synthetic loader-semantics probe (not modeling any real language)"] +sources: + - "rust/parity-out/audit/phase2/C-loader-parity.md (Phase-2 audit C finding N2)" +requires: [phonology] +words: + - word: bat + note: >- + The UseDefaults signal: middle segment "a" carries no explicit "nas" value, so its effective + nas (the feature's declared default, +) fails ncOral's nas=- pin -- pr1 (Lengthen oral + segment) must NOT fire, and the surface stays "bat" unmutated. + provenance: "Phase-2 audit C finding N2 (SymbolicFeature@defaultSymbol / UseDefaults)" + parses: + - signature: "|bat" + gloss: bat + rules: [] + exercises: + - "Boundary markers (CharacterDefinitionTable)" + + - word: bdt + note: >- + Control (expected zero parses in both engines): middle segment "d" is EXPLICITLY nas=- (not a + default fallback), so pr1 legitimately fires during the confirming synthesis, mutating "d" so + the resynthesized surface is no longer "bdt" -- proves the bat/UseDefaults divergence is + really about defaultSymbol, not some other loader/matcher bug. + provenance: "Phase-2 audit C finding N2 (SymbolicFeature@defaultSymbol / UseDefaults)" + expect_fail: true + blocked_by: [pr1] + exercises: + - "Boundary markers (CharacterDefinitionTable)" diff --git a/conformance/edge-cases/loader-isactive-breadth/grammar.xml b/conformance/edge-cases/loader-isactive-breadth/grammar.xml new file mode 100644 index 000000000..c84e89cc7 --- /dev/null +++ b/conformance/edge-cases/loader-isactive-breadth/grammar.xml @@ -0,0 +1,337 @@ + + + + + + IsActiveBreadth + + n + + + Live + Decoy + + + Live + + a + e + o + u + k + l + m + p + q + t + + z + + + + + = + + + + + Decoy + + z + + + + Any + Decoy + + + Live + Decoy + + + + Main + + + + livePrefix + + + + ta + + + + + mu + + + + + ot + + + TA + TA + + + + decoyPrefix + + + + pe + + + PE + PE + + + + ruleOnlyPrefix + + + + qo + + + QO + QO + + + + slotOnlyPrefix + + + + qe + + + QE + QE + + + + templateOnlyPrefix + + + + qu + + + QU + QU + + + + boundaryPrefix + + + + mo+ + + + MO + MO + + + + + liveTemplate + prefix + + decoySlot + + ruleOnlySlot + + slotOnlySlot + boundarySlot + + + + decoyTemplate + decoyTemplateSlot + + + + + + kul + + kol + + KUL + vessel + + isActive breadth probe + Properties and Property are loaded but never exercised elsewhere + + + + + + mep + + MEP + decoy + + + + + tup + + TUP + tupdecoy + + + + + put + + PUT + putdecoy + + + + + + DecoyStratum + + + + qot + + QOT + decoy + + + + + + TableDecoyStratum + + + + z + + ZD + zdecoy + + + + + + + + DecoyLanguage + + x + + + DecoyLang + + z + + + + + DecoyLangStratum + + + + diff --git a/conformance/edge-cases/loader-isactive-breadth/words.yaml b/conformance/edge-cases/loader-isactive-breadth/words.yaml new file mode 100644 index 000000000..d6faa05c1 --- /dev/null +++ b/conformance/edge-cases/loader-isactive-breadth/words.yaml @@ -0,0 +1,220 @@ +# isActive breadth probe. See grammar.xml's own header for the design: an inactive decoy alongside +# the live declaration for every loader collection XmlLanguageLoader filters through IsActive and +# that is reachable without a phonological feature system. +# +# Oracle: the C# founding oracle +# (conformance/adapters/hc-dotnet-wrapper.sh batch, over a Debug build of +# src/SIL.Machine.Morphology.HermitCrab.Tool). Every signature below is transcribed verbatim from +# that run, not hand-derived. Each negative control below was confirmed to produce no parse against +# that same run, so the fixture pins observed loader behavior rather than an assumption about it. +# +# SCOPE, stated plainly: eleven of the grammar's decoys are discriminated by a word here, and four +# (tableDecoy, ncDecoy, famDecoy, mprDecoy) are NOT and cannot be without breaking every other word's +# baseline; see grammar.xml's header for why (XmlLanguageLoader.cs resolves those four collections' +# IDREFs through a fail-fast Dictionary indexer, so the only way to make one of them matter is a live +# reference that would make the UNMUTATED grammar fail to load). "pekul" is a conjunction over mrDecoy +# and slotDecoy and does not separate those two call sites on its own; qokul/qekul do that +# independently via mrRuleOnly/mrSlotOnly. An explicit isActive="yes" writes the DTD's own default, +# which the loader supplies anyway, so it exercises the value appearing in a document, not a +# behavioural difference. +# +# Why this exists when edge-cases/loader-isactive already covers isActive: that fixture pins +# PhonologicalFeatureSystem only, and the loader has 25 separate .Where(IsActive) call sites. Covering +# one says nothing about the others, and a coarse "isActive is honored" claim would let 24 untested +# call sites inherit credit from the one that is tested. + +language: IsActiveBreadth +inspired_by: ["synthetic loader-semantics probe (not modeling any real language)"] +sources: + - "src/SIL.Machine.Morphology.HermitCrab/XmlLanguageLoader.cs IsActive call sites" +requires: [] +words: + - word: kul + note: >- + Bare live root. Proves the grammar loaded at all, which is itself the strongest single control + here: the document declares a second, inactive Language, and the loader selects the single + ACTIVE one, so a loader that ignored isActive would find two and fail to load anything. + provenance: "XmlLanguageLoader.cs Elements(\"Language\").Single(IsActive)" + neutralizes: + - DecoyLanguage + parses: + - signature: "KUL|kul" + rules: [] + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: takul + note: >- + Live prefix rule mrPfx through the live template's live, optional slot. The only affixed form + this grammar admits. + parses: + - signature: "TA+KUL|takul" + rules: [mrPfx] + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: tatakul + note: >- + Control for the template slot applying once: a doubled prefix is not a word. Verified against + the oracle with multipleApplication="2" set on the rule as well, where this word STILL does not + parse, because a rule reached through an AffixTemplate slot applies once per slot regardless. + That result is why the grammar writes NEITHER multipleApplication nor blockable: this fixture + cannot observe either, so both stay uncovered in the ledger instead of being claimed here. + expect_fail: true + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: tatatakul + note: Tripled prefix, the same bound from the other side. + expect_fail: true + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: mukul + note: >- + Negative control for MorphologicalSubrule@isActive. subPfxDecoy sits inside the LIVE rule mrPfx + and would prefix "mu", giving every stem a second analysis. + expect_fail: true + neutralizes: + - subPfxDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: pekul + note: >- + Negative control for MorphologicalRule@isActive and Slot@isActive together. mrDecoy would + prefix "pe" and is reachable only through the equally inactive decoySlot, so this word tests + both call sites at once and cannot leave a dangling IDREF either way. + expect_fail: true + blocked_by: [mrDecoy] + neutralizes: + - mrDecoy + - decoySlot + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: kol + note: >- + Negative control for Allomorph@isActive. aKolDecoy is an inactive allomorph of the LIVE entry + eKul, so the entry itself still loads and only this surface form should be rejected. + expect_fail: true + neutralizes: + - aKolDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: mep + note: Negative control for LexicalEntry@isActive. eMepDecoy would make "mep" an accepted root. + expect_fail: true + neutralizes: + - eMepDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: qot + note: >- + Negative control for Stratum@isActive. The inactive second stratum carries the root "qot", + which would be accepted if the stratum were loaded. + expect_fail: true + neutralizes: + - eQotDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: zal + note: >- + Negative control for SegmentDefinition@isActive. "z" is declared only by the inactive cZ, so + this word has no valid shape at all and is SKIPPED rather than merely unparsable, which is a + different and stronger outcome than the other controls. + expect_skip: true + neutralizes: + - cZ + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: qokul + note: >- + Negative control for MorphologicalRule@isActive, independent of Slot@isActive. mrRuleOnly would + prefix "qo" and is reachable only through ruleOnlySlot, which is itself ACTIVE (unlike + decoySlot), so this word isolates the rule's own isActive from the slot's. + expect_fail: true + blocked_by: [mrRuleOnly] + neutralizes: + - mrRuleOnly + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: qekul + note: >- + Negative control for Slot@isActive, independent of MorphologicalRule@isActive. mrSlotOnly is + itself ACTIVE (unlike mrDecoy) and would prefix "qe", but slotOnlySlot is the only route to it + and stays inactive here. + expect_fail: true + blocked_by: [mrSlotOnly] + neutralizes: + - slotOnlySlot + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: qukul + note: >- + Negative control for AffixTemplate@isActive. mrTemplateOnly is reachable ONLY through + decoyTemplate (never through liveTemplate, and never stratum-listed), so this discriminates the + template's own isActive rather than reusing mrPfx, whose duplicate result across two templates + collapses to one identical Word and would leave this surface Unobservable. + expect_fail: true + blocked_by: [mrTemplateOnly] + neutralizes: + - decoyTemplate + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: mo+kul + note: >- + Positive control for BoundaryDefinition@isActive="yes". mrBoundaryPfx's own output inserts the + live boundary character "+" itself, so deactivating bLive does not just fail to parse this + word: it fails to LOAD the grammar at all, because the rule's own PhoneticShape then names an + undefined phoneme. That is a genuine loader-level witness (CounterfactualVerdict.RequiredByLoader), + not the strictly weaker RequiredByDtd -- XmlLanguageLoader's own code has to run and fail here. + parses: + - signature: "MO+KUL|mo+?kul" + rules: [mrBoundaryPfx] + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: kul= + note: >- + Negative control for BoundaryDefinition@isActive="no". "=" is declared only by the inactive + bDecoy, so this word has no valid shape and is SKIPPED; activating bDecoy makes "=" a + recognized (if useless) character, changing the outcome to a tokenizable non-parse. + expect_skip: true + neutralizes: + - bDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: tup + note: >- + Joint control for Family@isActive="no". eTupDecoy is an inactive entry whose family names the + inactive famDecoy, so neither alone is observable: activating the family leaves nothing referencing + it, and activating the entry alone dangles its family reference and refuses to load. Only both + together admit this word. + expect_fail: true + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: put + note: >- + Joint control for MorphologicalPhonologicalRuleFeature@isActive="no", the same shape as tup: + ePutDecoy's ruleFeatures names the inactive mprDecoy. + expect_fail: true + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: otkul + note: >- + Joint control for FeatureNaturalClass@isActive="no". subNcDecoy is an inactive subrule whose + pattern names the inactive ncDecoy. + expect_fail: true + exercises: + - "Element deactivation (isActive) across loader collections" diff --git a/conformance/edge-cases/loader-isactive/grammar.xml b/conformance/edge-cases/loader-isactive/grammar.xml new file mode 100644 index 000000000..0b58d74ca --- /dev/null +++ b/conformance/edge-cases/loader-isactive/grammar.xml @@ -0,0 +1,138 @@ + + + + + N1-IsActive + + + Noun + + + + + + Voice + + + + - + + + + + SegId + + a + o + t + d + k + s + + + + + + Draft + + x + + + + + N1 Orthography + + + + a + + + + + + o + + + + + + t + + + + + + + d + + + + + + + k + + + + + + s + + + + + + + + + + + + + + + + Voiced + + + + + + main + + + + + kat + + + kat + + + + + sod + + + sod + + + + + + diff --git a/conformance/edge-cases/loader-isactive/words.yaml b/conformance/edge-cases/loader-isactive/words.yaml new file mode 100644 index 000000000..a6ca779c3 --- /dev/null +++ b/conformance/edge-cases/loader-isactive/words.yaml @@ -0,0 +1,38 @@ +# Converted from conformance/loader/n1-isactive (v1, removed after the v1->v2 migration's parity +# proof). grammar.xml is the same file, unmodified. +# +# What this pins (from the v1 fixture's README.md/manifest.json): C# XmlLanguageLoader.LoadLanguage +# selects the phonological feature system with +# Elements("PhonologicalFeatureSystem").SingleOrDefault(IsActive) (XmlLanguageLoader.cs:239) -- the +# one *active* block among the two grammar.xml declares. A loader that ignores isActive and takes +# the LAST block encountered instead would select the wrong (inactive, "junk"-only) block, and the +# NaturalClasses' FeatureValue feature="voi" reference would fail to resolve, failing to load the +# whole grammar. Both this grammar loading successfully AND its two words parsing to plain literal +# signatures (no char-def-set bracket notation, thanks to the "seg6" disambiguating feature) is what +# this fixture pins. + +language: N1-IsActive +inspired_by: ["synthetic loader-semantics probe (not modeling any real language)"] +sources: + - "rust/parity-out/audit/phase2/C-loader-parity.md (Phase-2 audit C finding N1)" +requires: [] +words: + - word: kat + note: Plain lexical root, no affixes -- proves the grammar loaded at all (the active PhonologicalFeatureSystem block's "voi" feature resolved) and that its signature renders as a plain literal string. + provenance: "Phase-2 audit C finding N1 (PhonologicalFeatureSystem@isActive)" + parses: + - signature: "|kat" + gloss: kat + rules: [] + exercises: + - "Boundary markers (CharacterDefinitionTable)" + + - word: sod + note: Second plain lexical root -- the same isActive-selection proof as "kat", from the language's other lexical entry. + provenance: "Phase-2 audit C finding N1 (PhonologicalFeatureSystem@isActive)" + parses: + - signature: "|sod" + gloss: sod + rules: [] + exercises: + - "Boundary markers (CharacterDefinitionTable)" diff --git a/conformance/edge-cases/loader-pattern-shapes/grammar.xml b/conformance/edge-cases/loader-pattern-shapes/grammar.xml new file mode 100644 index 000000000..3148e22db --- /dev/null +++ b/conformance/edge-cases/loader-pattern-shapes/grammar.xml @@ -0,0 +1,80 @@ + + + + + N3-PatternShapes + + + Noun + + + + N3 Orthography + + + + b + + + + + t + + + + + a + + + + + e + + + + + + + + Vowel + + + + + + + main + + + + + + b[Vowel]t + + + bVt + + + + + + b([Vowel])t + + + bt + + + + + + diff --git a/conformance/edge-cases/loader-pattern-shapes/words.yaml b/conformance/edge-cases/loader-pattern-shapes/words.yaml new file mode 100644 index 000000000..5d5269676 --- /dev/null +++ b/conformance/edge-cases/loader-pattern-shapes/words.yaml @@ -0,0 +1,89 @@ +# Converted from conformance/loader/n3-pattern-shapes (v1, removed after the v1->v2 migration's +# parity proof). grammar.xml is the same file, unmodified. +# +# What this pins (from the v1 fixture's README.md/manifest.json): C# +# CharacterDefinitionTable.GetShapeNodes(str, allowPattern, ...) has a pattern-language fallback +# active only when allowPattern=true: at any position where no literal character-definition +# substring matches, it additionally accepts "[NatClassName]" (bracketed natural-class reference, +# looked up by the class's text, not its XML id), "([NatClass])" (optional group), and +# "[NatClass]*" (Kleene star). Exactly one caller passes allowPattern=true: LoadRootAllomorph, i.e. +# plain lexicon root-allomorph shapes. This grammar's one lexical entry has PhoneticShape +# "b[Vowel]t": "b"/"t" match literally, "[Vowel]" doesn't match anything literally at that position, +# so it falls back to the Vowel natural class ({a, e}), giving signature "|b[ae]t" for any input that +# unifies against that pattern-derived shape node. +# +# Two-part status (carried from the v1 README, important context for any future Rust-adapter run +# against this fixture): the LOADER half (pinned here) is what N3 tests -- pre-fix, hc-grammar's +# load_root_allomorph had no pattern-language implementation at all and silently dropped the whole +# entry. The RUNTIME-MATCHING half (root_trie's CdSet-aware edge matching) is a documented, separate, +# NOT-yet-fixed follow-on gap in the Rust port (a pattern-derived trie edge born with NO_CHAR_DEF +# doesn't match a concrete query char_def) -- out of scope for this loader-semantics fixture, whose +# job is only to pin what the LOADER produces and what the ORACLE (C#) does with it. +# +# "bit": "i" is not declared anywhere in this grammar's CharacterDefinitionTable, so the C# oracle's +# own real status for this word is SKIPPED (InvalidShapeException), not "ok" with zero analyses -- +# v1's expected.tsv row is `2 bit 0 SKIPPED -`. This is the word's expect_skip: true below (as +# opposed to expect_fail, which is a genuine zero-parse "ok"). Both harness modes honour the +# distinction: self-check (RunnerV2.RunAllWords) confirms an InvalidShapeException actually fired, and +# adapter mode (FixtureMaterializer) materializes status "SKIPPED", so a conforming external adapter +# that reports SKIPPED for "bit" matches rather than registering a status mismatch. + +language: N3-PatternShapes +inspired_by: ["synthetic loader-semantics probe (not modeling any real language)"] +sources: + - "rust/parity-out/audit/phase2/C-loader-parity.md (Phase-2 audit C finding N3)" +requires: [] +words: + - word: bat + note: >- + "b[Vowel]t"'s pattern-derived middle position matches "a" -- the whole word unifies against + the one lexical entry's pattern-derived shape node, rendering as the char-def-set bracket + notation "[ae]" (both Vowel-class members), not the literal "a". + provenance: "Phase-2 audit C finding N3 (root-allomorph PhoneticShape pattern-language fallback)" + parses: + - signature: "|b[ae]t" + gloss: bVt + rules: [] + exercises: + - "Boundary markers (CharacterDefinitionTable)" + + - word: bet + note: >- + Same pattern-derived shape node as "bat", matched via its other Vowel-class member ("e") + instead -- proves the fallback is a genuine natural-class match, not a literal-string + coincidence limited to "a". + provenance: "Phase-2 audit C finding N3 (root-allomorph PhoneticShape pattern-language fallback)" + parses: + - signature: "|b[ae]t" + gloss: bVt + rules: [] + exercises: + - "Boundary markers (CharacterDefinitionTable)" + + - word: bit + note: >- + "i" is not declared anywhere in this grammar's CharacterDefinitionTable at all, so the oracle's + real status is SKIPPED (InvalidShapeException), not a genuine zero-parse "ok" -- hence + expect_skip, not expect_fail. Self-check confirms the InvalidShapeException actually fires; + adapter mode materializes status "SKIPPED" (v1's expected.tsv row was "2 bit 0 SKIPPED -"), so + an adapter that legitimately reports SKIPPED matches instead of registering a status mismatch. + provenance: "Phase-2 audit C finding N3 (root-allomorph PhoneticShape pattern-language fallback)" + expect_skip: true + exercises: + - "Boundary markers (CharacterDefinitionTable)" + + - word: bt + note: >- + G5 (code-coverage-driven): the second lexical entry's pattern "b([Vowel])t" makes the middle + position OPTIONAL in the LOADER's shape (the one CharacterDefinitionTable.GetShapeNodes + pattern-language branch N3 didn't already cover -- the loader itself runs this branch and + builds the optional-annotated shape node regardless of what happens next, so the loader code + is exercised either way). Reconciliation finding: at RUNTIME, root-allomorph analysis + matching does not actually honor the shape node's Optional annotation the way a phonological + environment match does -- "bt" gets zero parses rather than matching with the vowel position + skipped. Pinned as the real, verified oracle behavior, not the hand-derivation's original + guess (a genuine engine finding, not a fixture bug). + provenance: "G5 coverage sweep, CharacterDefinitionTable.GetShapeNodes optional-group '(...)' branch" + expect_fail: true + exercises: + - "CharacterDefinitionTable pattern shapes: optional group / Kleene star" diff --git a/conformance/edge-cases/metathesis-comparison-crash/grammar.xml b/conformance/edge-cases/metathesis-comparison-crash/grammar.xml new file mode 100644 index 000000000..c0a5ef4d2 --- /dev/null +++ b/conformance/edge-cases/metathesis-comparison-crash/grammar.xml @@ -0,0 +1,76 @@ + + + + + + MetathesisComparisonCrash + n + + + cons + + +cons + -cons + + + + + Main + + + t + + + + i + + + + + + tOnly + iOnly + + + + swapRightToLeft + + + + + + + + + + + + + Main + + + ti + TI + ti + + + + + + diff --git a/conformance/edge-cases/metathesis-comparison-crash/words.yaml b/conformance/edge-cases/metathesis-comparison-crash/words.yaml new file mode 100644 index 000000000..c66be2ae3 --- /dev/null +++ b/conformance/edge-cases/metathesis-comparison-crash/words.yaml @@ -0,0 +1,30 @@ +# Regression pin, not a coverage fixture. See grammar.xml's header. +# +# The C# engine used to throw System.InvalidOperationException "Failed to compare two elements in the +# array", inner System.ArgumentException "Only nodes from the same list can be compared", while +# analysing a word against a MetathesisRule whose leftSwitch names the EARLIER of its two pattern +# groups -- an internal invariant violation. Fixed upstream by sillsdev/machine#471, so the crash +# expectation is gone: this fixture now pins that the engine completes the analysis without throwing +# and reports no analysis for the word. +# +# Oracle: the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over a Debug build of +# src/SIL.Machine.Morphology.HermitCrab.Tool). Reduced from edge-cases/feature-system-breadth, where +# adding a root containing the swap pair turned a passing fixture into this crash. +# +# It claims no coverage of its own; everything it declares is covered with real evidence in +# edge-cases/feature-system-breadth. + +language: MetathesisComparisonCrash +inspired_by: ["synthetic metathesis-ordering crash reduction (not modeling any real language)"] +sources: + - "reduced from conformance/edge-cases/feature-system-breadth while covering MetathesisRule@multipleApplicationOrder" +requires: [phonology] +words: + - word: ti + note: >- + The root's own shape. Analysing it against the rightToLeftIterative swap is what used to trip the + comparison invariant; the swapped form "it" never did. Post-#471 the analysis completes and + yields nothing, which is the correct answer -- no rule derives "ti" from this lexicon. + expect_fail: true + exercises: + - "MetathesisRule" diff --git a/conformance/edge-cases/morphotactic-attribute-breadth/grammar.xml b/conformance/edge-cases/morphotactic-attribute-breadth/grammar.xml new file mode 100644 index 000000000..ec1feb093 --- /dev/null +++ b/conformance/edge-cases/morphotactic-attribute-breadth/grammar.xml @@ -0,0 +1,458 @@ + + + + + + MorphotacticAttributeBreadth + + n + + + xvA + + + A + B + + ExclFlag + + + appendGroup + + + + groupDecoy + + + + Main + + a + e + i + o + u + b + d + g + k + l + m + n + p + r + s + t + + + + Any + + + Blk + Blk3 + + + + + Main + + + + neverApplies + + + + ba + + + NEVER + never + + + + twiceAtMost + + + + de + + + TWICE + twice + + + nfOnly + + + + pu + + + NF + nf + + + + unblockable + + + + gi + + + + UNBLK + unblk + + + + partialRule + + + + mo + + + PART + part + + + + realUnblockable + + + + ru + + + REAL + real + + + realDecoy + + + + si + + + RDEC + rdec + + + + coA + + + + sa + + + COA + coa + + + coB + + + + ka + + + COB + cob + + + coC + + + + ta + + + COC + coc + + + coD + + + + na + + + COD + cod + + + + setMB + + + + bu + + + MB + mb + + + setMA + + + + bi + + + MA + ma + + + reqMB + + + + du + + + MREQ + mreq + + + + conferExcl + + + + do + + + CONFEREXCL + conferexcl + + + exclReader + + + + ri + + + EXCLREADER + exclreader + + + + + + finalTemplate + unblockableSlot + partialSlot + realSlot + realDecoySlot + coASlot + coBSlot + coCSlot + coDSlot + mbSlot + maSlot + mreqSlot + + + + nonFinalTemplate + nonFinalSlot + + + + + + kul + + kur + + KUL + vessel + + + + + nap + + NAP + stone + + + + sol + + SOL + rope + + + + bak + + VAK + bak + + + + dom + + + ZOM + dom + + + + sim + + + SIM + sim + + + + rog + + + ROG + rog + + + + top + + TOP + top + + + + + + Second + + + pogAffix + + + + li + + + POGAFX + pogafx + + + + afterFinal + + + + ti + + + PO + po + + + + + pogTemplate + pogSlot + + + + + + pog + + POG + pog + + + + + + + + + + + + + + + + + + + + + diff --git a/conformance/edge-cases/morphotactic-attribute-breadth/words.yaml b/conformance/edge-cases/morphotactic-attribute-breadth/words.yaml new file mode 100644 index 000000000..d53e5af9e --- /dev/null +++ b/conformance/edge-cases/morphotactic-attribute-breadth/words.yaml @@ -0,0 +1,410 @@ +# Morphotactic attribute breadth. See grammar.xml's header for the design. +# +# Oracle: the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over a Debug build +# of src/SIL.Machine.Morphology.HermitCrab.Tool). Every signature is transcribed from that run. +# +# What each negative control isolates: +# kulba multipleApplication="0" on mrRep0: the cap is zero, so the suffix never attaches. +# kuldedede multipleApplication="2" on mrRep2: a third copy exceeds the cap. +# kulsi RealizationalRule@isActive="no" on mrRealDecoy. +# kur Allomorph@isBound="true" on aKulBound: a bound form is not a free word. +# sol AllomorphCoOccurrenceRule@type="require": aSol requires aNap somewhereToLeft, and no +# word here supplies one, so the bare root is refused. This is the only co-occurrence +# rule in the fixture where aSol/aNap are the roots involved. +# napmo LexicalEntry@partial="true" on eNap: a partial root never matches ANY AffixTemplate +# (SynthesisAffixTemplatesRule.cs gates the whole template loop on +# !input.RootAllomorph.Morpheme.IsPartial), so mrPartial (reachable only through a +# template slot) can never attach to it, even though the identical suffix attaches to +# a non-partial root (kulmo). +# kulpu AffixTemplate@final="false" on nonFinalTemplate: mrNF is reachable ONLY through that +# template's own slot (never stratum-listed, never in finalTemplate), so its output can +# never be the end of a derivation while the template itself is non-final. +# +# mrReal appears in almost every traced rule list, including for the bare root, while contributing no +# morpheme to any signature. A realizational rule is traced as applied even when it realizes nothing, +# so the lists below are the oracle's, not a tidied version of them. +# +# The blocking pair (mrUnblockable/mrReal, blockable="false") needed a genuinely competing, MORE +# SPECIFIC form to be observable at all: bakgi/simru each use a dedicated root (family famBlk/famBlk3) +# with a suppletive sibling (dom/rog) whose own AssignedHeadFeatures matches what the blockable rule's +# output would assign, so Word.CheckBlocking has something to substitute in when blockable="true" is +# tried as the counterfactual. eKul/eNap/eSol carry no family, so blocking can never fire on kulgi +# itself (family==null short-circuits Word.CheckBlocking) is deliberate isolation, not an +# oversight: it keeps the repetition/co-occurrence controls above from ever being touched by a change +# to the blocking construct. +# +# The co-occurrence and MPR-feature-group constructs (topsakatana, kulbubidu) are on their own +# isolated roots/rules (mrCoA-D, mrMB/mrMA/mrMReq) for the same reason: none of them share a rule ID +# with anything the repetition/blocking/partial controls above touch, so mutating one surface's value +# can never accidentally break a DIFFERENT surface's own word. +# +# pog/pogli/pogti/pogliti live in grammar.xml's own second, Unordered stratum (Second), not Main: +# MorphologicalRule@partial="true" on mrPO only matters for a rule reached AFTER a final template +# already applied (SynthesisAffixProcessRule.cs's NonPartialRuleProhibitedAfterFinalTemplate check), +# and that ordering is only reachable via Unordered's ApplyTemplates -> ApplyMorphologicalRules +# recursion in SynthesisStratumRule.cs, never on Main, which is deliberately Linear (see its own +# comment). pogliti is the only string reachable through that exact order (template's own slot filled +# with "li", THEN the stratum-level "ti" appended): mrPO applying first instead would produce +# "pogtili", a different string, so there is no other path that could produce "pogliti" and make this +# a false control. +# +# NOT EVIDENCEABLE, and not for lack of trying: Stratum@cyclicity="cyclic" and +# Stratum@phonologicalRuleOrder="simultaneous" (both declared on Main, non-default, purely for the +# enumerated value's presence in a document). Neither attribute is read anywhere by +# XmlLanguageLoader.cs beyond the DTD-default parse itself, and Stratum.cs carries no corresponding +# property at all (only MorphologicalRuleOrder exists on the class), confirmed by grepping the whole +# of src/SIL.Machine.Morphology.HermitCrab for "Cyclicity" and "PhonologicalRuleOrder" as C# identifiers +# and finding zero hits outside the DTD text and this loader's own unread attribute string. No grammar +# shape, phonological or otherwise, can make an attribute the engine never consults observable (see +# conformance/README.md's exception-surfaces list, "Cyclic strata and simultaneous rule order"). + +language: MorphotacticAttributeBreadth +inspired_by: ["synthetic morphotactic-attribute probe (not modeling any real language)"] +sources: + - "conformance/semantic-coverage-baseline.txt morphotactic todo entries" +requires: [] +words: + # Bucket-2 coverage (MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures): + # placed FIRST in file order deliberately, and the distinguishing (baseline-fail) word placed + # before its own control, for the same reason suffixing-extension-slot-ordering's own bucket-2 + # words are ordered this way -- severing MorphologicalOutput.MPRFeatures fixture-wide ALSO affects + # mrMB/mrMA/mrMReq's own appendGroup interaction elsewhere in this file, and InterfaceWitnessLedger + # reports the FIRST word (in file order) whose outcome differs, not the first favorable one. + - word: topdori + note: >- + THE distinguishing row: TOP + mrConferExcl ("-do") + mrExclReader ("-ri"). mrConferExcl's own + MorphologicalOutput MPRFeatures="mprExclFlag" write is exactly what mrExclReader's + MorphologicalInput.excludedMPRFeatures="mprExclFlag" excludes, so mrExclReader can never apply + once mrConferExcl has -- zero parses. Removing either mrConferExcl's own + MorphologicalOutput.MPRFeatures write (the writer, so the exclusion is vacuously satisfied) or + mrExclReader's own excludedMPRFeatures (the reader, so there is no exclusion left to trip) + unblocks it independently, to the identical successful parse. topdo (below) is the control + showing mrConferExcl attaches normally on its own. + expect_fail: true + blocked_by: [mrExclReader] + claimed_cells: + - cell: "MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm" + severing: >- + either mrConferExcl's own MorphologicalOutput.MPRFeatures="mprExclFlag" write (the writer) + or mrExclReader's own MorphologicalInput.excludedMPRFeatures="mprExclFlag" gate (the + reader) -- severing either alone unblocks this word + before: "ok::-" + after: "ok::TOP+CONFEREXCL+EXCLREADER|topdori" + distinct_from: topdo + proof: >- + topdori is TOP run through mrConferExcl (which confers mprExclFlag) then attempting + mrExclReader; with both constructs intact the exclusion blocks it, so this has zero parses. + Removing either the writer (mrConferExcl's own MorphologicalOutput.MPRFeatures) or the + reader (mrExclReader's excludedMPRFeatures) lets mrExclReader apply anyway, producing + TOP+CONFEREXCL+EXCLREADER|topdori -- the PresentGatedForm arm: the feature is PRESENT + (conferred by mrConferExcl, never a lexical property of TOP itself) and mrExclReader's + exclusion GATES on it. + + - word: topdo + note: TOP + mrConferExcl ("-do") alone -- the control for topdori (above), showing mrConferExcl attaches normally. + parses: + - signature: "TOP+CONFEREXCL|topdo" + rules: [mrReal, mrConferExcl] + + - word: topri + note: TOP + mrExclReader ("-ri") alone, no mrConferExcl -- TOP carries no mprExclFlag on its own, so mrExclReader's exclusion is vacuously satisfied. + parses: + - signature: "TOP+EXCLREADER|topri" + rules: [mrReal, mrExclReader] + + - word: kul + note: Bare free root. The control that the grammar loads and admits a complete word at all. + parses: + - signature: "KUL|kul" + rules: [mrReal] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kulde + note: mrRep2 applied once, well inside its cap of two. + parses: + - signature: "KUL+TWICE|kulde" + rules: [mrReal, mrRep2] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kuldede + note: >- + mrRep2 applied twice, exactly at its cap. The morpheme id appears once in the signature even + though the rule applied twice; that is the oracle's own rendering, transcribed as-is. + parses: + - signature: "KUL+TWICE|kuldede" + rules: [mrReal, mrRep2] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kuldedede + note: Three copies exceed multipleApplication="2". The upper boundary of the cap. + expect_fail: true + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kulba + note: >- + mrRep0 carries multipleApplication="0", so its suffix can never attach and this word has no + analysis. The lower boundary of the cap, and the only evidence mrRep0 can ever have: a rule + capped at zero applications cannot appear in any traced rule list. + expect_fail: true + blocked_by: [mrRep0] + neutralizes: + - mrRep0 + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kulgi + note: mrUnblockable carries blockable="false" and sets an MPR feature through the append group. + parses: + - signature: "KUL+UNBLK|kulgi" + rules: [mrReal, mrUnblockable] + exercises: + - "MPR features/groups" + + - word: kulmo + note: mrPartial carries partial="true", reached through finalTemplate's own slot. + parses: + - signature: "KUL+PART|kulmo" + rules: [mrPartial, mrReal] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kulru + note: mrReal is a RealizationalRule with blockable="false". + parses: + - signature: "KUL+REAL|kulru" + rules: [mrReal] + exercises: + - "RealizationalAffixProcessRule" + + - word: kulsi + note: Negative control for RealizationalRule@isActive="no". mrRealDecoy would suffix "si". + expect_fail: true + blocked_by: [mrRealDecoy] + neutralizes: + - mrRealDecoy + exercises: + - "Element deactivation (isActive) across loader collections" + + - word: nap + note: eNap carries partial="true" and still parses as a free root (no template involved at all). + parses: + - signature: "NAP|nap" + rules: [] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: napmo + note: >- + Negative control for LexicalEntry@partial="true". mrPartial attaches to kul (kulmo) but never to + nap: a partial root is gated out of SynthesisAffixTemplatesRule's whole template loop before any + individual slot is even considered, so the identical suffix has no route to this root at all. + expect_fail: true + neutralizes: + - eNap + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: sol + note: >- + Negative control for AllomorphCoOccurrenceRule@type="require". aSol requires aNap somewhereToLeft; + nothing here can supply one, so the bare root is refused even though it is a declared allomorph. + expect_fail: true + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: kur + note: Negative control for Allomorph@isBound="true". aKulBound is not a free word. + expect_fail: true + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: kulpu + note: >- + Negative control for AffixTemplate@final="false". mrNF is reachable only through + nonFinalTemplate's own slot, and that template's output cannot be a complete word on its own. + expect_fail: true + blocked_by: [mrNF] + neutralizes: + - nonFinalTemplate + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: bak + note: >- + Bare root for the MorphologicalRule@blockable="false" control, in its own family (famBlk) so + blocking never touches the repetition/co-occurrence controls above. + parses: + - signature: "VAK|bak" + rules: [mrReal] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: dom + note: >- + Suppletive sibling of bak (family famBlk), lexically assigned the same head feature mrUnblockable + would assign to bak, the "more specific competing form" a blocking check substitutes in. + parses: + - signature: "ZOM|dom" + rules: [mrReal] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: bakgi + note: >- + mrUnblockable applied to bak. blockable="false" keeps this UNBLOCKED even though bak has a + family sibling (dom) whose own assigned features match what mrUnblockable's OutputHeadFeatures + would assign, the competing form Word.CheckBlocking would substitute in if blockable were true. + parses: + - signature: "VAK+UNBLK|bakgi" + rules: [mrReal, mrUnblockable] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: sim + note: >- + Bare root for the RealizationalRule@blockable="false" control, in its own family (famBlk3), + lexically assigned the same head feature its sibling rog carries. + parses: + - signature: "SIM|sim" + rules: [mrReal] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: rog + note: Suppletive sibling of sim (family famBlk3), the competing form for the RealizationalRule control. + parses: + - signature: "ROG|rog" + rules: [mrReal] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: simru + note: mrReal applied to sim. blockable="false" keeps this unblocked despite sim's sibling rog. + parses: + - signature: "SIM+REAL|simru" + rules: [mrReal] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: top + note: >- + Bare root for the co-occurrence and MPR-feature-group controls below, isolated from every other + construct in this fixture (no family, no shared rule IDs). + parses: + - signature: "TOP|top" + rules: [mrReal] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: topsakatana + note: >- + top + mrCoA/mrCoB/mrCoC/mrCoD, in that order. Positive control for the four non-default + AllomorphCoOccurrenceRule adjacency values (each keyed on a different one of COA-D so all four + requirements hold on the SAME word at once), MorphemeCoOccurrenceRule@adjacency="anywhere", and + both rule collections' isActive="no" decoys (exclude pairs that would invalidate this word if + activated). + parses: + - signature: "TOP+COA+COB+COC+COD|topsakatana" + rules: [mrCoA, mrCoB, mrCoC, mrCoD, mrReal] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: kulbubidu + note: >- + kul + mrMB (sets mprB) + mrMA (sets mprA) + mrMReq (requires mprB still present). Under + appendGroup's outputType="append", setting mprA does not evict mprB, so mrMReq succeeds; + MorphologicalPhonologicalRuleFeatureGroup@outputType="append" and @isActive="no" (groupDecoy, + which claims the SAME two features and hijacks their group membership when activated) both fail + this word the same way if neutralized. + parses: + - signature: "KUL+MB+MA+MREQ|kulbubidu" + rules: [mrMB, mrMA, mrMReq, mrReal] + exercises: + - "MPR features/groups" + + - word: pog + note: >- + Bare root of the second (Unordered) stratum, used for the MorphologicalRule@partial="true" + control below. + parses: + - signature: "POG|pog" + rules: [] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: pogli + note: pogTemplate's own slot (mrPogAffix) filled, template-final. + parses: + - signature: "POG+POGAFX|pogli" + rules: [mrPogAffix] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: pogti + note: >- + mrPO applied directly to the bare root (never through a template first), which is why this + string is "ti" appended once, not "li" then "ti". + parses: + - signature: "POG+PO|pogti" + rules: [mrPO] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: pogliti + note: >- + Positive control for MorphologicalRule@partial="true". pogTemplate applies first (its slot + filled with "li"), setting IsLastAppliedRuleFinal=true; mrPO then applies AFTER that final + template only because mrPO itself is partial="true" + (SynthesisAffixProcessRule.cs's NonPartialRuleProhibitedAfterFinalTemplate check exempts a + partial rule). No other derivation order can produce this exact string: mrPO applying before + pogTemplate gives "pogtili", not "pogliti". + parses: + - signature: "POG+POGAFX+PO|pogliti" + rules: [mrPO, mrPogAffix] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: kulgimo + note: >- + Ordering discriminator for finalTemplate's unblockableSlot~partialSlot adjacent pair. Carries + both mrUnblockable's "gi" and mrPartial's "mo" in declared slot order. Confirmed against a + hand-built mutant with the two Slot elements transposed: this exact string fails to parse under + the swap (baseline ok::KUL+UNBLK+PART|kulgimo -> swapped ok::-), and the reversed-affix form + "kulmogi" fails baseline but parses under the swap, so the pair is evidenced in both directions. + parses: + - signature: "KUL+UNBLK+PART|kulgimo" + rules: [mrPartial, mrReal, mrUnblockable] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: kulmoru + note: >- + Ordering discriminator for finalTemplate's partialSlot~realSlot adjacent pair. Carries both + mrPartial's "mo" and mrReal's "ru" in declared slot order. Confirmed against a hand-built mutant + with the two Slot elements transposed: this exact string fails to parse under the swap (baseline + ok::KUL+PART+REAL|kulmoru -> swapped ok::-), and the reversed-affix form "kulrumo" fails baseline + but parses under the swap, so the pair is evidenced in both directions. + parses: + - signature: "KUL+PART+REAL|kulmoru" + rules: [mrPartial, mrReal] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: topsakanabu + note: >- + Ordering discriminator for finalTemplate's coDSlot~mbSlot adjacent pair. top + mrCoA/mrCoB/mrCoD + (coCSlot skipped; its co-occurrence rules are not needed to satisfy coD's own requirements) + + mrMB, with coDSlot immediately before mbSlot in declared order. Confirmed against a hand-built + mutant with the two Slot elements transposed: this exact string fails to parse under the swap + (baseline ok::TOP+COA+COB+COD+MB|topsakanabu -> swapped ok::-), and the reversed-affix form + "topsakabuna" fails baseline but parses under the swap, so the pair is evidenced in both + directions. + parses: + - signature: "TOP+COA+COB+COD+MB|topsakanabu" + rules: [mrCoA, mrCoB, mrCoD, mrMB, mrReal] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" diff --git a/conformance/edge-cases/mpr-gated-exception/grammar.xml b/conformance/edge-cases/mpr-gated-exception/grammar.xml new file mode 100644 index 000000000..b8982e327 --- /dev/null +++ b/conformance/edge-cases/mpr-gated-exception/grammar.xml @@ -0,0 +1,292 @@ + + + + + Ranavu + + + vNasalDemo + vMprDemo + + + cons+- + voc+- + voice+- + nasal+- + + place + + bilabial + alveolar + lateral + velar + sibilant + labiodental + dentalD + other + vocalic + + + + highhighmidlowna + backfrontbackna + + + Exception + + AffixDelExcl + + + Main + + + a + + + + + + e + + + + + + i + + + + + + u + + + + + + o + + + + + + + N + + + + + + m + + + + + + n + + + + + + t + + + + + + b + + + + + + l + + + + + + k + + + + + + s + + + + + + v + + + + + + d + + + + + + + + + Any + NasalPlaceholder + Bilabial + + + Alveolar + + + VoicelessObstruent + + + Nasal + + + + + + + nasalAssimBilabial + + + + + + + + + + + + nasalAssimAlveolar + + + + + + + + + + + + + obstruentDeletion + + + + + + + + + + + + + + + Main + + + nPfx + + + + meN + + + NPFX + + + + suf + + + + an + + + SUF + + + + sufAlt + + + + i + + + SUFALT + + + + delExclSrc + + + + am + + + DELEXCLSRC + + + + + + tulik + TULIK + carve + + + + balo + BALO + gather + + + + + tanuk + TANUK + weave + + + + sanit + SANIT + root.sanit + + + + vokad + VOKAD + root.vokad + + + + + + + diff --git a/conformance/edge-cases/mpr-gated-exception/words.yaml b/conformance/edge-cases/mpr-gated-exception/words.yaml new file mode 100644 index 000000000..cff68c233 --- /dev/null +++ b/conformance/edge-cases/mpr-gated-exception/words.yaml @@ -0,0 +1,188 @@ +# agglutinative-Austronesian reference corpus's pathology mimic -- see STAGING.md and grammar.xml's +# own header comment. Originally authored and verified against PanGloss's Rust engine only +# (`pg_parse::Morpher`, driven directly -- see STAGING.md's "Verification" section); signatures were +# transcribed verbatim from that run, not hand-derived. Since then also verified against this repo's +# own C# HermitCrab engine (the founding oracle): every signature, every parse's traced `rules:` +# list, and the `vokadan` expect_fail all hold under self-check mode +# (ConformanceFixtureGateTests.EveryConformanceFixturePassesSelfCheck / `hc-conformance --fixtures +# conformance`, in-process XmlLanguageLoader + Morpher, no divergence found). +# +# Authoring note: an early draft gave every vowel (a/e/i/u/o) and several consonants (l/k/s/v/d) an +# IDENTICAL feature bundle (only `featPlace=vocalic`/`fPlaceOther` respectively distinguished them +# from other classes, not from each other) -- `pg_parse`'s own shape-rendering correctly collapsed +# feature-identical segments into a bracketed alternates class (e.g. "t[aeiuo][lvd][aeiuo][ks]" +# instead of the literal "tulik"), obscuring the actual pin. Fixed by giving every segment a fully +# unique feature bundle (featHigh/featBack added for the vowels; featPlace values split apart for the +# consonants) -- see grammar.xml's own PhonologicalFeatureSystem comment. Every signature below is +# now literal. + +language: Ranavu +inspired_by: ["synthetic agglutinative-Austronesian nasal-assimilation/deletion + MPR-exclusion probe (not modeling any real language)"] +sources: + - "docs/conformance-staging-plan.md pathology catalog (agglutinative-Austronesian row)" +requires: [phonology] +words: + - word: tulik + note: TULIK bare root, no prefix -- a plain control. + parses: + - signature: "TULIK|tulik" + rules: [] + + - word: menulik + note: >- + TULIK + mrNPfx: underlying "meN+tulik" -- the placeholder nasal assimilates to alveolar "n" + (prNasalAssimAlveolar, root-initial "t" is alveolar), then the now-real "n" triggers + prObstruentDeletion on the following VOICELESS obstruent "t" -- "mentulik" -> "menulik". The + deletion-junction model behind that agglutinative-Austronesian reference corpus's own + meN+tulis -> menulis. + provenance: "docs/conformance-staging-plan.md pathology catalog (agglutinative-Austronesian row): placeholder-nasal assimilation + junction deletion" + parses: + - signature: "NPFX+TULIK|menulik" + rules: [mrNPfx, prNasalAssimAlveolar, prObstruentDeletion] + # LeftToRightRewrite (constructs.txt row 29): prNasalAssimAlveolar/prObstruentDeletion both + # carry no multipleApplicationOrder attribute, so pg-grammar's own loader + # (load_rewrite_rule, rust/crates/pg-grammar/src/load.rs) gives each Dir::LeftToRight by + # default -- and this word is the fixture's strongest positive witness: BOTH rules actually + # fire in sequence (assimilation then deletion) to produce this surface form, not merely + # present-but-unused. Previously untagged -- constructs.txt had no row for this + # characteristic until G9 (sillsdev/machine PR #465) added row 29. + exercises: + - "RewriteRule direction (Dir): left-to-right" + + - word: balo + note: BALO bare root -- a plain control. + parses: + - signature: "BALO|balo" + rules: [] + + - word: membalo + note: >- + BALO + mrNPfx: underlying "meN+balo" -- the placeholder nasal assimilates to bilabial "m" + (prNasalAssimBilabial, root-initial "b" is bilabial); "b" is VOICED, not in the + VoicelessObstruent class, so prObstruentDeletion does NOT fire and "b" survives -- + "membalo", not "memalo". The contrasting (non-deleting) half of the deletion-junction pair. + provenance: "docs/conformance-staging-plan.md pathology catalog (agglutinative-Austronesian row): placeholder-nasal assimilation + junction deletion" + parses: + - signature: "NPFX+BALO|membalo" + rules: [mrNPfx, prNasalAssimBilabial] + + - word: sanit + note: SANIT bare root, no MPR feature -- a plain control for the MPR-exclusion pair below. + parses: + - signature: "SANIT|sanit" + rules: [] + + - word: sanitan + note: SANIT + mrSuf ("-an") -- no MPR feature on this root, so mrSuf's excludedMPRFeatures="mprException" gate is vacuously satisfied and the rule applies normally. + provenance: "docs/conformance-staging-plan.md pathology catalog (agglutinative-Austronesian row): MPR-gated rule exception (control)" + parses: + - signature: "SANIT+SUF|sanitan" + rules: [mrSuf] + + - word: vokad + note: VOKAD bare root (carries ruleFeatures="mprException") -- a plain control. + parses: + - signature: "VOKAD|vokad" + rules: [] + + - word: vokadan + note: >- + THE distinguishing row: VOKAD carries mprException, and mrSuf's MorphologicalInput excludes + exactly that feature (excludedMPRFeatures="mprException") -- so "vokadan" (VOKAD + mrSuf) has + NO valid derivation. An engine that ignores excludedMPRFeatures would wrongly accept this -- + the P6 flag-diacritics recall case in miniature (a corpus word's correct parse REQUIRES the + exclusion to be honored). + provenance: "docs/conformance-staging-plan.md pathology catalog (agglutinative-Austronesian row): MPR-gated rule exception" + expect_fail: true + blocked_by: [mrSuf] + # Claims the McDc:PresentGatedForm cell of conformance/dataflow-obligations.tsv's obligation matrix. + # DataflowClaimGate checks this against conformance/dataflow-obligations.tsv, never trusts it, + # and recomputes severing/before/after by re-severing the writer and reader named in the ledger + # row -- the inline values below are what it recomputed against, not what it trusts blindly. + claimed_cells: + - cell: "MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm" + severing: >- + either VOKAD's LexicalEntry.ruleFeatures="mprException" (the writer) or mrSuf's + MorphologicalInput.excludedMPRFeatures="mprException" gate (the reader) -- severing + either alone unblocks this word + before: "ok::-" + after: "ok::VOKAD+SUF|vokadan" + distinct_from: sanitan + proof: >- + vokadan is VOKAD (carries mprException) + mrSuf; with both constructs intact the + derivation is blocked (ok::-). Removing either the writer (VOKAD's ruleFeatures) or the + reader (mrSuf's excludedMPRFeatures) lets the same derivation through, producing + VOKAD+SUF|vokadan -- the PresentGatedForm arm: the feature is PRESENT on the root and the + rule's exclusion GATES on it. sanitan (SANIT, no mprException) is the plain control that + shows mrSuf fires normally when the feature is simply absent, so vokadan's block is + attributable to the gate, not to mrSuf never applying at all. + + - word: vokadi + note: >- + VOKAD's actual correct derived form: mrSufAlt ("-i") carries no MPR gate at all, so it is + the ONLY rule an mprException root can undergo -- the exception-honoring positive control + that pairs with vokadan's negative one. + provenance: "docs/conformance-staging-plan.md pathology catalog (agglutinative-Austronesian row): MPR-gated rule exception" + parses: + - signature: "VOKAD+SUFALT|vokadi" + rules: [mrSufAlt] + + - word: menanukam + note: >- + THE distinguishing row for MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures: + TANUK + mrNPfx + mrDelExclSrc, with the obstruent DELETED ("menanukam" instead of + "mentanukam"). With both constructs intact, mrDelExclSrc's own MPR write triggers + prObstruentDeletion's excludedMPRFeatures="mprAffixDelExcl" gate and blocks the deletion, so + this surface has zero parses even though the nasal+voiceless-obstruent environment + (prNasalAssimAlveolar having already run) is otherwise identical to menulik's own deleting + case. Removing either mrDelExclSrc's own MorphologicalOutput.MPRFeatures write (so the + exclusion-triggering write never happens) or prObstruentDeletion's own excludedMPRFeatures (so + the gate no longer needs mprAffixDelExcl at all) unblocks it independently, to the identical + successful (deleting) parse -- the same word, from two unrelated severances. mentanukam + (below) is the control showing the affix combination is otherwise well-formed. Placed AHEAD of + mentanukam deliberately: severing either construct ALSO flips mentanukam (pass->fail), and the + sweep reports whichever word differs FIRST in file order, so menanukam has to sit earlier than + mentanukam for its own fail->pass flip to be the one reported. + expect_fail: true + blocked_by: [prObstruentDeletion] + claimed_cells: + - cell: "MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm" + severing: >- + either mrDelExclSrc's own MorphologicalOutput.MPRFeatures="mprAffixDelExcl" write (the + writer) or prObstruentDeletion's own PhonologicalSubrule.excludedMPRFeatures="mprAffixDelExcl" + gate (the reader) -- severing either alone unblocks this word + before: "ok::-" + after: "ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam" + distinct_from: mentanukam + proof: >- + menanukam is TANUK run through mrNPfx and mrDelExclSrc (which confers mprAffixDelExcl) then + attempting prObstruentDeletion; with both constructs intact the deletion is blocked (zero + parses for the deleted surface). Removing either the writer (mrDelExclSrc's own + MorphologicalOutput.MPRFeatures) or the reader (prObstruentDeletion's excludedMPRFeatures) + lets the deletion through, producing NPFX+TANUK+DELEXCLSRC|menanukam -- the PresentGatedForm + arm: the feature is PRESENT (conferred by the affix, never by TANUK's own declaration) and + the rule's exclusion GATES on it. + + - word: mentanukam + note: >- + TANUK + mrNPfx + mrDelExclSrc ("-am"): underlying "meN+tanuk+am" -- the placeholder nasal + assimilates to alveolar "n" (prNasalAssimAlveolar, root-initial "t" is alveolar), but + mrDelExclSrc's own MorphologicalOutput MPRFeatures="mprAffixDelExcl" write means + prObstruentDeletion's excludedMPRFeatures="mprAffixDelExcl" gate now blocks the deletion that + would otherwise fire on the following voiceless obstruent "t" -- so "t" survives: + "mentanukam", not "menanukam". The control for menanukam (above). Two identical entries below: + the Main stratum is morphologicalRuleOrder="unordered", so mrNPfx (prefix) and mrDelExclSrc + (suffix) -- independent of each other's position -- are reached via two distinct derivation + orders that happen to produce the byte-identical surface and signature, exactly like any other + pair of non-conflicting affixes under this stratum's own ordering discipline. + parses: + - signature: "NPFX+TANUK+DELEXCLSRC|mentanukam" + rules: [mrNPfx, mrDelExclSrc, prNasalAssimAlveolar] + - signature: "NPFX+TANUK+DELEXCLSRC|mentanukam" + rules: [mrDelExclSrc, mrNPfx, prNasalAssimAlveolar] + + - word: tanuk + note: TANUK bare root, no prefix or suffix -- a plain control. + parses: + - signature: "TANUK|tanuk" + rules: [] diff --git a/conformance/edge-cases/mpr-group-overwrite-without-realizational/grammar.xml b/conformance/edge-cases/mpr-group-overwrite-without-realizational/grammar.xml new file mode 100644 index 000000000..b77e60f4d --- /dev/null +++ b/conformance/edge-cases/mpr-group-overwrite-without-realizational/grammar.xml @@ -0,0 +1,90 @@ + + + + + MprGroupOverwriteWithoutRealizational + + n + + + + A + B + ThemeGroup + + + Main + + d + o + f + u + w + q + + + + Any + + + + + S + + + themeA + + + + u + + + THEMEA + + + themeB + + + + w + + + THEMEB + + + + endC + + + + q + + + ENDC + + + + + dof + DOF + dof + + + + + + diff --git a/conformance/edge-cases/mpr-group-overwrite-without-realizational/words.yaml b/conformance/edge-cases/mpr-group-overwrite-without-realizational/words.yaml new file mode 100644 index 000000000..bb48c886f --- /dev/null +++ b/conformance/edge-cases/mpr-group-overwrite-without-realizational/words.yaml @@ -0,0 +1,61 @@ +# Oracle: pangloss (`pg_parse::Morpher`, driven directly via a temporary probe test -- see +# STAGING.md's "Verification" section), NOT the C# founding oracle. Signatures below are +# transcribed verbatim from that run, not hand-derived. + +language: MprGroupOverwriteWithoutRealizational +inspired_by: ["synthetic MPR-group-overwrite probe (not modeling any real language); the ThemeGroup mechanism of languages/fusional-realizational-morphology's own MprGroups stratum, isolated into a grammar with no RealizationalRule at all"] +sources: + - "languages/fusional-realizational-morphology's own MprGroups stratum (mrThemeX/mrThemeY/mrEndZ, ThemeGroup)" +requires: [] +words: + - word: dof + note: DOF bare root, no prefix -- a plain control. + parses: + - signature: "DOF|dof" + gloss: dof + rules: [] + exercises: [] + + - word: udof + note: DOF prefixed by mrThemeA ("u-", sets MPR feature mprA). + parses: + - signature: "THEMEA+DOF|udof" + gloss: THEME.A-dof + rules: [mrThemeA] + exercises: + - "MPR features/groups" + + - word: wudof + note: DOF prefixed by mrThemeA then mrThemeB ("w-", sets mprB) -- ThemeGroup's outputType="overwrite" means mrThemeB's own output DROPS mprA rather than accumulating it alongside mprB. + provenance: "mpr-groups/output-overwrite (MprGroupOutput::Overwrite in MPR output accumulation)" + parses: + - signature: "THEMEB+THEMEA+DOF|wudof" + gloss: THEME.B-THEME.A-dof + rules: [mrThemeA, mrThemeB] + exercises: + - "MPR features/groups" + + - word: udofq + note: DOF prefixed by mrThemeA then suffixed by mrEndC (requiredMPRFeatures="mprA") -- mprA is still present (only mrThemeA applied), so mrEndC's requirement is satisfied. + parses: + - signature: "THEMEA+DOF+ENDC|udofq" + gloss: THEME.A-dof-END + rules: [mrThemeA, mrEndC] + exercises: + - "MPR features/groups" + + - word: wudofq + note: >- + THE distinguishing row: DOF prefixed by mrThemeA then mrThemeB then suffixed by mrEndC -- + the CONSTRUCT this fixture exists to pin. After mrThemeB, ThemeGroup's Overwrite semantics + have already dropped mprA, so mrEndC's requiredMPRFeatures="mprA" fails. Zero parses. This + grammar carries NO RealizationalRule anywhere (unlike the only two existing grammars with an + Overwrite MPR group), so EmissionStrategy::PlanComposed is not refused outright and actually + reaches this material -- an engine whose plan-composed lexicon emitter (or any other + backend) treats Overwrite as a flat union (the pre-fix "Append" mis-implementation this + exact mechanism was built to catch) would wrongly accept this. + provenance: "mpr-groups/output-overwrite (MprGroupOutput::Overwrite in MPR output accumulation)" + expect_fail: true + blocked_by: [mrEndC] + exercises: + - "MPR features/groups" diff --git a/conformance/edge-cases/mpr-overwrite-order-dependence/grammar.xml b/conformance/edge-cases/mpr-overwrite-order-dependence/grammar.xml new file mode 100644 index 000000000..52369cce7 --- /dev/null +++ b/conformance/edge-cases/mpr-overwrite-order-dependence/grammar.xml @@ -0,0 +1,172 @@ + + + + + + MprOverwriteOrderDependence + + n + + + X + Y + P + Q + + + overwriteGroup + + + + appendGroup + + + + Main + + a + b + d + e + f + i + m + o + p + q + u + v + x + y + z + + + + Any + + + + Main + + + setX + + + + xa + + + SETX + setx + + + setY + + + + yu + + + SETY + sety + + + + gateX + + + + zi + + + GATEX + gatex + + + setP + + + + pi + + + SETP + setp + + + setQ + + + + qu + + + SETQ + setq + + + + gatePQ + + + + vo + + + GATEPQ + gatepq + + + + + + dabo + + DABO + root.dabo + + + + femo + + FEMO + root.femo + + + + + + diff --git a/conformance/edge-cases/mpr-overwrite-order-dependence/words.yaml b/conformance/edge-cases/mpr-overwrite-order-dependence/words.yaml new file mode 100644 index 000000000..5804b18aa --- /dev/null +++ b/conformance/edge-cases/mpr-overwrite-order-dependence/words.yaml @@ -0,0 +1,118 @@ +# MPR overwrite-group order dependence. See grammar.xml's own header for the full design; this +# pins the one consequence of outputType="overwrite" that edge-cases/morphotactic-attribute-breadth +# leaves untouched: on an UNORDERED stratum, two rules that both write an overwrite group can apply +# in either relative order, and the group's final content depends on which one wrote LAST. A third +# rule gated on requiredMPRFeatures naming one of the two members therefore succeeds under one +# derivation order and fails under the reverse -- the same morpheme set (root + mrSetX + mrSetY + +# mrGateX), two different outcomes, attributable only to which order the first two rules fired in. +# +# Oracle: the C# founding oracle +# (src/SIL.Machine.Morphology.HermitCrab.Conformance, run directly in this checkout -- this worktree +# IS the machine repo, so no submodule widening was needed). Every signature below is transcribed +# verbatim from --propose output, not hand-derived. +# +# Design of the word list: +# dabo/femo bare-root controls: the grammar loads and admits a free root on each probe. +# daboxayu/daboyuxa overwriteGroup, both relative orders of mrSetX/mrSetY alone (no gate yet) -- +# establishes that both orders are independently reachable and that each +# produces a DIFFERENT surface string (the suffix concatenation order is a +# fingerprint of which rule fired first), before the gate is layered on. +# daboxayuzi mrSetX then mrSetY then mrGateX: mrSetY wrote LAST, so overwriteGroup's +# eviction (MprFeatureSet.AddOutput) removes mprX before mrGateX's +# requiredMPRFeatures="mprX" is checked. THE negative control: no valid +# derivation exists for this exact surface string once the gate is added, even +# though the string differs from daboyuxazi only in affix order. +# daboyuxazi mrSetY then mrSetX then mrGateX: mrSetX wrote LAST, so mprX survives and +# mrGateX succeeds. THE positive control -- same three rules, same root, same +# gate, reversed order, opposite outcome. +# femopiqu/femoqupi appendGroup mirror of daboxayu/daboyuxa: both orders of mrSetP/mrSetQ alone. +# femopiquvo mrSetP then mrSetQ then mrGatePQ: append never evicts, so both mprP and mprQ +# are present and mrGatePQ (requiredMPRFeatures="mprP mprQ") succeeds. +# femoqupivo mrSetQ then mrSetP then mrGatePQ: the reverse order, SAME outcome (succeeds) +# -- the control that attributes daboxayuzi/daboyuxazi's order-sensitivity to +# outputType="overwrite" itself, not to some incidental difference between the +# two probes' rule shapes (which are otherwise identical apart from the group's +# outputType and the gate's matchType). + +language: MprOverwriteOrderDependence +inspired_by: ["synthetic MPR-overwrite-group order-dependence probe (not modeling any real language)"] +sources: + - "conformance/edge-cases/morphotactic-attribute-breadth (outputType coverage this fixture extends: order-dependence on an unordered stratum, not pinned there)" +requires: [] +words: + - word: dabo + note: Bare free root. The overwrite probe's own control that the grammar loads and admits a complete word at all. + parses: + - signature: "DABO|dabo" + rules: [] + + - word: femo + note: Bare free root. The append probe's own control, isolated from dabo (no shared letters, no shared rule). + parses: + - signature: "FEMO|femo" + rules: [] + + - word: daboxayu + note: >- + mrSetX then mrSetY, no gate yet. Establishes that this relative order is reachable and that it + produces a surface string distinct from the reverse order (daboyuxa) -- the suffix + concatenation order is a fingerprint of which rule fired first on this Unordered stratum. + parses: + - signature: "DABO+SETX+SETY|daboxayu" + rules: [mrSetX, mrSetY] + + - word: daboyuxa + note: mrSetY then mrSetX, the reverse order of daboxayu, no gate yet. + parses: + - signature: "DABO+SETY+SETX|daboyuxa" + rules: [mrSetX, mrSetY] + + - word: daboxayuzi + note: >- + THE negative control: mrSetX then mrSetY then mrGateX. mrSetY wrote overwriteGroup LAST, so + MprFeatureSet.AddOutput evicts mprX before mrGateX's requiredMPRFeatures="mprX" is checked -- + no valid derivation exists for this surface string. An engine that let outputType="overwrite" + silently degenerate to "append" (or ignored requiredMPRFeatures entirely) would wrongly accept + this. + expect_fail: true + blocked_by: [mrGateX] + + - word: daboyuxazi + note: >- + THE positive control: mrSetY then mrSetX then mrGateX -- the same three rules and the same + root as daboxayuzi, reversed order. mrSetX wrote overwriteGroup LAST, so mprX survives and + mrGateX's requiredMPRFeatures="mprX" succeeds. Same morpheme set as daboxayuzi; opposite + outcome, attributable only to which of mrSetX/mrSetY applied last. + parses: + - signature: "DABO+SETY+SETX+GATEX|daboyuxazi" + rules: [mrGateX, mrSetX, mrSetY] + + - word: femopiqu + note: mrSetP then mrSetQ, no gate yet -- the appendGroup mirror of daboxayu. + parses: + - signature: "FEMO+SETP+SETQ|femopiqu" + rules: [mrSetP, mrSetQ] + + - word: femoqupi + note: mrSetQ then mrSetP, the reverse order of femopiqu, no gate yet. + parses: + - signature: "FEMO+SETQ+SETP|femoqupi" + rules: [mrSetP, mrSetQ] + + - word: femopiquvo + note: >- + mrSetP then mrSetQ then mrGatePQ. appendGroup's outputType="append" never evicts, so both mprP + and mprQ are present and mrGatePQ's requiredMPRFeatures="mprP mprQ" (matchType="all") succeeds. + parses: + - signature: "FEMO+SETP+SETQ+GATEPQ|femopiquvo" + rules: [mrGatePQ, mrSetP, mrSetQ] + + - word: femoqupivo + note: >- + mrSetQ then mrSetP then mrGatePQ -- the reverse order of femopiquvo. SAME outcome (succeeds): + the control that attributes daboxayuzi/daboyuxazi's order-sensitivity to outputType="overwrite" + itself, since this probe is identical in shape apart from the group's outputType and the gate's + matchType, and order does NOT matter here. + parses: + - signature: "FEMO+SETQ+SETP+GATEPQ|femoqupivo" + rules: [mrGatePQ, mrSetP, mrSetQ] diff --git a/conformance/edge-cases/process-morphology-in-place-mutation/grammar.xml b/conformance/edge-cases/process-morphology-in-place-mutation/grammar.xml new file mode 100644 index 000000000..aceb7c513 --- /dev/null +++ b/conformance/edge-cases/process-morphology-in-place-mutation/grammar.xml @@ -0,0 +1,104 @@ + + + + + ProcessMorphologyInPlaceMutation + + root + + + + + id + + iau + + + + + tensepast + + + Main + + i + a + u + + + + + AblautI + AblautA + + + + S + + + + ablautPast + + + + + + + + ABLAUT + + + + + + i + ROOT + i-root + + + + a + AROOT + a-root + + + + u + UROOT + u-root + + + + + + diff --git a/conformance/edge-cases/process-morphology-in-place-mutation/words.yaml b/conformance/edge-cases/process-morphology-in-place-mutation/words.yaml new file mode 100644 index 000000000..6021d0634 --- /dev/null +++ b/conformance/edge-cases/process-morphology-in-place-mutation/words.yaml @@ -0,0 +1,45 @@ +# Oracle: pangloss (`pg_parse::Morpher`, driven directly via a temporary probe test -- see +# STAGING.md's "Verification" section), NOT the C# founding oracle. Signatures below are +# transcribed verbatim from that run, not hand-derived. + +language: ProcessMorphologyInPlaceMutation +inspired_by: ["synthetic ablaut/mutation-as-sole-exponent probe (not modeling any real language)"] +sources: + - "rust/crates/pg-foma/src/capability.rs, CharacteristicKind::ProcessMorphology's own doc and ABLAUT_PROCESS_XML unit fixture" +requires: [] +words: + - word: i + note: The mutable root, bare -- no tense feature assigned, mrAblaut has nothing to apply to (it requires the target segment itself, not the whole word, and this IS the whole word already in the right shape only if mrAblaut fired, which it hasn't). + parses: + - signature: "ROOT|i" + gloss: i-root + rules: [] + exercises: [] + + - word: a + note: >- + THE construct-exhibiting row: surface "a" has TWO analyses -- eA bare (an unrelated root + that happens to already be spelled "a"), and eI + mrAblaut (past tense realized purely by + mutating "i" to "a", no affix at all -- classify_affix reads this Modify-only RHS as + Role::Process). A ProcessMorphology compile regression (crate::emit::is_structural_rule no + longer admitting Role::Process, or the structural-composite replay breaking) would silently + drop the second analysis, leaving only "AROOT|a". + provenance: "capability.rs, CharacteristicKind::ProcessMorphology's own doc; strategy_coverage.rs's tuned_surface_probed ProcessMorphology row (emit::is_structural_rule / build_structural_composites / pg_rules::morph::synthesize)" + parses: + - signature: "AROOT|a" + gloss: a-root + rules: [] + exercises: [] + - signature: "ROOT+ABLAUT|a" + gloss: i-root-ABLAUT + rules: [mrAblaut] + exercises: + - "MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext" + + - word: u + note: A plain structural control -- mrAblaut's output class only ever contains "a", so it can never derive "u"; this root's only analysis is itself, bare. + parses: + - signature: "UROOT|u" + gloss: u-root + rules: [] + exercises: [] diff --git a/conformance/edge-cases/right-to-left-anchor-environment/grammar.xml b/conformance/edge-cases/right-to-left-anchor-environment/grammar.xml new file mode 100644 index 000000000..99563c8d2 --- /dev/null +++ b/conformance/edge-cases/right-to-left-anchor-environment/grammar.xml @@ -0,0 +1,85 @@ + + + + + RightToLeftAnchorEnvironment + Any + + + + + id + + a + e + + + + + Main + + a + + + e + + + + + + A + E + + + + rtlAnchorDemo + + + + + + + + + + + spreadEAfterE + + + + + + + + + + + + Main + + + aaa + ROOT1 + root1 + + + aa + ROOT2 + root2 + + + eaaa + ROOT3 + root3 + + + + + + + diff --git a/conformance/edge-cases/right-to-left-anchor-environment/words.yaml b/conformance/edge-cases/right-to-left-anchor-environment/words.yaml new file mode 100644 index 000000000..79d0ebd93 --- /dev/null +++ b/conformance/edge-cases/right-to-left-anchor-environment/words.yaml @@ -0,0 +1,120 @@ +# Synthetic construct-shaped mimic. Original oracle: pangloss (`pg_parse::Morpher`, driven +# directly), NOT the C# founding oracle. ROOT3/eaaa/eeae/eeee were added later and their signatures +# are transcribed from the C# founding oracle (conformance/adapters/hc-dotnet-wrapper.sh batch over +# a Debug build of src/SIL.Machine.Morphology.HermitCrab.Tool), since that oracle is available in +# this checkout; the earlier ROOT1/ROOT2 words were left as originally authored. +# +# prRtlAnchor's own anchored environment can only ever match the single word-final position, so its +# multipleApplicationOrder value was never observable through it alone: rightToLeftIterative and +# leftToRightIterative visit that one position identically. prSpread exists to give the fixture a +# rule where direction actually changes the result: it spreads "e" onto an immediately-following "a" +# iteratively, so a single pass can cascade further in the SCAN direction than against it. ROOT3 +# ("eaaa") is the word that shows this: +# eeae rightToLeftIterative (this fixture's declared order): scanning right to left, the +# rightmost "a" is checked against its (still unmodified) left neighbor first and does not +# yet qualify, so only one "a" ends up adjacent to the seed "e" and rewrites. +# eeee what leftToRightIterative would produce instead: scanning left to right, each rewrite +# updates the string before the next position to its right is checked, so the "e" cascades +# all the way across in one pass. Not a valid surface form here; kept as a negative control. + +language: RightToLeftAnchorEnvironment +inspired_by: ["synthetic right-to-left word-boundary-anchored rewrite probe (not modeling any real language)"] +sources: + - "openspec/changes/plan-construct-coverage-completion task 4.2 (RightToLeftRewrite: additional in-scope pattern shapes -- Anchor)" +requires: [phonology] +words: + - word: aae + note: >- + ROOT1's correctly-rewritten surface form: underlying "aaa" (three "a"s). The rule + (`prRtlAnchor`) rewrites "a" -> "e" only when the "a" is IMMEDIATELY followed by the end of + the word (`finalBoundaryCondition="true"`, a bare `PatternNode::Anchor` right environment, no + other context node). Only the THIRD (word-final) "a" satisfies that; the first two do not + (each is followed by another "a", never the boundary), so only the last one rewrites. + provenance: "openspec/changes/plan-construct-coverage-completion task 4.2" + parses: + - signature: "ROOT1|aae" + rules: [prRtlAnchor] + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: ae + note: >- + ROOT2's correctly-rewritten surface form: underlying "aa" (two "a"s). The second (word-final) + "a" rewrites to "e"; the first does not (followed by the second "a", not the boundary). + provenance: "openspec/changes/plan-construct-coverage-completion task 4.2" + parses: + - signature: "ROOT2|ae" + rules: [prRtlAnchor] + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: aaa + note: >- + ROOT1's own RAW, un-rewritten underlying shape, queried directly as a surface string -- the + rule is obligatory wherever its environment matches (the word-final "a" always satisfies + `finalBoundaryCondition`), so this exact string is NOT a valid surface form for ROOT1 at all. + Proves the rule genuinely fires (obligatorily), rather than being vacuously inapplicable. + provenance: "openspec/changes/plan-construct-coverage-completion task 4.2" + expect_fail: true + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: aa + note: ROOT2's own RAW underlying shape, queried directly -- same reasoning as "aaa" (should have rewritten to "ae"). + provenance: "openspec/changes/plan-construct-coverage-completion task 4.2" + expect_fail: true + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: eaa + note: >- + A WRONGLY-rewritten variant of ROOT1's underlying "aaa": if the anchor were mis-swapped to + "word-INITIAL" instead of "word-final" (exactly the mistake `crate::lower::Slot::Anchor`'s own + doc warns the mirror-and-reverse construction must not make), the FIRST "a" would rewrite + instead of the last, giving this string. Must have no analysis at all under either + hypothesis (it is not a valid surface form for ROOT1: the correct rewrite is "aae", and this + is neither the correct rewrite nor the raw underlying shape). + provenance: "openspec/changes/plan-construct-coverage-completion task 4.2" + expect_fail: true + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: aea + note: >- + Another structurally-invalid variant of ROOT1's underlying "aaa" (the MIDDLE "a" rewritten + instead of the last) -- no position of the LHS class other than the true word-final one ever + satisfies the anchored environment, so this is never a valid surface form either. + provenance: "openspec/changes/plan-construct-coverage-completion task 4.2" + expect_fail: true + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: eaaa + note: ROOT3's own raw underlying shape. prRtlAnchor's final "a" and prSpread's cascade both fire obligatorily, so this exact string is not a valid surface form. + expect_fail: true + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: eeae + note: >- + ROOT3's correctly-rewritten surface form. prRtlAnchor rewrites the word-final "a" to "e" first + ("eaaa" -> "eaae"); prSpread then runs right-to-left over "eaae": the rightmost "a" (position 3) + checks its left neighbor (position 2, still "a") first and does not qualify, so only position 2 + (adjacent to the original seed "e") rewrites. + neutralizes: + - prSpread + parses: + - signature: "ROOT3|eeae" + rules: [prRtlAnchor, prSpread] + exercises: + - "RewriteRule direction (Dir): right-to-left" + + - word: eeee + note: >- + What prSpread would produce on "eaae" if it ran leftToRightIterative instead: scanning left to + right, each rewrite updates the string before the next "a" to its right is checked, so the "e" + cascades across the whole word in one pass. Not a valid surface form under this fixture's + declared rightToLeftIterative order; kept as the negative control that shows direction matters. + expect_fail: true + exercises: + - "RewriteRule direction (Dir): right-to-left" diff --git a/conformance/edge-cases/simultaneous-epenthesis-cascade/grammar.xml b/conformance/edge-cases/simultaneous-epenthesis-cascade/grammar.xml new file mode 100644 index 000000000..692bf21b0 --- /dev/null +++ b/conformance/edge-cases/simultaneous-epenthesis-cascade/grammar.xml @@ -0,0 +1,143 @@ + + + + + IterativeEpenthesisCascadeProbe + + + n + + + + + cons + + + + - + + + + voc + + + + - + + + + high + + + + - + + + + back + + + + - + + + + round + + + + - + + + + + + Main + + + + b + + + + + + + + + + i + + + + + + + + + + u + + + + + + + + + + + + HighVowel + + + + + + HFUVowel + + + + + + + + + + + rule4 + + + + + + + + + + + + + + + + + + + + + + + + Main + + + + + bubu + + + 19 + + + + + + diff --git a/conformance/edge-cases/simultaneous-epenthesis-cascade/words.yaml b/conformance/edge-cases/simultaneous-epenthesis-cascade/words.yaml new file mode 100644 index 000000000..3881b39db --- /dev/null +++ b/conformance/edge-cases/simultaneous-epenthesis-cascade/words.yaml @@ -0,0 +1,39 @@ +# Converted from conformance/rewrite/simultaneous-epenthesis-cascade (v1, removed after the v1->v2 +# migration's parity proof). grammar.xml is the same file, unmodified. expect_crash semantics (front +# matter, below) must match v1's exactly: the engine +# under test is expected to ALSO crash (loading the grammar or parsing the word) for this fixture to +# PASS; a harness-level problem (bad adapter, process fails to start, timeout) is never treated as a +# crash match and always FAILs regardless of expect_crash -- see conformance/PROTOCOL.md's +# "expectCrash" section, unchanged by this conversion. +# +# What this pins (from the v1 fixture's README.md/manifest.json provenance, carried forward +# verbatim): P13 synthetic oracle -- a hand-designed probe (not derived from a C# unit test) of the +# OTHER direction of the Simultaneous-vs-Iterative divergence for epenthesis (LHS-empty) subrules: +# the rule inserts an HFU vowel ("i") after any HighVowel, no RightEnvironment, tagged Iterative (the +# grammar carries no multipleApplicationOrder="simultaneous" attribute). Because C#'s epenthesis +# substitute LHS pattern never adds a Modified=Clean filter, IterativePhonologicalPatternRule.Apply's +# freshly-inserted "i" node is itself a HighVowel and gets revisited by the very next iteration of +# the same outer loop, satisfying its own LeftEnvironment and re-triggering insertion -- a runaway +# self-feeding cascade that only stops when EpenthesisSynthesisRewriteSubruleSpec.ApplyRhs's own hard +# cap (Shape.Count == 256) throws InfiniteLoopException. BatchCommand.ParseOneWord only catches +# InvalidShapeException, so this kills the whole batch run rather than recording a per-word result -- +# expected.tsv's v1 ground truth was only the STARTED sentinel for word 0, never a completed row; +# this fixture's materialized expected.tsv (built by FixtureMaterializer for adapter mode) reproduces +# that same STARTED-only shape. Keep words.txt/this file to a single word: a crash aborts the whole +# word loop, so anything after the crashing word would never actually be exercised (same reasoning +# as v1 -- see PROTOCOL.md's "Because a crash aborts a fixture's whole word loop..." note). + +language: IterativeEpenthesisCascadeProbe +inspired_by: ["synthetic RewriteRule Iterative-vs-Simultaneous stress probe (not modeling any real language)"] +sources: + - "rust/docs/p13-simultaneous-design.md section 5" +requires: [phonology] +expect_crash: true +words: + - word: bubu + note: >- + Lexical root "bubu" alone (no affixes needed -- this only needs to exercise synthesis, i.e. + the forward phonological-rule direction). Parsing this word crashes the oracle with an + uncaught InfiniteLoopException partway through, per the fixture's front-matter expect_crash. + provenance: "P13 synthetic oracle: Iterative self-feeding epenthesis crashes; Simultaneous cannot" + expect_fail: true diff --git a/conformance/edge-cases/stem-name-restricted-root-allomorph/grammar.xml b/conformance/edge-cases/stem-name-restricted-root-allomorph/grammar.xml new file mode 100644 index 000000000..1aa0b53e2 --- /dev/null +++ b/conformance/edge-cases/stem-name-restricted-root-allomorph/grammar.xml @@ -0,0 +1,92 @@ + + + + + StemNameRestrictedRootAllomorph + + v + + + + pers12 + + + + + PrincipalPartP1 + + + + + + + Main + + t + a + m + k + p + o + u + r + + + + Any + + + + S + + + + pers1 + + + + om + + + + PERS1 + + + + pers2 + + + + ur + + + + PERS2 + + + + + + + tam + kap + + ROOT + root + + + + + + diff --git a/conformance/edge-cases/stem-name-restricted-root-allomorph/words.yaml b/conformance/edge-cases/stem-name-restricted-root-allomorph/words.yaml new file mode 100644 index 000000000..b55603132 --- /dev/null +++ b/conformance/edge-cases/stem-name-restricted-root-allomorph/words.yaml @@ -0,0 +1,66 @@ +# Oracle: pangloss (`pg_parse::Morpher`, driven directly via a temporary probe test -- see +# STAGING.md's "Verification" section), NOT the C# founding oracle. Signatures below are +# transcribed verbatim from that run, not hand-derived. + +language: StemNameRestrictedRootAllomorph +inspired_by: ["synthetic principal-parts / stem-alternation probe (not modeling any real language)"] +sources: + - "rust/crates/pg-foma/src/capability.rs, CharacteristicKind::StemName's own doc" +requires: [] +words: + - word: tam + note: The unrestricted default allomorph, bare -- no featPers assigned at all, which is outside snP1's region, so the excluded-match check is satisfied trivially. + parses: + - signature: "ROOT|tam" + gloss: root + rules: [] + exercises: + - "Stem names" + + - word: kap + note: >- + THE distinguishing row: the stemName="snP1" allomorph, bare -- its region requires + featPers=1 to be ASSIGNED, but a bare form has no person feature at all, so the + required-match fails. Zero parses. An engine that ignores RootAllomorphDef::stem_name + entirely (proposes every allomorph unconditionally, per capability.rs's own StemName doc) + would wrongly accept this. + expect_fail: true + exercises: + - "Stem names" + + - word: kapom + note: The stemName="snP1" allomorph + mrPers1 (assigns featPers=1) -- the word's FS now falls inside snP1's region, so the required-match succeeds. + provenance: "capability.rs, CharacteristicKind::StemName's own doc (RootAllomorphDef::stem_name / StemName.IsRequiredMatch)" + parses: + - signature: "ROOT+PERS1|kapom" + gloss: root-1 + rules: [mrPers1] + exercises: + - "Stem names" + + - word: tamom + note: >- + THE mirror-image distinguishing row: the DEFAULT allomorph + mrPers1 -- featPers=1 now + puts the word's FS INSIDE snP1's region, so the default's excluded-match check FAILS (it is + valid only outside every declared StemName's region). Zero parses. The same + flat-proposal bug would wrongly accept this too, using the wrong allomorph for this + person. + expect_fail: true + exercises: + - "Stem names" + + - word: tamur + note: The default allomorph + mrPers2 (assigns featPers=2) -- outside snP1's region, so the excluded-match check succeeds. + provenance: "capability.rs, CharacteristicKind::StemName's own doc (RootAllomorphDef::stem_name / StemName.IsExcludedMatch)" + parses: + - signature: "ROOT+PERS2|tamur" + gloss: root-2 + rules: [mrPers2] + exercises: + - "Stem names" + + - word: kapur + note: The stemName="snP1" allomorph + mrPers2 -- featPers=2 is outside snP1's region, so the required-match fails (this allomorph is valid only inside its own region). + expect_fail: true + exercises: + - "Stem names" diff --git a/conformance/edge-cases/strrep-identity/grammar.xml b/conformance/edge-cases/strrep-identity/grammar.xml new file mode 100644 index 000000000..7b6aeb728 --- /dev/null +++ b/conformance/edge-cases/strrep-identity/grammar.xml @@ -0,0 +1,204 @@ + + + + + StrRepIdentityProbe + + + root + + + + + Main + + m + w + u + p + a + t + i + n + d + + + + + + + + + + + + ^0 + + + + + + + + Any + + + + Vclass + + + + + + Main + + + + class-prefix + + + + + + + + + + + + + mw+ + + + + + + + + + + + + + + + ^0+ + + + + + + + + + + + + + + + mu+ + + + + + + CL + + + + obj-prefix + + + + + + + + + + + + i+ + + + + + + + + + + m + + + + + + + + + + + + + + + + + + nd+ + + + + + + OBJ + + + + + + pat + + pat + + + + uta + + uta + + + + mat + + mat + + + + + + diff --git a/conformance/edge-cases/strrep-identity/words.yaml b/conformance/edge-cases/strrep-identity/words.yaml new file mode 100644 index 000000000..5b260b278 --- /dev/null +++ b/conformance/edge-cases/strrep-identity/words.yaml @@ -0,0 +1,214 @@ +# Converted from conformance/allomorphy/strrep-identity (v1, removed after the v1->v2 migration's +# parity proof). grammar.xml is the same file, +# unmodified: deliberately NO PhonologicalFeatureSystem at all (every char-def's feature bundle is +# empty) and NO element on either MorphologicalRule (rulePfx, ruleObj) -- like +# edge-cases/disjunctive-recheck, this fixture's own signatures ("+|mu+?pat" etc.) would change if a +# MorphemeId were added, so it cannot gain one. See disjunctive-recheck's words.yaml header for the +# GrammarRuleIndex cross-cutting finding this fixture also depends on (fixed in the same commit). +# +# What this pins (from the v1 fixture's README.md/manifest.json, carried forward verbatim): C# makes +# character identity a real matching dimension -- every char-def's feature struct carries a StrRep +# (the segment's own representation string), and SegmentNaturalClass/literal-segment +# constraints/environments consult it. On a grammar with NO phonological features at all (like the reference grammar, +# and like this fixture), StrRep is the ONLY thing distinguishing one segment from another; an engine +# that drops this dimension degenerates every such constraint to "matches any segment" -- the exact +# gap behind the reference grammar's null-allomorph coverage loss (this suite's single largest historical divergence +# class). +# +# - rulePfx (the Bantu mu-2/mu-3 class-prefix analog -- the DISJUNCTIVE-BREAK probe): subrule 0 +# ("mw+") requires a stem-initial ncV member ("u"); subrules 1 (the null "^0+") and 2 ("mu+") +# share identical LHS/constraints, so they free-fluctuate and BOTH fire once reached. On a +# consonant-initial stem C# skips subrule 0 (StrRep mismatch) and reaches the null subrule; an +# engine that lets subrule 0 match "any segment" breaks right after it and never realizes the +# zero allomorph. +# - ruleObj (the Bantu ndi- analog -- the ENVIRONMENT-RECHECK probe, P10 part 2): subrule 0 ("i+") +# carries a literal-segment RequiredEnvironment (following "m"): because it is +# environment-constrained, C#'s synthesis loop does not break after it, subrule 1 ("nd+") also +# fires, and subrule 0 lands in the nd-morph's passed-over set. At final validity +# (Allomorph.cs:127-152) an "nd+" parse is rejected only when subrule 0's environment is ALSO +# satisfied at the same morph position (stem starts with a real "m"). +# +# Both rules are on the same posRoot part of speech with morphologicalRuleOrder="unordered", so they +# can stack in either linear order -- ndpat/imat below each have 3 distinct valid analyses (rulePfx +# and ruleObj both applied, in either order; or ruleObj alone), all oracle-verified. + +language: StrRepIdentityProbe +inspired_by: ["synthetic StrRep-identity probe (not modeling any real language)"] +sources: + - "P10, StrRep identity dimension on a feature-less grammar" +requires: [] +words: + - word: pat + note: >- + PAT bare root -- ambiguous between two valid analyses: the null-prefixed one (rulePfx's + subrule 1, "^0+", a genuine zero allomorph that free-fluctuates with "mu+") and the plain bare + root. Both surface identically as "pat" but are distinct MorphemeId-chain analyses (the + shared, deliberate combinatorial-identity trick this whole fixture probes). + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "+|[(^0)∅]?+?pat" + gloss: pat-CL + rules: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - signature: "|pat" + gloss: pat + rules: [] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: uta + note: UTA bare root, no prefix -- a plain control; also the sole ncV ("Vclass") member, used by mwuta/muuta below. + parses: + - signature: "|uta" + gloss: uta + rules: [] + exercises: [] + + - word: mat + note: MAT bare root -- the same null-prefix/bare-root ambiguity as "pat", on the root ruleObj's own-environment rows below also use. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "+|[(^0)∅]?+?mat" + gloss: mat-CL + rules: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - signature: "|mat" + gloss: mat + rules: [] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: mupat + note: >- + PAT + rulePfx subrule 2 ("mu+", the free-fluctuation partner of the null subrule) -- "pat" is + consonant-initial, so subrule 0 ("mw+") is correctly skipped (StrRep mismatch on its + stem-initial ncV requirement) and subrule 2 is reached and fires. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "+|mu+?pat" + gloss: pat-CL + rules: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: mumat + note: The mu+ variant of the mat/rulePfx pair, mirroring mupat on the other root. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "+|mu+?mat" + gloss: mat-CL + rules: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: mwpat + note: >- + rulePfx subrule 0 ("mw+") requires the FOLLOWING stem to start with a ncV member ("u") -- "pat" + is consonant-initial, so subrule 0 cannot apply here at all, and no other subrule produces + surface "mw+pat" (subrules 1/2 insert "^0+"/"mu+", not "mw+"). Zero parses: this is the + StrRep-identity gate itself -- an engine that lets "mw+" match a consonant-initial stem (the + pre-fix Rust bug) would wrongly accept this. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + expect_fail: true + blocked_by: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: mwuta + note: >- + UTA + rulePfx subrule 0 ("mw+") -- "uta" starts with "u" (the sole ncV member), so subrule 0's + stem-initial requirement is satisfied and it fires; C#'s synthesis loop breaks immediately + after this ordinary (non-environment-constrained) match, so subrules 1/2 are never reached for + a vowel-initial stem (see muuta below). + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "+|mw+?uta" + gloss: uta-CL + rules: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: muuta + note: >- + The mirror-image gate of mwpat: "uta" is vowel-initial, so rulePfx subrule 0 ("mw+") matches + and the loop breaks right after it -- subrule 2 ("mu+") is never reached for this stem, so + surface "mu+uta" has no valid derivation. Zero parses. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + expect_fail: true + blocked_by: [rulePfx] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: ndpat + note: >- + PAT + ruleObj subrule 1 ("nd+"), optionally ALSO with rulePfx's null subrule stacked (the two + rules share posRoot with morphologicalRuleOrder="unordered", so both linear orders are valid, + plus the ruleObj-alone analysis) -- three distinct, equally-valid analyses, all surfacing + "ndpat" (the null prefix's "^0+"/"∅" boundary is invisible in the literal string). Also + pins C# GetSkippedOptionalNodes: a word-initial run of optional (boundary) nodes left of the + captured stem range is folded into the copy, so the medial zero allomorph survives ruleObj's + own stem-copy instead of being silently dropped. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "++|[(^0)∅]?+?nd+?pat" + rules: [rulePfx, ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - signature: "++|nd+?[(^0)∅]?+?pat" + rules: [rulePfx, ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - signature: "+|nd+?pat" + gloss: pat-OBJ + rules: [ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: ndmat + note: >- + THE distinguishing row (environment re-check): ruleObj subrule 1 ("nd+") used on "mat", but + subrule 0's RequiredEnvironment (following "m") is ALSO satisfied at the same morph position + (the stem is "mat", which starts with "m") and subrule 0 was recorded as passed-over -- the + disjunctive re-check REJECTS this synthesis (right answer for the C# oracle here, but for a + pre-fix engine that over-matches literal segments in environments, EVERY "nd+" parse would be + wrongly rejected this way -- the reference grammar's "the recheck-probe word" gap). Zero parses. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + expect_fail: true + blocked_by: [ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: imat + note: >- + MAT + ruleObj subrule 0 ("i+", RequiredEnvironment following "m" is satisfied by the "m" of + "mat" itself) -- the mirror-image acceptance of ndmat, with the same rulePfx-stacking + ambiguity as ndpat (three analyses: subrule 0 alone, or stacked with rulePfx's null subrule in + either linear order). + provenance: "P10, StrRep identity dimension on a feature-less grammar" + parses: + - signature: "++|[(^0)∅]?+?i+?mat" + rules: [rulePfx, ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - signature: "++|i+?[(^0)∅]?+?mat" + rules: [rulePfx, ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - signature: "+|i+?mat" + gloss: mat-OBJ + rules: [ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + + - word: ipat + note: >- + ruleObj subrule 0 ("i+") requires a following "m" -- "pat" starts with "p", so subrule 0's own + environment fails outright (the already-ported #5a own-environment gate, not the re-check), + and no other subrule produces surface "i+pat" (subrule 1 inserts "nd+", not "i+"). Zero parses. + provenance: "P10, StrRep identity dimension on a feature-less grammar" + expect_fail: true + blocked_by: [ruleObj] + exercises: + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" diff --git a/conformance/edge-cases/subrule-morphosyntactic-gating/grammar.xml b/conformance/edge-cases/subrule-morphosyntactic-gating/grammar.xml new file mode 100644 index 000000000..19ce511f7 --- /dev/null +++ b/conformance/edge-cases/subrule-morphosyntactic-gating/grammar.xml @@ -0,0 +1,82 @@ + + + + + SubruleMorphosyntacticGating + + + root + derived + + + + cons+- + voice+- + placebilabialalveolarvocalic + + + Main + + a + + + p + + + b + + + t + + + + + + Any + P + A + + + + gatedVoicing + + + + + + + + + + + + Main + + + zeroDerive + + + + + + + + + + + DERIVE + derive + + + + + pat + ROOT1 + root1 + + + + + + + diff --git a/conformance/edge-cases/subrule-morphosyntactic-gating/words.yaml b/conformance/edge-cases/subrule-morphosyntactic-gating/words.yaml new file mode 100644 index 000000000..dfff2b63f --- /dev/null +++ b/conformance/edge-cases/subrule-morphosyntactic-gating/words.yaml @@ -0,0 +1,46 @@ +# Synthetic construct-shaped mimic -- see STAGING.md and grammar.xml's own header comment. Oracle: +# pangloss (`pg_parse::Morpher`, driven directly -- see STAGING.md's "Verification" section), NOT the +# C# founding oracle -- authored and verified against this repo's own Rust engine only. Signatures +# below are transcribed verbatim from that run, not hand-derived. +# +# Authoring note: an early all-featureless draft (SegmentNaturalClass only, no +# PhonologicalFeatureSystem at all) made every segment share an identical (empty) feature bundle, +# and pg_parse's own shape rendering collapsed the analysis into a bracketed alternates class (e.g. +# "[apbt][apbt][apbt]") instead of the literal input string, on TOP of masking a real correctness +# problem (see grammar.xml's own G2a-discipline comment). Fixed by giving every segment a fully +# unique feature bundle, mirroring `conformance-staging/edge-cases/mpr-gated-exception`'s own fix for +# the identical symptom. + +language: SubruleMorphosyntacticGating +inspired_by: ["synthetic subrule-level phonological gating probe (not modeling any real language)"] +sources: + - "docs/conformance/representative-typology-basis.md S1.2.7 (Subrule-level phonological gating -- its own tagged phenomenon)" +requires: [phonology] +words: + - word: pat + note: >- + ROOT1 bare, with NO mrDerive applied -- the word's part of speech is never "posDerived", so + prGate's own subrule (requiredPartsOfSpeech="posDerived") is not licensed and the "p" before + "a" environment is left untouched. The SAME phonological environment ("p" before "a") is + present here as in "bat" below; only the morphosyntactic derivation state differs. + provenance: "docs/conformance/representative-typology-basis.md S1.2.7" + parses: + - signature: "ROOT1|pat" + rules: [prGate] + exercises: + - "RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level" + + - word: bat + note: >- + ROOT1 + mrDerive (a "zero-derivation" MorphologicalRule: CopyFromInput only, no segment + change, but outputPartOfSpeech="posDerived") -- once the word's own part of speech becomes + "posDerived", prGate's subrule IS licensed and rewrites "p" -> "b" in the identical "before a" + environment "pat" already presented. This is the load-bearing positive witness: the same + phonological trigger, reached via a different morphosyntactic derivation state, is now + licensed to fire. + provenance: "docs/conformance/representative-typology-basis.md S1.2.7" + parses: + - signature: "ROOT1+DERIVE|bat" + rules: [mrDerive, prGate] + exercises: + - "RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level" diff --git a/conformance/edge-cases/truncate-morphotactic/grammar.xml b/conformance/edge-cases/truncate-morphotactic/grammar.xml new file mode 100644 index 000000000..6ece9e0ed --- /dev/null +++ b/conformance/edge-cases/truncate-morphotactic/grammar.xml @@ -0,0 +1,218 @@ + + + + + TruncateRulesProbe + + + v + + + + + cons + + + + - + + + + cont + + + + - + + + + place + + alveolar + velar + bilabial + + + + height + + low + high + + + + back + + + + - + + + + + + Main + + + + s + + + + + + + + g + + + + + + + + b + + + + + + + + a + + + + + + + u + + + + + + + + i + + + + + + + + + + Any + + + Fricative + + + + + + + Main + + + + truncate_trail_literal + + + + + + + + + + + + + + + + + + 3SGA + + + + truncate_lead_class + + + + + + + + + + + + + + + + + + 3SGB + + + + truncate_optional_insert + + + + + + + + + + + + + + + + + g + + + + + + 3SGC + + + + + + + sag + + + 32 + + + + + sas + + + 33 + + + + + bubibi + + + 42 + + + + + + diff --git a/conformance/edge-cases/truncate-morphotactic/words.yaml b/conformance/edge-cases/truncate-morphotactic/words.yaml new file mode 100644 index 000000000..f100c80af --- /dev/null +++ b/conformance/edge-cases/truncate-morphotactic/words.yaml @@ -0,0 +1,156 @@ +# Converted from conformance/affix-shapes/truncate (v1, removed after the v1->v2 migration's parity +# proof). grammar.xml is the same file, unmodified: +# it carries a PhonologicalFeatureSystem (feeding the NaturalClasses the morphotactic rules below +# pattern-match against) but declares NO PhonologicalRule/MetathesisRule element anywhere, so +# RequiresDerivation mechanically derives requires: [] -- truncation here is pure AffixProcessRule +# morphotactics, no phonological rule involved at all. +# +# THE XAMPLE FLOOR (why this fixture exists as its own edge-case rather than folding only into +# metathesis-phase-isolation): metathesis-phase-isolation's own truncate word (mrTrunc, "pure"->"pur", SAME +# provenance string as this fixture's own words below, carried deliberately -- both pin the identical +# W9.1 construct) lives in a requires:[phonology] grammar (metathesis-phase-isolation has real +# PhonologicalRule elements elsewhere), so it cannot serve as the suite's requires:[] home for +# truncation coverage. This fixture is that duplicate requires:[] home, so an XAmple-class +# (phonology-free) engine still gets truncation coverage. +# +# Also carries no on any MorphologicalRule (mruleTruncTrail/mruleTruncLead/ +# mruleTruncOptIns) or LexicalEntry (root32/root33/root42) -- same v1 authoring choice as +# edge-cases/disjunctive-recheck and edge-cases/strrep-identity (adding one would change the +# "+|sa"-style signatures this fixture pins), and it exercises the SAME GrammarRuleIndex Name-based +# fallback those two fixtures' commit introduced. +# +# What this pins (from the v1 fixture's README.md, carried forward verbatim): minimized from +# AffixProcessRuleTests.TruncateRules's 5 sub-cases down to 3 structurally distinct rules sharing one +# grammar -- +# - mruleTruncTrail (case 1/4 combined): a TRAILING segment matched by LITERAL identity +# (, not a natural class) is truncated -- root "sag" -> "sa". +# - mruleTruncLead (case 2/3 combined): a LEADING segment matched by a NATURAL CLASS (Fricative = +# cons+,cont+) is truncated -- root "sag" -> "ag", root "sas" -> "as". +# - mruleTruncOptIns (case 5): an OPTIONAL leading segment combined with an InsertSegments in the +# SAME Rhs -- root "sas" -> "gas" (optional "s" consumed, "g" inserted), root "bubibi" -> "gbubibi" +# (optional part empty, "g" inserted). +# Because morphologicalRuleOrder="unordered", the oracle finds an UNPLANNED but legitimate SECOND +# analysis for "gas": root "sas" --(mruleTruncLead, strips "s")--> "as" +# --(mruleTruncOptIns, optional part empty, inserts "g")--> "gas" -- two rule applications composing +# to the same surface form as the direct one-rule mruleTruncOptIns analysis. Both signatures are +# distinct (leading "+"-count differs: "++" for the 2-hop chain, "+" for the 1-hop direct analysis) +# and both are required; this pins the boundary-count marker surviving a pure-truncation hop with no +# new output material (LT-21939 / HISTORY-MATRIX row 11's "floating marker" fix, referenced in the +# v1 README for the Rust port's own parity history -- not itself a claim about this suite's oracle, +# which is C# throughout). + +language: TruncateRulesProbe +inspired_by: ["synthetic AffixProcessRule truncation probe (not modeling any real language)"] +sources: + - "W9.1 probe, AffixProcessRuleTests.TruncateRules" +requires: [] +words: + - word: sag + note: root32 ("sag") bare, no rule applied -- a plain control proving the root itself is valid before any truncation rule touches it. + parses: + - signature: "|sag" + gloss: "32" + rules: [] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: sas + note: root33 ("sas") bare, no rule applied -- the other plain control root used by the leading-truncation/optional-insertion rows below. + parses: + - signature: "|sas" + gloss: "33" + rules: [] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: bubibi + note: root42 ("bubibi") bare, no rule applied -- the plain control root used by the optional-insertion row (gbubibi) below. + parses: + - signature: "|bubibi" + gloss: "42" + rules: [] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: sa + note: >- + root32 ("sag") + mruleTruncTrail: the trailing segment matched by LITERAL identity + (, not a natural class) is truncated -- "sag" -> "sa". + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + parses: + - signature: "+|sa" + gloss: "32-3SGA" + rules: [mruleTruncTrail] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: ag + note: >- + root32 ("sag") + mruleTruncLead: the leading segment matched by the Fricative natural class + (cons+,cont+, matching "s") is truncated -- "sag" -> "ag". + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + parses: + - signature: "+|ag" + gloss: "32-3SGB" + rules: [mruleTruncLead] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: as + note: root33 ("sas") + mruleTruncLead, the same leading-fricative truncation as "ag" but on the other root -- "sas" -> "as". + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + parses: + - signature: "+|as" + gloss: "33-3SGB" + rules: [mruleTruncLead] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: gbubibi + note: >- + root42 ("bubibi") + mruleTruncOptIns: "bubibi" does not start with "s", so the rule's optional + leading segment matches EMPTY (0 occurrences) and the whole stem is copied, with "g" inserted + in front -- "bubibi" -> "gbubibi". + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + parses: + - signature: "+|gbubibi" + gloss: "42-3SGC" + rules: [mruleTruncOptIns] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: gas + note: >- + THE distinguishing row (unplanned second analysis via morphologicalRuleOrder="unordered"): + root33 ("sas") admits TWO independent, equally valid derivations of "gas" -- + (1) the DIRECT one-rule analysis: mruleTruncOptIns's optional leading segment matches the + stem-initial "s" itself (consumed, not copied) and inserts "g" in front of the remainder + "as" -> "gas"; and + (2) the CHAINED two-rule analysis: mruleTruncLead first strips the leading fricative "s" + ("sas" -> "as"), then mruleTruncOptIns applies to THAT result with its optional part empty + (since "as" doesn't start with "s") and inserts "g" -> "gas". + Both produce byte-identical surface text but are distinct MorphemeId-chain analyses (the + chained one carries one more empty-morpheme "+" boundary marker than the direct one) -- a + conforming engine must report BOTH. + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + parses: + - signature: "++|gas" + gloss: "33-3SGB-3SGC" + rules: [mruleTruncLead, mruleTruncOptIns] + exercises: + - "AffixProcessRule: subtraction/truncation" + - signature: "+|gas" + gloss: "33-3SGC" + rules: [mruleTruncOptIns] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: bag + note: >- + No lexical entry or rule combination produces "bag" at all -- none of the three roots + ("sag"/"sas"/"bubibi") begins with "ba", and no rule's output shape matches it either. A + plain, uncontrived zero-parse control (not itself a disjunctive/environment rejection). + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + expect_fail: true + exercises: + - "AffixProcessRule: subtraction/truncation" diff --git a/conformance/engine-gate-inventory.tsv b/conformance/engine-gate-inventory.tsv new file mode 100644 index 000000000..02d94672f --- /dev/null +++ b/conformance/engine-gate-inventory.tsv @@ -0,0 +1,38 @@ +# GENERATED by hc-conformance --write-engine-gate-inventory. One row per SIL.Machine.Morphology. +# HermitCrab.FailureReason member (excluding None) -- HermitCrab's OWN enumeration of the +# decisions it makes when declining to apply or unapply something, kept alongside (never +# instead of) conformance/dataflow-obligations.tsv's DTD-attribute-pair denominator, because +# the engine's own enum draws different lines than the schema does: it separates gates the DTD +# fuses into one attribute and names several gates no DTD attribute pair expresses at all. +# raise_sites is mechanically scanned (RaiseSiteScanner); dtd_attributes is hand-verified +# against XmlLanguageLoader.cs (see EngineGateInventoryLedger.DtdAttributes' own doc comment) and +# '-' is a genuine finding for six gates, not a placeholder. triggered_by_fixtures/ +# triggering_words/status come from EngineGateWitnessSweep, an ACTUAL traced engine run over +# every non-pathological, non-crash fixture -- status is Witnessed iff some word's trace tree +# contains this FailureReason anywhere, a materially WEAKER claim than a dataflow-obligation +# cell's same-word pair witness (see this file's own doc comment, and conformance/docs/ +# how-it-is-computed.md, for why the two are not comparable strength). +gate raise_sites dtd_attributes triggered_by_fixtures triggering_words status +AllomorphCoOccurrenceRules Allomorph.cs:171 AllomorphCoOccurrenceRule.primaryAllomorph edge-cases/morphotactic-attribute-breadth;languages/suffixing-evidential-adjacency-chain kantancha;sol;takincha Witnessed +BoundRoot RootAllomorph.cs:61 Allomorph.isBound edge-cases/morphotactic-attribute-breadth kul;kulru;kur Witnessed +DisjunctiveAllomorph Allomorph.cs:145 - edge-cases/disjunctive-recheck;edge-cases/free-fluctuating-allomorph-pair;edge-cases/morphotactic-attribute-breadth;edge-cases/strrep-identity imat;ipat;kits;kots;kul;kulbubidu;kulde;kuldede;kulgi;kulgimo;kulmo;kulmoru;kulru;kur;ndmat;ndpat;pakda;pakza;wakta;wokta Witnessed +Environments Allomorph.cs:119 - edge-cases/diacritic-segments;edge-cases/disjunctive-recheck;edge-cases/feature-system-breadth;edge-cases/free-fluctuating-allomorph-pair;edge-cases/strrep-identity;languages/suffixing-evidential-adjacency-chain;languages/suffixing-vowel-harmony añota;esalik;etemik;gölta;ipat;kantay;kit;kot;ndpat;pitda;pitza;salk;sipuy;sipuymi;takiy;tupay;wak;walakni;walaknichik;walaknichiktan;walaknichikwas;walaknitan;walakniwas;walaky;wok Witnessed +ExcludedMprFeatures SynthesisAffixProcessRule.cs:171;SynthesisCompoundingRule.cs:163;SynthesisRealizationalAffixProcessRule.cs:129;SynthesisRewriteSubruleSpec.cs:69 MorphologicalInput.excludedMPRFeatures;HeadMorphologicalInput.excludedMPRFeatures;PhonologicalSubrule.excludedMPRFeatures edge-cases/morphotactic-attribute-breadth;edge-cases/mpr-gated-exception;languages/suffixing-extension-slot-ordering mbe;menanukam;mentanukam;mpe;topdori;vokadan Witnessed +ExcludedStemName RootAllomorph.cs:83 Allomorph.stemName edge-cases/stem-name-restricted-root-allomorph;languages/fusional-realizational-morphology;languages/templatic-root-modification halaku;hilaka;hilaki;hilaku;hulaka;hulaki;hulaku;kapom;mano;mans;mant;mino;mins;mint;muno;muns;munt;tamom Witnessed +HeadPattern SynthesisCompoundingRule.cs:222 - - - Unreached +HeadProdRestrictMprFeatures SynthesisCompoundingRule.cs:124 CompoundingRule.headProdRestrictionsMprFeatures languages/fusional-realizational-morphology seclav Witnessed +HeadRequiredSyntacticFeatureStruct SynthesisCompoundingRule.cs:109 CompoundingRule.headPartsOfSpeech edge-cases/compounding-breadth;languages/polysynthetic-stratal-derivation-chain kutu;patu;takuvuq Witnessed +MaxApplicationCount SynthesisAffixProcessRule.cs:54;SynthesisCompoundingRule.cs:58;SynthesisRealizationalAffixProcessRule.cs:57 MorphologicalRule.multipleApplication;CompoundingRule.multipleApplication edge-cases/feature-gating-breadth;languages/fusional-realizational-morphology;languages/suffixing-extension-slot-ordering feresid;ferid;kalid;kalmuid;limaile Witnessed +MorphemeCoOccurrenceRules Allomorph.cs:193 MorphemeCoOccurrenceRule.primaryMorpheme languages/suffixing-evidential-adjacency-chain;languages/templatic-root-modification samm;sipulupachikmi;siputuku;walaknichikwas;walaknkicha;walakntan Witnessed +NonHeadPattern SynthesisCompoundingRule.cs:215 - - - Unreached +NonHeadProdRestrictMprFeatures AnalysisCompoundingRule.cs:90 CompoundingRule.nonHeadProdRestrictionsMprFeatures - - Unreached +NonHeadRequiredSyntacticFeatureStruct SynthesisCompoundingRule.cs:93 CompoundingRule.nonHeadPartsOfSpeech - - Unreached +NonPartialRuleProhibitedAfterFinalTemplate SynthesisAffixProcessRule.cs:76;SynthesisCompoundingRule.cs:73 AffixTemplate.final;MorphologicalRule.partial edge-cases/disjunctive-recheck;edge-cases/free-fluctuating-allomorph-pair;edge-cases/mpr-gated-exception;edge-cases/mpr-overwrite-order-dependence;edge-cases/process-morphology-in-place-mutation;edge-cases/stem-name-restricted-root-allomorph;edge-cases/strrep-identity;edge-cases/truncate-morphotactic;languages/fusional-realizational-morphology;languages/metathesis-phase-isolation;languages/polysynthetic-stratal-derivation-chain;languages/suffixing-vowel-harmony;languages/templatic-root-modification a;ag;akutat;as;bahain;benox;corriv;daboxayu;daboxayuzi;daboyuxa;daboyuxazi;ducit;ducunt;esalik;etemik;femopiqu;femopiquvo;femoqupi;femoqupivo;feres;feresid;ficlav;gas;gbubibi;gelobt;gelobth;genlav;gigigi;gigugi;guan;halaku;hilaka;hilaki;hilaku;hulaka;hulaki;hulaku;iktub;imat;ipat;kalitin;kalutun;kapom;kapur;kataba;katabit;katabt;katabɯd;katibɯd;keadilan;kits;kots;lexbedom;lexdom;lobh;man;mano;mans;mant;mat;membalo;menanukam;mentanukam;menulik;mino;mins;mint;mitlav;mu+i;mumat;muno;muns;munt;mupat;muuta;mwuta;ndmat;ndpat;nunaliq;nunaliqvuq;nunavuq;pakda;pakza;pannox;pat;pitat;pitda;pitza;pui;pur;pure;qil;sa;samm;sang;sanitan;sapr;satun;seclav;setin;silamanuk;silanuk;sueb;sueeb;sumulat;takuvuq;tamom;tamur;tulatula;tutula;uta;vinc;vokadan;vokadi;wakta;wokta Witnessed +NonPartialRuleRequiredAfterNonFinalTemplate SynthesisAffixProcessRule.cs:99 AffixTemplate.final;MorphologicalRule.partial - - Unreached +ObligatorySyntacticFeatures Morpher.cs:613 MorphologicalRule.outputObligatoryFeatures;CompoundingRule.outputObligatoryFeatures - - Unreached +PartialParse Morpher.cs:599;SynthesisStratumRule.cs:72;TraceManager.cs:151;TraceManager.cs:162 Slot.optional;AffixTemplate.final edge-cases/compounding-breadth;edge-cases/diacritic-segments;edge-cases/disjunctive-recheck;edge-cases/feature-gating-breadth;edge-cases/feature-system-breadth;edge-cases/free-fluctuating-allomorph-pair;edge-cases/loader-isactive-breadth;edge-cases/morphotactic-attribute-breadth;edge-cases/mpr-gated-exception;edge-cases/mpr-group-overwrite-without-realizational;edge-cases/mpr-overwrite-order-dependence;edge-cases/process-morphology-in-place-mutation;edge-cases/stem-name-restricted-root-allomorph;edge-cases/strrep-identity;edge-cases/subrule-morphosyntactic-gating;edge-cases/truncate-morphotactic;languages/fusional-realizational-morphology;languages/metathesis-phase-isolation;languages/polysynthetic-stratal-derivation-chain;languages/prefixal-discontinuous-slot-dependency;languages/suffixing-evidential-adjacency-chain;languages/suffixing-extension-slot-ordering;languages/suffixing-vowel-harmony;languages/templatic-root-modification a;ag;akutat;andik;andika;andikila;andikilisha;andikisha;andikishila;as;años;añota;bahain;bak;bakgi;bat;belh;belw;benox;bishiwodkal;bishiyidkal;cafés;caféta;corriv;dabep;dabepez;dabez;daboxayu;daboxayuzi;daboyuxa;daboyuxazi;daheh;daleh;dalehiz;dalizeh;dom;ducit;ducunt;esalik;etemik;femopiqu;femopiquvo;femoqupi;femoqupivo;feres;feresid;ficlav;gabishiyidkal;gas;gbubibi;gelobt;gelobth;genlav;gigigi;gigugi;gofwh;gofz;gofzw;guan;göls;gölta;halaku;hilaka;hilaki;hilaku;hogabishiyidkal;hulaka;hulaki;hulaku;ikt;iktub;imat;ipat;itk;kal;kalitin;kalka;kalkano;kalmuid;kalutun;kantancha;kantay;kapom;kapur;kataba;katabit;katabt;katabɯd;kath;katibɯd;katu;katw;keadilan;kelîs;kelîta;kesepez;kesez;kibh;kibw;kimbiakimbia;kits;kots;kul;kulbubidu;kulde;kuldede;kulgi;kulgimo;kulmo;kulmoru;kulpu;kulru;kur;kutagida;kutagila;kutak;kutakler;kutu;lexbedom;lexdom;limaile;limape;limapeile;limh;limw;lisez;lobh;man;mano;mans;mant;mat;membalo;menanukam;mentanukam;menulik;mino;mins;mint;mitlav;mo+kul;molka;mu+i;mumat;muno;muns;munt;mupat;muuta;mwuta;nalh;nalno;nalnomu;nalw;napmo;nbael;ndmat;ndpat;npael;nunaliq;nunaliqvuq;nunavuq;pakda;pakza;pannox;pat;patu;pitat;pitda;pitza;pogli;pogliti;pogti;pui;pur;pure;qil;rog;sa;salk;samm;sang;sanitan;sapr;satun;seclav;sekhw;sekwh;sekwz;sekzw;semitide;semitideler;semitile;setin;silamanuk;silanuk;siliz;siliziz;sim;simru;sipulupachikmi;sipulupami;sipun;sipuncha;siputuku;siputukuchikmi;siputukumi;sipuy;sipuymi;sodh;sodw;sol;sueb;sueeb;sumulat;takincha;takiy;takul;takuvuq;tamom;tamur;tik;top;topdo;topdori;topri;topsakanabu;topsakatana;tulatula;tunka;tupay;tutula;udof;udofq;unitide;uta;vinc;vokadan;vokadi;wakta;walakchik;walakni;walaknichik;walaknichiktan;walaknichikwas;walaknitan;walakniwas;walaknki;walaknkicha;walaknkichikmi;walaknkishi;walaknkisi;walakntan;walaky;wokta;wudof;wudofq;xkib;xkibz;xped;xpedz;ygofz;yxkib;yxkibz;yxped;yxpedz;zamed;zimed Witnessed +Pattern SynthesisAffixProcessRule.cs:231;SynthesisMetathesisRule.cs:52;SynthesisRealizationalAffixProcessRule.cs:179;SynthesisRewriteRule.cs:82 - edge-cases/feature-system-breadth;edge-cases/loader-default-symbol;edge-cases/mpr-gated-exception;edge-cases/process-morphology-in-place-mutation;edge-cases/right-to-left-anchor-environment;edge-cases/strrep-identity;languages/metathesis-phase-isolation;languages/polysynthetic-stratal-derivation-chain;languages/suffixing-extension-slot-ordering;languages/suffixing-vowel-harmony;languages/templatic-root-modification a;aa;aaa;aae;ae;ak;andika;andikila;andikilisha;andikisha;andikishila;ask;at;balo;bat;bel;belh;bubu;buibu;buiibuii;buuubuuu;dabez;daleh;dalizeh;duii;duy;esalik;etemik;gan;gigigi;gigugi;gigugu;guan;halak;halaku;hilaka;hilaki;hilaku;hulaka;hulaki;hulaku;ik;ikt;iktub;imat;ipat;isk;it;itk;ka;kalit;kalitin;kalut;kalutun;katab;kataba;katabit;katabt;kes;kib;kibw;kimbia;kimbiakimbia;ktb;ktl;ktub;kuiikuii;kutagida;kutagila;kuuukuuu;lima;limaile;lisez;mat;matu;mau;mba;membalo;menanukam;mentanukam;menulik;mi;mpa;mu+i;mumat;mupat;nal;nba;ndmat;ndpat;niu;npa;nui;pat;pui;pur;pure;qal;qil;rada;radda;sal;salk;samm;sanit;sanitan;sapr;sat;satun;sek;sekwh;sekzw;semitide;semitideler;semitile;set;setin;siliz;smm;spr;sueb;sueeb;tanuk;tem;ti;tik;tkl;tlk;ts;tulik;unitide;utui;uui;uuu;vokad;vokadi;xkib;xkibz;yxkib;zamed;zimed Witnessed +RequiredMprFeatures SynthesisAffixProcessRule.cs:154;SynthesisCompoundingRule.cs:146;SynthesisRealizationalAffixProcessRule.cs:112;SynthesisRewriteSubruleSpec.cs:54 MorphologicalInput.requiredMPRFeatures;HeadMorphologicalInput.requiredMPRFeatures;PhonologicalSubrule.requiredMPRFeatures edge-cases/mpr-group-overwrite-without-realizational;edge-cases/mpr-overwrite-order-dependence;languages/fusional-realizational-morphology;languages/prefixal-discontinuous-slot-dependency;languages/suffixing-extension-slot-ordering andik;andika;andikila;andikilisha;andikisha;andikishila;bel;belh;belw;bishiwodkal;dabep;dabepez;dabez;daboxayuzi;daheh;daleh;dalehiz;dalizeh;ficlav;genlav;kath;kes;kesepez;kesez;kib;kibh;kibw;kimbia;kimbiakimbia;lima;limaile;limape;limapeile;limh;limw;lisez;mba;mbe;mpa;mpe;nal;nalh;nalw;nba;nbael;niyidtan;npa;npael;sek;sekhw;sekwh;sekwz;sekzw;siliz;siliziz;sodw;wudofq;xkib;xkibz;ygofz;yxkib;yxkibz;yxpedz;zamed Witnessed +RequiredStemName RootAllomorph.cs:68;SynthesisAffixProcessRule.cs:114 Allomorph.stemName;MorphologicalRule.requiredStemName edge-cases/stem-name-restricted-root-allomorph;languages/fusional-realizational-morphology;languages/suffixing-extension-slot-ordering;languages/templatic-root-modification daheh;halak;halaku;hilaka;hilaku;hulaka;hulaku;kap;kapur;man;mans;mant;min;mins;mint;mun;muns;munt;tam;tamur Witnessed +RequiredSyntacticFeatureStruct AffixProcessAllomorph.cs:96;SynthesisAffixProcessRule.cs:130;SynthesisRealizationalAffixProcessRule.cs:88;SynthesisRewriteSubruleSpec.cs:38 MorphologicalRule.requiredPartsOfSpeech;PhonologicalSubrule.requiredPartsOfSpeech edge-cases/feature-gating-breadth;edge-cases/mpr-gated-exception;edge-cases/subrule-morphosyntactic-gating;languages/fusional-realizational-morphology;languages/metathesis-phase-isolation;languages/polysynthetic-stratal-derivation-chain;languages/suffixing-extension-slot-ordering;languages/suffixing-vowel-harmony;languages/templatic-root-modification adil;andika;andikila;andikilisha;andikisha;andikishila;baha;bahain;bat;belh;belw;benox;buiibuii;buuubuuu;dabep;dabepez;dabez;daheh;daleh;dalehiz;dalizeh;duii;duy;esalik;etemik;gigigi;gigugi;gigugu;guan;halak;halaku;hilaka;hilaki;hilaku;hulaka;hulaki;hulaku;idil;iktub;katab;kataba;katabit;katabt;keadilan;kesepez;kesez;kibh;kibw;ktub;kuiikuii;kutagida;kutagila;kuuukuuu;lexbedom;limaile;limape;limapeile;lisez;lobh;man;mbe;mint;molka;mpe;mu+i;nalh;nalw;nba;nbael;npa;npael;nunavuq;pannox;pat;pitat;pui;pur;pure;qal;qil;rada;radda;samm;sanit;sanitan;sapr;sekhw;sekwh;sekwz;sekzw;semitide;semitideler;semitile;silamanuk;siliz;siliziz;smm;spr;sueb;sueeb;sulat;sumulat;tula;tulatula;tunka;tutula;unitide;utui;uui;uuu;vokad;vokadi;zamed;zimed Witnessed +SurfaceFormMismatch Morpher.cs:630 - edge-cases/alpha-variable-name-collision;edge-cases/disjunctive-recheck;edge-cases/feature-gating-breadth;edge-cases/feature-system-breadth;edge-cases/free-fluctuating-allomorph-pair;edge-cases/loader-default-symbol;edge-cases/metathesis-comparison-crash;edge-cases/morphotactic-attribute-breadth;edge-cases/mpr-gated-exception;edge-cases/right-to-left-anchor-environment;edge-cases/stem-name-restricted-root-allomorph;edge-cases/strrep-identity;edge-cases/subrule-morphosyntactic-gating;languages/fusional-realizational-morphology;languages/metathesis-phase-isolation;languages/polysynthetic-stratal-derivation-chain;languages/suffixing-evidential-adjacency-chain;languages/suffixing-extension-slot-ordering;languages/suffixing-vowel-harmony;languages/templatic-root-modification aa;aaa;ak;ask;au;bak;bakgi;bat;bdt;buibu;buiibuii;dom;ducit;duii;eaaa;eeee;ferid;genlav;gigigi;gigugi;gigugu;gray;grey;halaku;hilaka;hilaki;hulaki;hulaku;idil;ikt;imat;ipat;it;itk;kalid;kalit;kalitin;kantancha;kantay;kap;kapur;katabt;katabɯd;kit;kots;ktl;ktub;kuiikuii;kul;kulbubidu;kulde;kuldede;kulgi;kulgimo;kulmo;kulmoru;kulru;kur;limaile;man;mano;mant;mat;matu;mbe;menanukam;min;mino;mins;mpa;mumat;muno;muns;munt;mupat;muuta;nbael;ndmat;ndpat;niu;npa;pakda;pat;pel;pitza;pol;rada;rog;sim;simru;sueb;sueeb;takiy;takuvuq;tamom;ti;tik;tkl;top;topdo;topri;topsakanabu;topsakatana;uta;utui;uuu;wakta;walaknkishi;walaknkisi;walaky;wok;zamed;zimed Witnessed diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__052ae9e692.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__052ae9e692.md new file mode 100644 index 000000000..d19735dff --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__052ae9e692.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__0a7b6ab127.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__0a7b6ab127.md new file mode 100644 index 000000000..bd94a58b5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__0a7b6ab127.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__12c1dd278b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__12c1dd278b.md new file mode 100644 index 000000000..423e6d436 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__12c1dd278b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__465d14e7ea.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__465d14e7ea.md new file mode 100644 index 000000000..41ae14c3f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__465d14e7ea.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__467816e969.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__467816e969.md new file mode 100644 index 000000000..605340a9f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__467816e969.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__567ab12323.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__567ab12323.md new file mode 100644 index 000000000..968f8a63f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__567ab12323.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__7e8dfce20c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__7e8dfce20c.md new file mode 100644 index 000000000..2569c312c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__7e8dfce20c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__93c811f4d5.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__93c811f4d5.md new file mode 100644 index 000000000..7af102a03 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__93c811f4d5.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__a2eb8294a4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__a2eb8294a4.md new file mode 100644 index 000000000..289a3e814 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__a2eb8294a4.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__aa369d5755.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__aa369d5755.md new file mode 100644 index 000000000..4128636f4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__aa369d5755.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__abc75d50e6.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__abc75d50e6.md new file mode 100644 index 000000000..741d0b589 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__abc75d50e6.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__b0e58b74f2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__b0e58b74f2.md new file mode 100644 index 000000000..2c37dc34b --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__b0e58b74f2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c458c1ff29.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c458c1ff29.md new file mode 100644 index 000000000..e3bf42d2b --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c458c1ff29.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c6138fd4fd.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c6138fd4fd.md new file mode 100644 index 000000000..93124f250 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c6138fd4fd.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__ef1546bf5d.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__ef1546bf5d.md new file mode 100644 index 000000000..f2eec6c20 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__ef1546bf5d.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__fd29133b69.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__fd29133b69.md new file mode 100644 index 000000000..204630d53 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__fd29133b69.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__1eda51418f.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__1eda51418f.md new file mode 100644 index 000000000..9fc3e3431 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__1eda51418f.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__35c72b2b37.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__35c72b2b37.md new file mode 100644 index 000000000..b5a6eba9e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__35c72b2b37.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__37c442dab7.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__37c442dab7.md new file mode 100644 index 000000000..0ee444581 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__37c442dab7.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__405a9614b4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__405a9614b4.md new file mode 100644 index 000000000..16fe71b8f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__405a9614b4.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__415b26f386.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__415b26f386.md new file mode 100644 index 000000000..43535aa5c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__415b26f386.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__4d08fbcb7c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__4d08fbcb7c.md new file mode 100644 index 000000000..47d673c99 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__4d08fbcb7c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__56ff64b77c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__56ff64b77c.md new file mode 100644 index 000000000..6b4ab25b7 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__56ff64b77c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__5fea2ced00.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__5fea2ced00.md new file mode 100644 index 000000000..74bc4146d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__5fea2ced00.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9226354c95.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9226354c95.md new file mode 100644 index 000000000..f849e3fe1 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9226354c95.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9299596233.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9299596233.md new file mode 100644 index 000000000..a9746e688 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9299596233.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__96581b2cd9.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__96581b2cd9.md new file mode 100644 index 000000000..28bbe1b79 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__96581b2cd9.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__97b09dae7d.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__97b09dae7d.md new file mode 100644 index 000000000..9e9c5ef61 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__97b09dae7d.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__cddbf27789.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__cddbf27789.md new file mode 100644 index 000000000..ed1caf50a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__cddbf27789.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d796a07fa2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d796a07fa2.md new file mode 100644 index 000000000..4a302d605 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d796a07fa2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d99534f349.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d99534f349.md new file mode 100644 index 000000000..316a544c3 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d99534f349.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__e66f1ca54a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__e66f1ca54a.md new file mode 100644 index 000000000..33c2b9e2c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__e66f1ca54a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__1517146226.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__1517146226.md new file mode 100644 index 000000000..6c572023d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__1517146226.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2758486360.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2758486360.md new file mode 100644 index 000000000..b0b977a8a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2758486360.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2e5601a4c2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2e5601a4c2.md new file mode 100644 index 000000000..24c942c53 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2e5601a4c2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2f467ca65b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2f467ca65b.md new file mode 100644 index 000000000..86fc06152 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2f467ca65b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__64995b1c65.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__64995b1c65.md new file mode 100644 index 000000000..4faff6675 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__64995b1c65.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__6b8f280520.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__6b8f280520.md new file mode 100644 index 000000000..348ce842a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__6b8f280520.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__78f6bef8c8.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__78f6bef8c8.md new file mode 100644 index 000000000..81f921a7e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__78f6bef8c8.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__790befcd64.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__790befcd64.md new file mode 100644 index 000000000..cf21e3d4a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__790befcd64.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__8bd9dcbef2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__8bd9dcbef2.md new file mode 100644 index 000000000..b52202ebb --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__8bd9dcbef2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__906fe66113.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__906fe66113.md new file mode 100644 index 000000000..717efc197 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__906fe66113.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__9075d6cf1e.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__9075d6cf1e.md new file mode 100644 index 000000000..f1dd8c0f2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__9075d6cf1e.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__b0b0b46a1a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__b0b0b46a1a.md new file mode 100644 index 000000000..6249a1de6 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__b0b0b46a1a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cc92c992f8.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cc92c992f8.md new file mode 100644 index 000000000..aae37b8b9 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cc92c992f8.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__ce747db9c8.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__ce747db9c8.md new file mode 100644 index 000000000..30a55d85d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__ce747db9c8.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cfcaf6aad9.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cfcaf6aad9.md new file mode 100644 index 000000000..3549546de --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cfcaf6aad9.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__d5e5d69c61.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__d5e5d69c61.md new file mode 100644 index 000000000..bb828c29d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__d5e5d69c61.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__dcb5cdf354.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__dcb5cdf354.md new file mode 100644 index 000000000..778bf9a35 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__dcb5cdf354.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__eb45ca963c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__eb45ca963c.md new file mode 100644 index 000000000..095036195 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__eb45ca963c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe09105f72.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe09105f72.md new file mode 100644 index 000000000..030f5721f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe09105f72.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe117dd02d.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe117dd02d.md new file mode 100644 index 000000000..8f9575d4e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe117dd02d.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1c84ebb58a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1c84ebb58a.md new file mode 100644 index 000000000..7d4f8a0a2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1c84ebb58a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1f2b9caf36.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1f2b9caf36.md new file mode 100644 index 000000000..582eb5696 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1f2b9caf36.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__253ea8070c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__253ea8070c.md new file mode 100644 index 000000000..318a24f15 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__253ea8070c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__27d1114083.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__27d1114083.md new file mode 100644 index 000000000..9217950bd --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__27d1114083.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__421fa34556.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__421fa34556.md new file mode 100644 index 000000000..da6bd23a1 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__421fa34556.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__5eca01cd32.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__5eca01cd32.md new file mode 100644 index 000000000..a9c6f2b37 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__5eca01cd32.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__6374bee20a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__6374bee20a.md new file mode 100644 index 000000000..9b4a95d0a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__6374bee20a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__864a3c00a3.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__864a3c00a3.md new file mode 100644 index 000000000..cd33522c9 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__864a3c00a3.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__a60574b201.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__a60574b201.md new file mode 100644 index 000000000..0d8cea4fb --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__a60574b201.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__abda497cb4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__abda497cb4.md new file mode 100644 index 000000000..fecd6ad87 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__abda497cb4.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__b54787693b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__b54787693b.md new file mode 100644 index 000000000..a5c10eefe --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__b54787693b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c1a283bb40.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c1a283bb40.md new file mode 100644 index 000000000..53e3faafc --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c1a283bb40.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c4d80b41ec.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c4d80b41ec.md new file mode 100644 index 000000000..98c68d2bf --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c4d80b41ec.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c775f67d2b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c775f67d2b.md new file mode 100644 index 000000000..da474ca18 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c775f67d2b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__d4c7012b97.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__d4c7012b97.md new file mode 100644 index 000000000..32aea6080 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__d4c7012b97.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__dd4151c4fe.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__dd4151c4fe.md new file mode 100644 index 000000000..4040bb725 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__dd4151c4fe.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__ebb45949a6.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__ebb45949a6.md new file mode 100644 index 000000000..fd4a3b20c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__ebb45949a6.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f3ebd9210b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f3ebd9210b.md new file mode 100644 index 000000000..a9dbffd11 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f3ebd9210b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f749d716c7.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f749d716c7.md new file mode 100644 index 000000000..babd4e745 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f749d716c7.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f8b238ecbe.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f8b238ecbe.md new file mode 100644 index 000000000..fb2d71f7f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f8b238ecbe.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputProdRestrictionsMprFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__203812db54.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__203812db54.md new file mode 100644 index 000000000..9cbc3ee8a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__203812db54.md @@ -0,0 +1,53 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`CompoundingRule.headProdRestrictionsMprFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed headProdRestrictionsMprFeatures from 1 element(s)", example: 'seclav': ok::- -> ok::SEC+LAV|sec+?lav + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `CompoundingRule.headProdRestrictionsMprFeatures`: `grammar.xml:411` = "mprCompReq" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__58bce01d05.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__58bce01d05.md new file mode 100644 index 000000000..a89cb3698 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__58bce01d05.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__98401f9202.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__98401f9202.md new file mode 100644 index 000000000..f89c113e2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__98401f9202.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__9b745dcd86.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__9b745dcd86.md new file mode 100644 index 000000000..951c0b098 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__9b745dcd86.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a46fb6d267.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a46fb6d267.md new file mode 100644 index 000000000..09d064295 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a46fb6d267.md @@ -0,0 +1,53 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`CompoundingRule.headProdRestrictionsMprFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed headProdRestrictionsMprFeatures from 1 element(s)", example: 'seclav': ok::- -> ok::SEC+LAV|sec+?lav + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `CompoundingRule.headProdRestrictionsMprFeatures`: `grammar.xml:411` = "mprCompReq" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a92ba2d57e.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a92ba2d57e.md new file mode 100644 index 000000000..75a65bb85 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a92ba2d57e.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__babe17f79e.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__babe17f79e.md new file mode 100644 index 000000000..5cee6fe18 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__babe17f79e.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__effb1f89e2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__effb1f89e2.md new file mode 100644 index 000000000..a77dc17b4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__effb1f89e2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__1b3451751a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__1b3451751a.md new file mode 100644 index 000000000..6d29df376 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__1b3451751a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__54bf8baa0b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__54bf8baa0b.md new file mode 100644 index 000000000..2b837adcf --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__54bf8baa0b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__62cc6f6e55.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__62cc6f6e55.md new file mode 100644 index 000000000..1d4bbe56e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__62cc6f6e55.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__8bacba3d80.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__8bacba3d80.md new file mode 100644 index 000000000..58edeaabe --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__8bacba3d80.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__9ae48b649a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__9ae48b649a.md new file mode 100644 index 000000000..58662facc --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__9ae48b649a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__a339c69438.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__a339c69438.md new file mode 100644 index 000000000..8be7e34f9 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__a339c69438.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__adb12adc76.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__adb12adc76.md new file mode 100644 index 000000000..e297840ab --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__adb12adc76.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__c494cd5fcb.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__c494cd5fcb.md new file mode 100644 index 000000000..c34e14a5e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__c494cd5fcb.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__087a1ee277.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__087a1ee277.md new file mode 100644 index 000000000..c7a9a55d5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__087a1ee277.md @@ -0,0 +1,53 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`HeadMorphologicalInput.excludedMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed excludedMPRFeatures from 1 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `HeadMorphologicalInput.excludedMPRFeatures`: `grammar.xml:428` = "mprSubA" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__0b282120a4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__0b282120a4.md new file mode 100644 index 000000000..015d375ac --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__0b282120a4.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__357f5a25bc.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__357f5a25bc.md new file mode 100644 index 000000000..74c540905 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__357f5a25bc.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__3b313cba38.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__3b313cba38.md new file mode 100644 index 000000000..317e10f8a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__3b313cba38.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__5603689493.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__5603689493.md new file mode 100644 index 000000000..415e8fc41 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__5603689493.md @@ -0,0 +1,53 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`HeadMorphologicalInput.excludedMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed excludedMPRFeatures from 1 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `HeadMorphologicalInput.excludedMPRFeatures`: `grammar.xml:428` = "mprSubA" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__6f38e7a899.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__6f38e7a899.md new file mode 100644 index 000000000..9a7c82740 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__6f38e7a899.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__a1d7e84b20.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__a1d7e84b20.md new file mode 100644 index 000000000..1591cf781 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__a1d7e84b20.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__e721931de3.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__e721931de3.md new file mode 100644 index 000000000..c6de12496 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__e721931de3.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__1f9a1ccadc.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__1f9a1ccadc.md new file mode 100644 index 000000000..d31339a35 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__1f9a1ccadc.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__5000df9f32.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__5000df9f32.md new file mode 100644 index 000000000..5d62eace2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__5000df9f32.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__65217a5ef6.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__65217a5ef6.md new file mode 100644 index 000000000..a27d034bb --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__65217a5ef6.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7291112a11.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7291112a11.md new file mode 100644 index 000000000..099d8731c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7291112a11.md @@ -0,0 +1,53 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`HeadMorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed requiredMPRFeatures from 1 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `HeadMorphologicalInput.requiredMPRFeatures`: `grammar.xml:423` = "mprSubA" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7f676b3fc5.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7f676b3fc5.md new file mode 100644 index 000000000..6a1e19240 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7f676b3fc5.md @@ -0,0 +1,53 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`HeadMorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed requiredMPRFeatures from 1 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `HeadMorphologicalInput.requiredMPRFeatures`: `grammar.xml:423` = "mprSubA" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__caf3c5dd47.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__caf3c5dd47.md new file mode 100644 index 000000000..fb2b353f5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__caf3c5dd47.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__de9acd72d5.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__de9acd72d5.md new file mode 100644 index 000000000..6ffe934ac --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__de9acd72d5.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__ffff27d9b0.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__ffff27d9b0.md new file mode 100644 index 000000000..9b2802870 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__ffff27d9b0.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__0d618c944c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__0d618c944c.md new file mode 100644 index 000000000..42b5d507c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__0d618c944c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__5026df6a95.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__5026df6a95.md new file mode 100644 index 000000000..27807ffe9 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__5026df6a95.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__702762c0f9.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__702762c0f9.md new file mode 100644 index 000000000..8fa10b19d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__702762c0f9.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__7a25f70cd7.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__7a25f70cd7.md new file mode 100644 index 000000000..377e6f231 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__7a25f70cd7.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__a65827b3c9.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__a65827b3c9.md new file mode 100644 index 000000000..fdc92fefd --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__a65827b3c9.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b7765fce5a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b7765fce5a.md new file mode 100644 index 000000000..78086ce8c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b7765fce5a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b991bc3075.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b991bc3075.md new file mode 100644 index 000000000..49cab602d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b991bc3075.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__bd8e009600.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__bd8e009600.md new file mode 100644 index 000000000..824813838 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__bd8e009600.md @@ -0,0 +1,52 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'vokadan' from failed to successful parse in edge-cases/mpr-gated-exception (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'vokadan'** in `edge-cases/mpr-gated-exception` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (edge-cases/mpr-gated-exception / 'vokadan') + +- Severing: either VOKAD's LexicalEntry.ruleFeatures="mprException" (the writer) or mrSuf's MorphologicalInput.excludedMPRFeatures="mprException" gate (the reader) -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::VOKAD+SUF|vokadan` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `edge-cases/mpr-gated-exception`): verdict=Evidenced, mutation="removed ruleFeatures from 1 element(s)", example: 'vokadan': ok::- -> ok::VOKAD+SUF|vokadan +- Reader (`MorphologicalInput.excludedMPRFeatures` in `edge-cases/mpr-gated-exception`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'vokadan': ok::- -> ok::VOKAD+SUF|vokadan + +## Grammar citations + +### `edge-cases/mpr-gated-exception/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:282` = "mprException" +- Reader (gate declared here) `MorphologicalInput.excludedMPRFeatures`: `grammar.xml:222` = "mprException" + +## Author's prose + +- `proof:` (claimed_cells, 'vokadan' in edge-cases/mpr-gated-exception): vokadan is VOKAD (carries mprException) + mrSuf; with both constructs intact the derivation is blocked (ok::-). Removing either the writer (VOKAD's ruleFeatures) or the reader (mrSuf's excludedMPRFeatures) lets the same derivation through, producing VOKAD+SUF|vokadan -- the PresentGatedForm arm: the feature is PRESENT on the root and the rule's exclusion GATES on it. sanitan (SANIT, no mprException) is the plain control that shows mrSuf fires normally when the feature is simply absent, so vokadan's block is attributable to the gate, not to mrSuf never applying at all. + +## `distinct_from` counterpart + +- 'vokadan' in edge-cases/mpr-gated-exception: `distinct_from` **'sanitan'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__e5f69f5a64.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__e5f69f5a64.md new file mode 100644 index 000000000..455ed8966 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__e5f69f5a64.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__ebbec8602a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__ebbec8602a.md new file mode 100644 index 000000000..ee8964ee5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__ebbec8602a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__0f3d86ac4b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__0f3d86ac4b.md new file mode 100644 index 000000000..15bfd6468 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__0f3d86ac4b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__1c74446857.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__1c74446857.md new file mode 100644 index 000000000..8bd34abf4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__1c74446857.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__2c09dc0c6a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__2c09dc0c6a.md new file mode 100644 index 000000000..beadb51df --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__2c09dc0c6a.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3Control:languages/fusional-realizational-morphology + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +Extra MC/DC vector #3, required because the reader's gate has more than one condition -- see the chain kind below. This arm is where the reader does NOT block (control). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `ConditionExtension` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: mechanically required by 2-condition gate observed in languages/fusional-realizational-morphology ('mprConjA mprConjB'); no per-vector witness check implemented yet + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__41e8e8056f.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__41e8e8056f.md new file mode 100644 index 000000000..85669f7dc --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__41e8e8056f.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__44f82457d0.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__44f82457d0.md new file mode 100644 index 000000000..e210fcc0c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__44f82457d0.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__480dfb8ea4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__480dfb8ea4.md new file mode 100644 index 000000000..a82e3c69a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__480dfb8ea4.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__57f78eca98.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__57f78eca98.md new file mode 100644 index 000000000..bba7e2468 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__57f78eca98.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__6c132d754d.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__6c132d754d.md new file mode 100644 index 000000000..bf14ee6f4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__6c132d754d.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__a6edbbf91c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__a6edbbf91c.md new file mode 100644 index 000000000..e67651566 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__a6edbbf91c.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__bc8720c649.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__bc8720c649.md new file mode 100644 index 000000000..fa4f9011c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__bc8720c649.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__e4dac625a8.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__e4dac625a8.md new file mode 100644 index 000000000..eecfc60f3 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__e4dac625a8.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3GatedForm:languages/fusional-realizational-morphology + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +Extra MC/DC vector #3, required because the reader's gate has more than one condition -- see the chain kind below. This arm is where the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `ConditionExtension` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: mechanically required by 2-condition gate observed in languages/fusional-realizational-morphology ('mprConjA mprConjB'); no per-vector witness check implemented yet + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__fc52e807aa.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__fc52e807aa.md new file mode 100644 index 000000000..a7eb9f381 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__fc52e807aa.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed ruleFeatures from 6 element(s)", example: 'gofz': ok::GOF+ENDZ|gofz -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:543` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:557` = "mprCompReq mprSubA" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:562` = "mprCompReq" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:652` = "mprConjA mprConjB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:657` = "mprConjA mprConjC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:670` = "mprPedA mprConjA mprConjB mprConjC" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__02e8c1d4b0.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__02e8c1d4b0.md new file mode 100644 index 000000000..4cc290593 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__02e8c1d4b0.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__046705cf46.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__046705cf46.md new file mode 100644 index 000000000..eae262d83 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__046705cf46.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__0e07ff724c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__0e07ff724c.md new file mode 100644 index 000000000..d8c8c4fd6 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__0e07ff724c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__4dab0fc534.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__4dab0fc534.md new file mode 100644 index 000000000..21ff06204 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__4dab0fc534.md @@ -0,0 +1,54 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed ruleFeatures from 7 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe +- Reader (`PhonologicalSubrule.excludedMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:617` = "mprConcA mprConcB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:622` = "mprConcA mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:645` = "mprPhX" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:650` = "mprPhExcl" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:658` = "mprExtA mprConcA mprConcB mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:714` = "mprRRealTest" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:720` = "mprRRealTest" +- Reader (gate declared here) `PhonologicalSubrule.excludedMPRFeatures`: `grammar.xml:340` = "mprPhExcl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__9238acddc7.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__9238acddc7.md new file mode 100644 index 000000000..29df166b0 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__9238acddc7.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__accfca0bda.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__accfca0bda.md new file mode 100644 index 000000000..2af13ee9a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__accfca0bda.md @@ -0,0 +1,58 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'mbe' from failed to successful parse in languages/suffixing-extension-slot-ordering (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'mbe'** in `languages/suffixing-extension-slot-ordering` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (languages/suffixing-extension-slot-ordering / 'mbe') + +- Severing: either PPE's own LexicalEntry.ruleFeatures="mprPhExcl" (the writer) or prPhonoExcl's own PhonologicalSubrule.excludedMPRFeatures="mprPhExcl" gate (the reader) -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::PPE|mbe` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed ruleFeatures from 7 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe +- Reader (`PhonologicalSubrule.excludedMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:617` = "mprConcA mprConcB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:622` = "mprConcA mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:645` = "mprPhX" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:650` = "mprPhExcl" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:658` = "mprExtA mprConcA mprConcB mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:714` = "mprRRealTest" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:720` = "mprRRealTest" +- Reader (gate declared here) `PhonologicalSubrule.excludedMPRFeatures`: `grammar.xml:340` = "mprPhExcl" + +## Author's prose + +- `proof:` (claimed_cells, 'mbe' in languages/suffixing-extension-slot-ordering): mbe is PPE (carries mprPhExcl) attempting the post-nasal voicing minor rule; with both constructs intact the mutation is blocked (zero parses). Removing either the writer (PPE's ruleFeatures) or the reader (prPhonoExcl's excludedMPRFeatures) lets the same mutation through, producing PPE|mbe -- the PresentGatedForm arm: the feature is PRESENT on the root and the rule's exclusion GATES on it. + +## `distinct_from` counterpart + +- 'mbe' in languages/suffixing-extension-slot-ordering: `distinct_from` **'mpe'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__b2d1b47c42.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__b2d1b47c42.md new file mode 100644 index 000000000..9ee21c41d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__b2d1b47c42.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__d082d864eb.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__d082d864eb.md new file mode 100644 index 000000000..4ccb2e68b --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__d082d864eb.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e09a3fc53a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e09a3fc53a.md new file mode 100644 index 000000000..836525e83 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e09a3fc53a.md @@ -0,0 +1,54 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed ruleFeatures from 7 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe +- Reader (`PhonologicalSubrule.excludedMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:617` = "mprConcA mprConcB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:622` = "mprConcA mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:645` = "mprPhX" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:650` = "mprPhExcl" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:658` = "mprExtA mprConcA mprConcB mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:714` = "mprRRealTest" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:720` = "mprRRealTest" +- Reader (gate declared here) `PhonologicalSubrule.excludedMPRFeatures`: `grammar.xml:340` = "mprPhExcl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e31f5ff6a6.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e31f5ff6a6.md new file mode 100644 index 000000000..44fa9666e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e31f5ff6a6.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__0c716ed680.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__0c716ed680.md new file mode 100644 index 000000000..64ab96a81 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__0c716ed680.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__2b3161f60e.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__2b3161f60e.md new file mode 100644 index 000000000..11e7b3980 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__2b3161f60e.md @@ -0,0 +1,54 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed ruleFeatures from 7 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe +- Reader (`PhonologicalSubrule.requiredMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 1 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:617` = "mprConcA mprConcB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:622` = "mprConcA mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:645` = "mprPhX" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:650` = "mprPhExcl" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:658` = "mprExtA mprConcA mprConcB mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:714` = "mprRRealTest" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:720` = "mprRRealTest" +- Reader (gate declared here) `PhonologicalSubrule.requiredMPRFeatures`: `grammar.xml:325` = "mprPhX" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__439a31b7db.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__439a31b7db.md new file mode 100644 index 000000000..3f42402a2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__439a31b7db.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4860eb4802.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4860eb4802.md new file mode 100644 index 000000000..b3a86dee7 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4860eb4802.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4eb890fcf9.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4eb890fcf9.md new file mode 100644 index 000000000..eb2c9e6e2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4eb890fcf9.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__5e88566ca5.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__5e88566ca5.md new file mode 100644 index 000000000..2bb101f97 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__5e88566ca5.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__babdf41edb.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__babdf41edb.md new file mode 100644 index 000000000..59a3fc2a7 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__babdf41edb.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__be70f8a294.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__be70f8a294.md new file mode 100644 index 000000000..0f7e415f5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__be70f8a294.md @@ -0,0 +1,54 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.ruleFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed ruleFeatures from 7 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe +- Reader (`PhonologicalSubrule.requiredMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 1 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:617` = "mprConcA mprConcB" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:622` = "mprConcA mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:645` = "mprPhX" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:650` = "mprPhExcl" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:658` = "mprExtA mprConcA mprConcB mprConcC" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:714` = "mprRRealTest" +- Writer (payload declared here) `LexicalEntry.ruleFeatures`: `grammar.xml:720` = "mprRRealTest" +- Reader (gate declared here) `PhonologicalSubrule.requiredMPRFeatures`: `grammar.xml:325` = "mprPhX" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__cf84a64879.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__cf84a64879.md new file mode 100644 index 000000000..d9e795194 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__cf84a64879.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__e2d2525d54.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__e2d2525d54.md new file mode 100644 index 000000000..1f94a5032 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__e2d2525d54.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.ruleFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__0c9d8962c6.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__0c9d8962c6.md new file mode 100644 index 000000000..b0777cccb --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__0c9d8962c6.md @@ -0,0 +1,52 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed MPRFeatures from 5 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz +- Reader (`CompoundingRule.headProdRestrictionsMprFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed headProdRestrictionsMprFeatures from 1 element(s)", example: 'seclav': ok::- -> ok::SEC+LAV|sec+?lav + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:204` = "mprConjA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:425` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:430` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:595` = "mprPedA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:605` = "mprPedB" +- Reader (gate declared here) `CompoundingRule.headProdRestrictionsMprFeatures`: `grammar.xml:411` = "mprCompReq" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__7b2b736272.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__7b2b736272.md new file mode 100644 index 000000000..338c33066 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__7b2b736272.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__960586fc20.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__960586fc20.md new file mode 100644 index 000000000..49f22a77d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__960586fc20.md @@ -0,0 +1,52 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed MPRFeatures from 5 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz +- Reader (`CompoundingRule.headProdRestrictionsMprFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed headProdRestrictionsMprFeatures from 1 element(s)", example: 'seclav': ok::- -> ok::SEC+LAV|sec+?lav + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:204` = "mprConjA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:425` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:430` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:595` = "mprPedA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:605` = "mprPedB" +- Reader (gate declared here) `CompoundingRule.headProdRestrictionsMprFeatures`: `grammar.xml:411` = "mprCompReq" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__9818f76507.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__9818f76507.md new file mode 100644 index 000000000..5dae23241 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__9818f76507.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5c2ae3b0b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5c2ae3b0b.md new file mode 100644 index 000000000..477d5c753 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5c2ae3b0b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5d1391448.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5d1391448.md new file mode 100644 index 000000000..3af745726 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5d1391448.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__eabac31439.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__eabac31439.md new file mode 100644 index 000000000..6cd7c3c4f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__eabac31439.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__f50c9ea523.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__f50c9ea523.md new file mode 100644 index 000000000..be3005c43 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__f50c9ea523.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.headProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__2c1970a9d0.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__2c1970a9d0.md new file mode 100644 index 000000000..6217a6d19 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__2c1970a9d0.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__5a11107cca.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__5a11107cca.md new file mode 100644 index 000000000..95f0ae430 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__5a11107cca.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__c11d047cc3.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__c11d047cc3.md new file mode 100644 index 000000000..d9bbf495e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__c11d047cc3.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ca5bb9f72b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ca5bb9f72b.md new file mode 100644 index 000000000..9a86da58f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ca5bb9f72b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ed79a7fd12.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ed79a7fd12.md new file mode 100644 index 000000000..1b6479530 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ed79a7fd12.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f2861c0957.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f2861c0957.md new file mode 100644 index 000000000..2c31c2d4c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f2861c0957.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f8d1a8842d.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f8d1a8842d.md new file mode 100644 index 000000000..3404cc05d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f8d1a8842d.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f9938dd123.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f9938dd123.md new file mode 100644 index 000000000..e8bba3e74 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f9938dd123.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `CompoundingRule.nonHeadProdRestrictionsMprFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__072c9ca1bf.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__072c9ca1bf.md new file mode 100644 index 000000000..017a128f4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__072c9ca1bf.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__276bbeee50.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__276bbeee50.md new file mode 100644 index 000000000..4b8c910c8 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__276bbeee50.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__51153ce7b8.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__51153ce7b8.md new file mode 100644 index 000000000..ebef75d4a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__51153ce7b8.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__7144b8b154.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__7144b8b154.md new file mode 100644 index 000000000..0c623ab91 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__7144b8b154.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__8940376b9e.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__8940376b9e.md new file mode 100644 index 000000000..dc31ecd1c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__8940376b9e.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__bab91881f5.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__bab91881f5.md new file mode 100644 index 000000000..e071c0345 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__bab91881f5.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__d0d2dfe62c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__d0d2dfe62c.md new file mode 100644 index 000000000..f1c279302 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__d0d2dfe62c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__ff7a5f84e6.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__ff7a5f84e6.md new file mode 100644 index 000000000..5617bafd7 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__ff7a5f84e6.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__00d5cacf7c.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__00d5cacf7c.md new file mode 100644 index 000000000..f9c656872 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__00d5cacf7c.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__3464c8928b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__3464c8928b.md new file mode 100644 index 000000000..0a6d4485e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__3464c8928b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__359421269f.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__359421269f.md new file mode 100644 index 000000000..8c3fe52f2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__359421269f.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__560fba93ef.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__560fba93ef.md new file mode 100644 index 000000000..69c937406 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__560fba93ef.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__7f5e095707.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__7f5e095707.md new file mode 100644 index 000000000..c3f04b692 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__7f5e095707.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__96f5b25fd2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__96f5b25fd2.md new file mode 100644 index 000000000..d422e3d64 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__96f5b25fd2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__af77f63865.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__af77f63865.md new file mode 100644 index 000000000..9c706cca7 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__af77f63865.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__da47e0486f.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__da47e0486f.md new file mode 100644 index 000000000..5ea8cd9d5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__da47e0486f.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `HeadMorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__03b5f060c4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__03b5f060c4.md new file mode 100644 index 000000000..816d680fc --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__03b5f060c4.md @@ -0,0 +1,51 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori +- Reader (`MorphologicalInput.excludedMPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:142` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:243` = "mprB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:254` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:281` = "mprExclFlag" +- Reader (gate declared here) `MorphologicalInput.excludedMPRFeatures`: `grammar.xml:291` = "mprExclFlag" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__3e2b83906f.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__3e2b83906f.md new file mode 100644 index 000000000..77a2b137d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__3e2b83906f.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__46a77463a4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__46a77463a4.md new file mode 100644 index 000000000..68d43e7bf --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__46a77463a4.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'topdori' from failed to successful parse in edge-cases/morphotactic-attribute-breadth (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'topdori'** in `edge-cases/morphotactic-attribute-breadth` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (edge-cases/morphotactic-attribute-breadth / 'topdori') + +- Severing: either mrConferExcl's own MorphologicalOutput.MPRFeatures="mprExclFlag" write (the writer) or mrExclReader's own MorphologicalInput.excludedMPRFeatures="mprExclFlag" gate (the reader) -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::TOP+CONFEREXCL+EXCLREADER|topdori` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori +- Reader (`MorphologicalInput.excludedMPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:142` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:243` = "mprB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:254` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:281` = "mprExclFlag" +- Reader (gate declared here) `MorphologicalInput.excludedMPRFeatures`: `grammar.xml:291` = "mprExclFlag" + +## Author's prose + +- `proof:` (claimed_cells, 'topdori' in edge-cases/morphotactic-attribute-breadth): topdori is TOP run through mrConferExcl (which confers mprExclFlag) then attempting mrExclReader; with both constructs intact the exclusion blocks it, so this has zero parses. Removing either the writer (mrConferExcl's own MorphologicalOutput.MPRFeatures) or the reader (mrExclReader's excludedMPRFeatures) lets mrExclReader apply anyway, producing TOP+CONFEREXCL+EXCLREADER|topdori -- the PresentGatedForm arm: the feature is PRESENT (conferred by mrConferExcl, never a lexical property of TOP itself) and mrExclReader's exclusion GATES on it. + +## `distinct_from` counterpart + +- 'topdori' in edge-cases/morphotactic-attribute-breadth: `distinct_from` **'topdo'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__541dc27660.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__541dc27660.md new file mode 100644 index 000000000..33a3b14f8 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__541dc27660.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__5e8b2b839e.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__5e8b2b839e.md new file mode 100644 index 000000000..ceda8b818 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__5e8b2b839e.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__82cc2c30cf.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__82cc2c30cf.md new file mode 100644 index 000000000..845fa670b --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__82cc2c30cf.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__897627234b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__897627234b.md new file mode 100644 index 000000000..db1a3f1fc --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__897627234b.md @@ -0,0 +1,51 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori +- Reader (`MorphologicalInput.excludedMPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:142` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:243` = "mprB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:254` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:281` = "mprExclFlag" +- Reader (gate declared here) `MorphologicalInput.excludedMPRFeatures`: `grammar.xml:291` = "mprExclFlag" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a0b4289d2a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a0b4289d2a.md new file mode 100644 index 000000000..1859fe15d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a0b4289d2a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a1365c87bf.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a1365c87bf.md new file mode 100644 index 000000000..3d391318e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a1365c87bf.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__c1bf9a3742.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__c1bf9a3742.md new file mode 100644 index 000000000..d2764f350 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__c1bf9a3742.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__1d7a649164.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__1d7a649164.md new file mode 100644 index 000000000..e127b6ac2 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__1d7a649164.md @@ -0,0 +1,52 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3Control:edge-cases/mpr-overwrite-order-dependence + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +Extra MC/DC vector #3, required because the reader's gate has more than one condition -- see the chain kind below. This arm is where the reader does NOT block (control). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `ConditionExtension` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: mechanically required by 2-condition gate observed in edge-cases/mpr-overwrite-order-dependence ('mprP mprQ'); no per-vector witness check implemented yet + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/mpr-overwrite-order-dependence` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/mpr-overwrite-order-dependence`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'daboyuxazi': ok::DABO+SETY+SETX+GATEX|daboyuxazi -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `edge-cases/mpr-overwrite-order-dependence`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 2 element(s)", example: 'daboxayuzi': ok::- -> ok::DABO+SETX+SETY+GATEX|daboxayuzi + +## Grammar citations + +### `edge-cases/mpr-overwrite-order-dependence/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:87` = "mprX" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:98` = "mprY" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:122` = "mprP" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:133` = "mprQ" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:110` = "mprX" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:145` = "mprP mprQ" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__33aaa87cb8.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__33aaa87cb8.md new file mode 100644 index 000000000..2c88fed1e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__33aaa87cb8.md @@ -0,0 +1,52 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3GatedForm:edge-cases/mpr-overwrite-order-dependence + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +Extra MC/DC vector #3, required because the reader's gate has more than one condition -- see the chain kind below. This arm is where the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `ConditionExtension` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: mechanically required by 2-condition gate observed in edge-cases/mpr-overwrite-order-dependence ('mprP mprQ'); no per-vector witness check implemented yet + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/mpr-overwrite-order-dependence` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/mpr-overwrite-order-dependence`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'daboyuxazi': ok::DABO+SETY+SETX+GATEX|daboyuxazi -> ok::- +- Reader (`MorphologicalInput.requiredMPRFeatures` in `edge-cases/mpr-overwrite-order-dependence`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 2 element(s)", example: 'daboxayuzi': ok::- -> ok::DABO+SETX+SETY+GATEX|daboxayuzi + +## Grammar citations + +### `edge-cases/mpr-overwrite-order-dependence/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:87` = "mprX" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:98` = "mprY" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:122` = "mprP" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:133` = "mprQ" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:110` = "mprX" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:145` = "mprP mprQ" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__423093b89f.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__423093b89f.md new file mode 100644 index 000000000..1dc8d2322 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__423093b89f.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__4d56ef58ab.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__4d56ef58ab.md new file mode 100644 index 000000000..f42642cc5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__4d56ef58ab.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6a0738e58d.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6a0738e58d.md new file mode 100644 index 000000000..385118c1d --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6a0738e58d.md @@ -0,0 +1,51 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori +- Reader (`MorphologicalInput.requiredMPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredMPRFeatures from 1 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:142` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:243` = "mprB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:254` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:281` = "mprExclFlag" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:264` = "mprB" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6f6a3c7be2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6f6a3c7be2.md new file mode 100644 index 000000000..a981531a0 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6f6a3c7be2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__7ad6be3e44.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__7ad6be3e44.md new file mode 100644 index 000000000..283cfea66 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__7ad6be3e44.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__9a427b5040.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__9a427b5040.md new file mode 100644 index 000000000..9a01978ab --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__9a427b5040.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__c43b787c90.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__c43b787c90.md new file mode 100644 index 000000000..538d13069 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__c43b787c90.md @@ -0,0 +1,54 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed MPRFeatures from 5 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:204` = "mprConjA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:425` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:430` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:595` = "mprPedA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:605` = "mprPedB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__dff8d6ff95.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__dff8d6ff95.md new file mode 100644 index 000000000..d54b55a3a --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__dff8d6ff95.md @@ -0,0 +1,51 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori +- Reader (`MorphologicalInput.requiredMPRFeatures` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredMPRFeatures from 1 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:142` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:243` = "mprB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:254` = "mprA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:281` = "mprExclFlag" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:264` = "mprB" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e46cfee1d1.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e46cfee1d1.md new file mode 100644 index 000000000..c3f6d41d5 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e46cfee1d1.md @@ -0,0 +1,58 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'ygofz' from failed to successful parse in languages/fusional-realizational-morphology (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'ygofz'** in `languages/fusional-realizational-morphology` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (languages/fusional-realizational-morphology / 'ygofz') + +- Severing: MPRFeatures across every MorphologicalOutput (the one that matters here is mrThemeY's own "mprPedB" write), as the writer, or mrEndZ's MorphologicalInput.requiredMPRFeatures="mprPedA" gate, as the reader -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::THEMEY+GOF+ENDZ|ygofz` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed MPRFeatures from 5 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:204` = "mprConjA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:425` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:430` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:595` = "mprPedA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:605` = "mprPedB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- `proof:` (claimed_cells, 'ygofz' in languages/fusional-realizational-morphology): ygofz is GOF (lexically preset with mprPedA) run through mrThemeY then mrEndZ; with both constructs intact, mrThemeY's own write triggers ThemeGroup's overwrite semantics (MprFeatureSet.AddOutput) and drops GOF's preset mprPedA before mrEndZ's gate is ever checked, so this has zero parses (ok::-). Removing either the writer (mrThemeY's own MorphologicalOutput.MPRFeatures, so the overwrite-triggering write never happens) or the reader (mrEndZ's requiredMPRFeatures, so the gate no longer needs mprPedA) lets mrEndZ apply anyway, producing THEMEY+GOF+ENDZ|ygofz -- the AbsentGatedForm arm: the required feature is ABSENT (from the derivation's accumulated state, though never from GOF's own declaration) and the rule's requirement GATES on it. gofz (GOF+ENDZ with no mrThemeY at all) is the control that shows mrEndZ applies normally once mprPedA actually survives to the gate, so ygofz's block is attributable to mrThemeY's overwrite, not to mrEndZ never applying at all. + +## `distinct_from` counterpart + +- 'ygofz' in languages/fusional-realizational-morphology: `distinct_from` **'gofz'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e68235eebb.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e68235eebb.md new file mode 100644 index 000000000..488b5d057 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e68235eebb.md @@ -0,0 +1,54 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `MorphologicalInput.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed MPRFeatures from 5 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz +- Reader (`MorphologicalInput.requiredMPRFeatures` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 3 element(s)", example: 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:204` = "mprConjA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:425` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:430` = "mprCompReq" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:595` = "mprPedA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:605` = "mprPedB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:614` = "mprPedA" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:625` = "mprConjA mprConjB" +- Reader (gate declared here) `MorphologicalInput.requiredMPRFeatures`: `grammar.xml:635` = "mprConjC mprConjD" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__3a50ce58d4.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__3a50ce58d4.md new file mode 100644 index 000000000..9e9444430 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__3a50ce58d4.md @@ -0,0 +1,52 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'menanukam' from failed to successful parse in edge-cases/mpr-gated-exception (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'menanukam'** in `edge-cases/mpr-gated-exception` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (edge-cases/mpr-gated-exception / 'menanukam') + +- Severing: either mrDelExclSrc's own MorphologicalOutput.MPRFeatures="mprAffixDelExcl" write (the writer) or prObstruentDeletion's own PhonologicalSubrule.excludedMPRFeatures="mprAffixDelExcl" gate (the reader) -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `edge-cases/mpr-gated-exception`): verdict=Evidenced, mutation="removed MPRFeatures from 1 element(s)", example: 'menanukam': ok::- -> ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam +- Reader (`PhonologicalSubrule.excludedMPRFeatures` in `edge-cases/mpr-gated-exception`): verdict=Evidenced, mutation="removed excludedMPRFeatures from 1 element(s)", example: 'menanukam': ok::- -> ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam + +## Grammar citations + +### `edge-cases/mpr-gated-exception/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:248` = "mprAffixDelExcl" +- Reader (gate declared here) `PhonologicalSubrule.excludedMPRFeatures`: `grammar.xml:192` = "mprAffixDelExcl" + +## Author's prose + +- `proof:` (claimed_cells, 'menanukam' in edge-cases/mpr-gated-exception): menanukam is TANUK run through mrNPfx and mrDelExclSrc (which confers mprAffixDelExcl) then attempting prObstruentDeletion; with both constructs intact the deletion is blocked (zero parses for the deleted surface). Removing either the writer (mrDelExclSrc's own MorphologicalOutput.MPRFeatures) or the reader (prObstruentDeletion's excludedMPRFeatures) lets the deletion through, producing NPFX+TANUK+DELEXCLSRC|menanukam -- the PresentGatedForm arm: the feature is PRESENT (conferred by the affix, never by TANUK's own declaration) and the rule's exclusion GATES on it. + +## `distinct_from` counterpart + +- 'menanukam' in edge-cases/mpr-gated-exception: `distinct_from` **'mentanukam'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__5d863899ec.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__5d863899ec.md new file mode 100644 index 000000000..61aa71375 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__5d863899ec.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__6d8ca45a01.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__6d8ca45a01.md new file mode 100644 index 000000000..78af34ad8 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__6d8ca45a01.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9901ca7838.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9901ca7838.md new file mode 100644 index 000000000..515a86173 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9901ca7838.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9f07bc6b34.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9f07bc6b34.md new file mode 100644 index 000000000..f3d60a1b9 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9f07bc6b34.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a524525471.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a524525471.md new file mode 100644 index 000000000..67d49cf81 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a524525471.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a5e2ccf42a.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a5e2ccf42a.md new file mode 100644 index 000000000..bfe6a5ba4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a5e2ccf42a.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__bd77eb6f30.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__bd77eb6f30.md new file mode 100644 index 000000000..367439dc0 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__bd77eb6f30.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__dcacddbe6b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__dcacddbe6b.md new file mode 100644 index 000000000..52909923c --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__dcacddbe6b.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__e1cb70b918.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__e1cb70b918.md new file mode 100644 index 000000000..93e9e9d7b --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__e1cb70b918.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.excludedMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__15619d7374.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__15619d7374.md new file mode 100644 index 000000000..374db91a4 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__15619d7374.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__272f2eff25.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__272f2eff25.md new file mode 100644 index 000000000..1ee44216f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__272f2eff25.md @@ -0,0 +1,55 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'nbael' from failed to successful parse in languages/suffixing-extension-slot-ordering (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'nbael'** in `languages/suffixing-extension-slot-ordering` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (languages/suffixing-extension-slot-ordering / 'nbael') + +- Severing: either mrPhonoDestroy's own MorphologicalOutput.MPRFeatures="mprPhY" write (the writer) or prPhonoReq's own PhonologicalSubrule.requiredMPRFeatures="mprPhX" gate (the reader) -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::PPO+PHDESTROY|nbael` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael +- Reader (`PhonologicalSubrule.requiredMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 1 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:387` = "mprExtA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:397` = "mprExtB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:568` = "mprPhY" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:586` = "mprPhX" +- Reader (gate declared here) `PhonologicalSubrule.requiredMPRFeatures`: `grammar.xml:325` = "mprPhX" + +## Author's prose + +- `proof:` (claimed_cells, 'nbael' in languages/suffixing-extension-slot-ordering): nbael is PPO (lexically preset with mprPhX) run through mrPhonoDestroy then prPhonoReq's phonological gate; with both constructs intact, mrPhonoDestroy's write triggers PhonoGroup's overwrite semantics (MprFeatureSet.AddOutput) and drops PPO's preset mprPhX before prPhonoReq's gate is ever checked, so this has zero parses. Removing either the writer (mrPhonoDestroy's own MorphologicalOutput.MPRFeatures, so the overwrite-triggering write never happens) or the reader (prPhonoReq's requiredMPRFeatures, so the gate no longer needs mprPhX) lets the mutation fire anyway, producing PPO+PHDESTROY|nbael -- the AbsentGatedForm arm: the required feature is ABSENT (from the derivation's accumulated state, though never from PPO's own declaration) and the rule's requirement GATES on it. + +## `distinct_from` counterpart + +- 'nbael' in languages/suffixing-extension-slot-ordering: `distinct_from` **'npael'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__613c3bd08b.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__613c3bd08b.md new file mode 100644 index 000000000..e9f754df7 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__613c3bd08b.md @@ -0,0 +1,51 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael +- Reader (`PhonologicalSubrule.requiredMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 1 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:387` = "mprExtA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:397` = "mprExtB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:568` = "mprPhY" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:586` = "mprPhX" +- Reader (gate declared here) `PhonologicalSubrule.requiredMPRFeatures`: `grammar.xml:325` = "mprPhX" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__67552876cb.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__67552876cb.md new file mode 100644 index 000000000..1766c1dae --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__67552876cb.md @@ -0,0 +1,51 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalOutput.MPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed MPRFeatures from 4 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael +- Reader (`PhonologicalSubrule.requiredMPRFeatures` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredMPRFeatures from 1 element(s)", example: 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:387` = "mprExtA" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:397` = "mprExtB" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:568` = "mprPhY" +- Writer (payload declared here) `MorphologicalOutput.MPRFeatures`: `grammar.xml:586` = "mprPhX" +- Reader (gate declared here) `PhonologicalSubrule.requiredMPRFeatures`: `grammar.xml:325` = "mprPhX" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__724988ff85.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__724988ff85.md new file mode 100644 index 000000000..746c7132f --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__724988ff85.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__82cd28b991.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__82cd28b991.md new file mode 100644 index 000000000..58ed49df1 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__82cd28b991.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__c5e8f0bdd2.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__c5e8f0bdd2.md new file mode 100644 index 000000000..f71775bde --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__c5e8f0bdd2.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__cfa6a04091.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__cfa6a04091.md new file mode 100644 index 000000000..63f9e8bf3 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__cfa6a04091.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__ee64baff46.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__ee64baff46.md new file mode 100644 index 000000000..03909f45e --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__ee64baff46.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a compounding non-head drop (the output word is built from the head alone, so the non-head's payload is never copied into it) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `CompoundingNonHeadDrop` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__fe6bfd4ffe.md b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__fe6bfd4ffe.md new file mode 100644 index 000000000..2f548f9f3 --- /dev/null +++ b/conformance/evidence-cards/MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__fe6bfd4ffe.md @@ -0,0 +1,43 @@ +# MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with outputType="overwrite" drops the accumulated feature set before the read) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalOutput.MPRFeatures` +- Payload type: `MorphologicalPhonologicalRuleFeature` +- Reader: `PhonologicalSubrule.requiredMPRFeatures` +- Cell kind: `Mutator`, mutator class: `Overwrite` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCont__1279c82367.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCont__1279c82367.md new file mode 100644 index 000000000..a8f707fbf --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCont__1279c82367.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGate__e809525828.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGate__e809525828.md new file mode 100644 index 000000000..45aa849b6 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGate__e809525828.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentCon__69fa993ea6.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentCon__69fa993ea6.md new file mode 100644 index 000000000..a31cc8f18 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentCon__69fa993ea6.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGat__07a16a4cfe.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGat__07a16a4cfe.md new file mode 100644 index 000000000..71c85e771 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGat__07a16a4cfe.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__0b9bd700b1.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__0b9bd700b1.md new file mode 100644 index 000000000..3278e1651 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__0b9bd700b1.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__243845d05e.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__243845d05e.md new file mode 100644 index 000000000..d44d654cd --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__243845d05e.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__ab2424673d.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__ab2424673d.md new file mode 100644 index 000000000..a95702d8b --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__ab2424673d.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__d06fe8ee83.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__d06fe8ee83.md new file mode 100644 index 000000000..a330b815e --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__d06fe8ee83.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentContro__d836fc0cf4.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentContro__d836fc0cf4.md new file mode 100644 index 000000000..87313c0c7 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentContro__d836fc0cf4.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedF__482ad3d9ed.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedF__482ad3d9ed.md new file mode 100644 index 000000000..4d98ac3fd --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedF__482ad3d9ed.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentContr__d78150d7c7.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentContr__d78150d7c7.md new file mode 100644 index 000000000..b7d6382e7 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentContr__d78150d7c7.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGated__30da04ee2f.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGated__30da04ee2f.md new file mode 100644 index 000000000..8129ab425 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGated__30da04ee2f.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__466ff08aae.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__466ff08aae.md new file mode 100644 index 000000000..ae23cd708 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__466ff08aae.md @@ -0,0 +1,50 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 1 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:411` = "posCompH" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__cc6cb61e70.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__cc6cb61e70.md new file mode 100644 index 000000000..8df1a9e8e --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__cc6cb61e70.md @@ -0,0 +1,50 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 1 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:411` = "posCompH" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__0c340e4205.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__0c340e4205.md new file mode 100644 index 000000000..536ddebe0 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__0c340e4205.md @@ -0,0 +1,50 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 1 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:411` = "posCompH" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__83594721ef.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__83594721ef.md new file mode 100644 index 000000000..e473ffbd2 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__83594721ef.md @@ -0,0 +1,50 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 1 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:411` = "posCompH" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentCon__2274b0e237.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentCon__2274b0e237.md new file mode 100644 index 000000000..5fb181507 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentCon__2274b0e237.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGat__a0adb93408.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGat__a0adb93408.md new file mode 100644 index 000000000..2bb0c2801 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGat__a0adb93408.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentCo__e3487dd647.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentCo__e3487dd647.md new file mode 100644 index 000000000..d39036880 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentCo__e3487dd647.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGa__d9159f1374.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGa__d9159f1374.md new file mode 100644 index 000000000..5f6416539 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGa__d9159f1374.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__1113ca565a.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__1113ca565a.md new file mode 100644 index 000000000..bbb7408de --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__1113ca565a.md @@ -0,0 +1,54 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/compounding-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed outputPartOfSpeech from 4 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `edge-cases/compounding-breadth`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 4 element(s)" + +## Grammar citations + +### `edge-cases/compounding-breadth/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:79` = "posOther" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:104` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:128` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:148` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:79` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:104` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:128` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:148` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__75faacc83a.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__75faacc83a.md new file mode 100644 index 000000000..76e0faed0 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__75faacc83a.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__8e6c8a918f.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__8e6c8a918f.md new file mode 100644 index 000000000..f70b61c57 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__8e6c8a918f.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__b1a3af58f4.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__b1a3af58f4.md new file mode 100644 index 000000000..14829eabc --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__b1a3af58f4.md @@ -0,0 +1,54 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/compounding-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed outputPartOfSpeech from 4 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `edge-cases/compounding-breadth`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 4 element(s)" + +## Grammar citations + +### `edge-cases/compounding-breadth/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:79` = "posOther" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:104` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:128` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:148` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:79` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:104` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:128` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:148` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__343dd24ada.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__343dd24ada.md new file mode 100644 index 000000000..cad63e6ee --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__343dd24ada.md @@ -0,0 +1,55 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'katumi' from failed to successful parse in edge-cases/compounding-breadth (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'katumi'** in `edge-cases/compounding-breadth` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (edge-cases/compounding-breadth / 'katumi') + +- Severing: either crJoin's own CompoundingRule.outputPartOfSpeech="posOther" (the writer) or mrTplSuf's own MorphologicalRule.requiredPartsOfSpeech="posN" gate (the reader) -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::KA+TU+TPLSUF|katumi` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed outputPartOfSpeech from 4 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 1 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi + +## Grammar citations + +### `edge-cases/compounding-breadth/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:79` = "posOther" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:104` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:128` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:148` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:178` = "posN" + +## Author's prose + +- `proof:` (claimed_cells, 'katumi' in edge-cases/compounding-breadth): katumi is KA+TU (crJoin's compound, tagged posOther) attempting mrTplSuf; with both constructs intact the part-of-speech conflict (posOther vs. mrTplSuf's own required posN) blocks it, so this has zero parses. Removing either the writer (crJoin's own outputPartOfSpeech, so the compound's output keeps the head's own seeded posN instead of being overwritten to posOther) or the reader (mrTplSuf's requiredPartsOfSpeech) lets the rule apply anyway, producing KA+TU+TPLSUF|katumi -- the AbsentGatedForm arm: the required part of speech is ABSENT (overwritten away, though never from KA's own declaration) and the rule's requirement GATES on it. + +## `distinct_from` counterpart + +- 'katumi' in edge-cases/compounding-breadth: `distinct_from` **'katu'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__bce657e908.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__bce657e908.md new file mode 100644 index 000000000..e6aa0c50e --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__bce657e908.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__4d5c16475f.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__4d5c16475f.md new file mode 100644 index 000000000..cb4f983bc --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__4d5c16475f.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__cf6c32cac7.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__cf6c32cac7.md new file mode 100644 index 000000000..8e0a16acc --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__cf6c32cac7.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__118ae9565e.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__118ae9565e.md new file mode 100644 index 000000000..fd1967114 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__118ae9565e.md @@ -0,0 +1,51 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/compounding-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed outputPartOfSpeech from 4 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 1 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi + +## Grammar citations + +### `edge-cases/compounding-breadth/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:79` = "posOther" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:104` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:128` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:148` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:178` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5c53e2628d.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5c53e2628d.md new file mode 100644 index 000000000..ecf5d1498 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5c53e2628d.md @@ -0,0 +1,51 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/compounding-breadth declares 5 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/compounding-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`CompoundingRule.outputPartOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed outputPartOfSpeech from 4 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/compounding-breadth`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 1 element(s)", example: 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi + +## Grammar citations + +### `edge-cases/compounding-breadth/grammar.xml` + +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:79` = "posOther" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:104` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:128` = "posN" +- Writer (payload declared here) `CompoundingRule.outputPartOfSpeech`: `grammar.xml:148` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:178` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5d88ceb7e6.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5d88ceb7e6.md new file mode 100644 index 000000000..413ed25bc --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5d88ceb7e6.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__756edf94e4.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__756edf94e4.md new file mode 100644 index 000000000..087737db0 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__756edf94e4.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__26b5ae41c5.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__26b5ae41c5.md new file mode 100644 index 000000000..ed886cea5 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__26b5ae41c5.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__a12e4b86ee.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__a12e4b86ee.md new file mode 100644 index 000000000..d68af14d3 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__a12e4b86ee.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__44c6571023.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__44c6571023.md new file mode 100644 index 000000000..cc358999f --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__44c6571023.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__8bddaa7cca.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__8bddaa7cca.md new file mode 100644 index 000000000..4047e0bed --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__8bddaa7cca.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__0f7ddf55bf.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__0f7ddf55bf.md new file mode 100644 index 000000000..71d0dd451 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__0f7ddf55bf.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__4bc935f0cc.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__4bc935f0cc.md new file mode 100644 index 000000000..ae9ec7622 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__4bc935f0cc.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__562b30b100.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__562b30b100.md new file mode 100644 index 000000000..09d9d7e14 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__562b30b100.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__739fd876fc.md b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__739fd876fc.md new file mode 100644 index 000000000..575abc493 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__739fd876fc.md @@ -0,0 +1,43 @@ +# PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `CompoundingRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**NotSatisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv) + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentControl__a5b4995baa.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentControl__a5b4995baa.md new file mode 100644 index 000000000..be5e555ee --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentControl__a5b4995baa.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGatedForm__dc25dce562.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGatedForm__dc25dce562.md new file mode 100644 index 000000000..0e69f2cbe --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGatedForm__dc25dce562.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentControl__3da410288c.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentControl__3da410288c.md new file mode 100644 index 000000000..451593172 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentControl__3da410288c.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGatedForm__0fc1fd9740.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGatedForm__0fc1fd9740.md new file mode 100644 index 000000000..a096e485c --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGatedForm__0fc1fd9740.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Bl__e47d3d51db.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Bl__e47d3d51db.md new file mode 100644 index 000000000..ee8869194 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Bl__e47d3d51db.md @@ -0,0 +1,58 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed partOfSpeech from 9 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:324` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:334` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:341` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:348` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:355` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:363` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:371` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:379` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:428` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Po__c731ce6cd5.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Po__c731ce6cd5.md new file mode 100644 index 000000000..53340f8f9 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Po__c731ce6cd5.md @@ -0,0 +1,58 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed partOfSpeech from 9 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:324` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:334` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:341` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:348` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:355` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:363` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:371` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:379` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:428` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_B__54bb99a44b.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_B__54bb99a44b.md new file mode 100644 index 000000000..229090b71 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_B__54bb99a44b.md @@ -0,0 +1,58 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed partOfSpeech from 9 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:324` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:334` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:341` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:348` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:355` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:363` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:371` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:379` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:428` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_P__a4060dd34c.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_P__a4060dd34c.md new file mode 100644 index 000000000..e5cc98253 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_P__a4060dd34c.md @@ -0,0 +1,58 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed partOfSpeech from 9 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:324` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:334` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:341` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:348` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:355` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:363` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:371` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:379` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:428` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentControl__f3e516d6fd.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentControl__f3e516d6fd.md new file mode 100644 index 000000000..9a4c077a3 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentControl__f3e516d6fd.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedForm__1bea7c3fa6.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedForm__1bea7c3fa6.md new file mode 100644 index 000000000..dcb0b1eb5 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedForm__1bea7c3fa6.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentControl__09151a056b.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentControl__09151a056b.md new file mode 100644 index 000000000..f5c7602b0 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentControl__09151a056b.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGatedForm__c71a480a3b.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGatedForm__c71a480a3b.md new file mode 100644 index 000000000..985921da0 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGatedForm__c71a480a3b.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_Bloc__f0e1fcf009.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_Bloc__f0e1fcf009.md new file mode 100644 index 000000000..9fd95bd5e --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_Bloc__f0e1fcf009.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_PosP__0d0dd22ef9.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_PosP__0d0dd22ef9.md new file mode 100644 index 000000000..7c4fc1dc9 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_PosP__0d0dd22ef9.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Blo__79033eb224.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Blo__79033eb224.md new file mode 100644 index 000000000..f3ec46623 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Blo__79033eb224.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Pos__aa1b56f9fa.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Pos__aa1b56f9fa.md new file mode 100644 index 000000000..3502ed43c --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Pos__aa1b56f9fa.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentControl__79a58b0237.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentControl__79a58b0237.md new file mode 100644 index 000000000..bb4747358 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentControl__79a58b0237.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGatedForm__396b84ab5a.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGatedForm__396b84ab5a.md new file mode 100644 index 000000000..b93963ac8 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGatedForm__396b84ab5a.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentControl__ce8026bc83.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentControl__ce8026bc83.md new file mode 100644 index 000000000..43017261e --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentControl__ce8026bc83.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGatedForm__26ced6d991.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGatedForm__26ced6d991.md new file mode 100644 index 000000000..b5e6c105c --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGatedForm__26ced6d991.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_B__e400b4a993.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_B__e400b4a993.md new file mode 100644 index 000000000..ba423e5cd --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_B__e400b4a993.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_P__335516f509.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_P__335516f509.md new file mode 100644 index 000000000..7e07c5e39 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_P__335516f509.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___0685342ef3.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___0685342ef3.md new file mode 100644 index 000000000..0b7c08024 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___0685342ef3.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___3a7a548bf6.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___3a7a548bf6.md new file mode 100644 index 000000000..7d184edd5 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___3a7a548bf6.md @@ -0,0 +1,76 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentControl__29a6b50f8a.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentControl__29a6b50f8a.md new file mode 100644 index 000000000..42df06cce --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentControl__29a6b50f8a.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentGatedForm__19788af842.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentGatedForm__19788af842.md new file mode 100644 index 000000000..84338f1a3 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentGatedForm__19788af842.md @@ -0,0 +1,69 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'nunavuq' from failed to successful parse in languages/polysynthetic-stratal-derivation-chain (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'nunavuq'** in `languages/polysynthetic-stratal-derivation-chain` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (languages/polysynthetic-stratal-derivation-chain / 'nunavuq') + +- Severing: partOfSpeech across every LexicalEntry (the one that matters here is NUNA's posN), as the writer, or mrInfl's MorphologicalRule.requiredPartsOfSpeech="posV" gate, as the reader -- severing either alone unblocks this word +- Before: `ok::-` +- After: `ok::NUNA+INFL|nunavuq` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/polysynthetic-stratal-derivation-chain`): verdict=Evidenced, mutation="removed partOfSpeech from 15 element(s)", example: 'nunavuq': ok::- -> ok::NUNA+INFL|nunavuq +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `languages/polysynthetic-stratal-derivation-chain`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 4 element(s)", example: 'nunavuq': ok::- -> ok::NUNA+INFL|nunavuq + +## Grammar citations + +### `languages/polysynthetic-stratal-derivation-chain/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:248` = "posDelR" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:253` = "posDelR" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:258` = "posDelR" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:264` = "posMultiSeg" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:272` = "posMDC" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:280` = "posMDC" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:292` = "posMDC" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:375` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:378` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:384` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:389` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:394` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:400` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:405` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:410` = "posV2" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:308` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:330` = "posV1" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:353` = "posV2" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:425` = "posV" + +## Author's prose + +- `proof:` (claimed_cells, 'nunavuq' in languages/polysynthetic-stratal-derivation-chain): nunavuq is mrInfl attempted directly on the bare noun NUNA (posN); with both constructs intact, inflection cannot attach (ok::-). Removing either the writer (LexicalEntry's partOfSpeech) or the reader (mrInfl's requiredPartsOfSpeech) lets inflection attach anyway, producing NUNA+INFL|nunavuq -- the AbsentGatedForm arm: the required feature is ABSENT and the rule's requirement GATES on it. nunaliqvuq (NUNA+DERIV+INFL, where mrDeriv verbalizes the root to posV first) is the control that shows mrInfl applies normally once the required POS is actually present, so nunavuq's block is attributable to the gate, not to mrInfl never applying at all. + +## `distinct_from` counterpart + +- 'nunavuq' in languages/polysynthetic-stratal-derivation-chain: `distinct_from` **'nunaliqvuq'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentControl__5c0774a54a.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentControl__5c0774a54a.md new file mode 100644 index 000000000..a103493f9 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentControl__5c0774a54a.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentGatedFor__7589d364d6.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentGatedFor__7589d364d6.md new file mode 100644 index 000000000..20caa57fa --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentGatedFor__7589d364d6.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3aaacd2922.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3aaacd2922.md new file mode 100644 index 000000000..3fb4c13f5 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3aaacd2922.md @@ -0,0 +1,90 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 17 element(s)", example: 'mano': ok::STEM+P1|mano -> ok::STEM+ABLAUT+P1|mano;STEM+P1|mano + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:233` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:271` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:283` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:302` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:316` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:350` = "posV1" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:371` = "posV2" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:386` = "posAblautV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:590` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:600` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:610` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:621` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:631` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3e506284e1.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3e506284e1.md new file mode 100644 index 000000000..049cf3a65 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3e506284e1.md @@ -0,0 +1,71 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed partOfSpeech from 9 element(s)" +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 16 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:324` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:334` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:341` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:348` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:355` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:363` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:371` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:379` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:428` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:102` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:114` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:125` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:137` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:150` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:188` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:238` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:249` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:276` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:287` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:396` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:409` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f261d96931.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f261d96931.md new file mode 100644 index 000000000..d65af7f90 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f261d96931.md @@ -0,0 +1,71 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed partOfSpeech from 9 element(s)" +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 16 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:324` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:334` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:341` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:348` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:355` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:363` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:371` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:379` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:428` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:102` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:114` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:125` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:137` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:150` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:188` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:238` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:249` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:276` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:287` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:396` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:409` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f8386bced5.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f8386bced5.md new file mode 100644 index 000000000..bd081ccc4 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f8386bced5.md @@ -0,0 +1,90 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed partOfSpeech from 27 element(s)", example: 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 17 element(s)", example: 'mano': ok::STEM+P1|mano -> ok::STEM+ABLAUT+P1|mano;STEM+P1|mano + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:457` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:462` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:469` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:476` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:483` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:488` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:493` = "posV1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:500` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:507` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:512` = "posN1" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:522` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:527` = "posN2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:532` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:538` = "posAblautV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:543` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:551` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:557` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:562` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:568` = "posCompH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:573` = "posCompNH" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:644` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:652` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:657` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:662` = "posN" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:233` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:271` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:283` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:302` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:316` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:350` = "posV1" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:371` = "posV2" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:386` = "posAblautV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:590` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:600` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:610` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:621` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:631` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentControl__cd479494ba.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentControl__cd479494ba.md new file mode 100644 index 000000000..a2f5472b8 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentControl__cd479494ba.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentGatedFo__918bf3ccbd.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentGatedFo__918bf3ccbd.md new file mode 100644 index 000000000..4c277f3a6 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentGatedFo__918bf3ccbd.md @@ -0,0 +1,60 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Satisfied** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: paired witness: severing writer and reader both flip 'idil' from failed to successful parse in languages/metathesis-phase-isolation (conformance/interface-witness.tsv) + +## Fixture and word + +- Claimed by word **'idil'** in `languages/metathesis-phase-isolation` (a `claimed_cells` entry in `words.yaml`). + +## Exact mutation and before/after parse + +### Author's claim (languages/metathesis-phase-isolation / 'idil') + +- Severing: ADIL's own partOfSpeech="posCircum" (the writer), or prNonContig's PhonologicalSubrule requiredPartsOfSpeech="posNonContig" (the reader) -- severing either alone lets prNonContig apply to ADIL too +- Before: `ok::-` +- After: `ok::ADIL|idil` + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/metathesis-phase-isolation`): verdict=Evidenced, mutation="removed partOfSpeech from 9 element(s)", example: 'idil': ok::- -> ok::ADIL|idil +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/metathesis-phase-isolation`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 1 element(s)", example: 'idil': ok::- -> ok::ADIL|idil + +## Grammar citations + +### `languages/metathesis-phase-isolation/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:263` = "posComplexMeta" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:294` = "posSimpleMeta" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:299` = "posNotUnapplied" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:433` = "posInfix" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:438` = "posCircum" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:443` = "posRedup" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:448` = "posTrunc" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:453` = "posLnk" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:458` = "posNonContig" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:205` = "posNonContig" + +## Author's prose + +- `proof:` (claimed_cells, 'idil' in languages/metathesis-phase-isolation): "idil" needs prNonContig (a -> i before a voiced consonant, gated to a DIFFERENT part of speech, posNonContig) to fire on ADIL's own root; with both constructs intact this word has zero parses (ok::-). Removing either the writer (LexicalEntry's partOfSpeech) or the reader (prNonContig's requiredPartsOfSpeech) lets prNonContig apply to ADIL as well, producing ok::ADIL|idil -- the AbsentGatedForm arm: the required part of speech is ABSENT from ADIL and the phonological subrule's requirement GATES on it. adil (ADIL's own bare, un-raised surface) is the control that shows the root is otherwise ordinary and fully valid, so idil's block is attributable specifically to prNonContig's gate, not to ADIL failing to parse at all. + +## `distinct_from` counterpart + +- 'idil' in languages/metathesis-phase-isolation: `distinct_from` **'adil'** (expect_fail=False) vs. this word (expect_fail=True). diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentContro__9f6e2a8199.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentContro__9f6e2a8199.md new file mode 100644 index 000000000..b3288c89e --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentContro__9f6e2a8199.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentGatedF__146e6d44f8.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentGatedF__146e6d44f8.md new file mode 100644 index 000000000..adc2fdce3 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentGatedF__146e6d44f8.md @@ -0,0 +1,43 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__1c868fac61.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__1c868fac61.md new file mode 100644 index 000000000..69ebc36be --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__1c868fac61.md @@ -0,0 +1,68 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed partOfSpeech from 19 element(s)", example: 'mpe': ok::PPE|mpe -> ok::- +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:604` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:610` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:617` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:622` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:627` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:640` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:645` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:650` = "posV3excl" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:658` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:664` = "posV4" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posV5" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:676` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:685` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:693` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:700` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:705` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:714` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:720` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:726` = "posV7" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__5d14512c40.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__5d14512c40.md new file mode 100644 index 000000000..b44a0c4f4 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__5d14512c40.md @@ -0,0 +1,68 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed partOfSpeech from 19 element(s)", example: 'mpe': ok::PPE|mpe -> ok::- +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:604` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:610` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:617` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:622` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:627` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:640` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:645` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:650` = "posV3excl" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:658` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:664` = "posV4" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posV5" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:676` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:685` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:693` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:700` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:705` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:714` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:720` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:726` = "posV7" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__19c2a7e90c.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__19c2a7e90c.md new file mode 100644 index 000000000..b68131bbf --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__19c2a7e90c.md @@ -0,0 +1,68 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed partOfSpeech from 19 element(s)", example: 'mpe': ok::PPE|mpe -> ok::- +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:604` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:610` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:617` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:622` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:627` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:640` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:645` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:650` = "posV3excl" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:658` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:664` = "posV4" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posV5" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:676` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:685` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:693` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:700` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:705` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:714` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:720` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:726` = "posV7" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__91e275055b.md b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__91e275055b.md new file mode 100644 index 000000000..395098e16 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__91e275055b.md @@ -0,0 +1,68 @@ +# PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `LexicalEntry.partOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`LexicalEntry.partOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed partOfSpeech from 19 element(s)", example: 'mpe': ok::PPE|mpe -> ok::- +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:604` = "posV" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:610` = "posV2" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:617` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:622` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:627` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:640` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:645` = "posV3req" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:650` = "posV3excl" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:658` = "posV3" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:664` = "posV4" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:670` = "posV5" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:676` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:685` = "posV6" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:693` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:700` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:705` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:714` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:720` = "posV7" +- Writer (payload declared here) `LexicalEntry.partOfSpeech`: `grammar.xml:726` = "posV7" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCo__427b970f16.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCo__427b970f16.md new file mode 100644 index 000000000..8ccacd7f1 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCo__427b970f16.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGa__07d26442ca.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGa__07d26442ca.md new file mode 100644 index 000000000..1c6b52d2d --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGa__07d26442ca.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentC__275363a4e6.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentC__275363a4e6.md new file mode 100644 index 000000000..4d1cb445d --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentC__275363a4e6.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentG__2c21324b11.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentG__2c21324b11.md new file mode 100644 index 000000000..528864c65 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentG__2c21324b11.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__ae5db4f350.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__ae5db4f350.md new file mode 100644 index 000000000..860439f6c --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__ae5db4f350.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:102` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:114` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:125` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:137` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:150` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:188` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:238` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:249` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:276` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:287` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:396` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:409` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__d510fa6c76.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__d510fa6c76.md new file mode 100644 index 000000000..a480aab4f --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__d510fa6c76.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:102` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:114` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:125` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:137` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:150` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:188` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:238` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:249` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:276` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:287` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:396` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:409` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__de951125fb.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__de951125fb.md new file mode 100644 index 000000000..4185885c2 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__de951125fb.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:102` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:114` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:125` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:137` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:150` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:188` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:238` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:249` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:276` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:287` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:396` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:409` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__fd652643d4.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__fd652643d4.md new file mode 100644 index 000000000..f983b5b41 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__fd652643d4.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `AffixTemplate.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`AffixTemplate.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:102` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:114` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:125` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:137` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:150` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:188` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:238` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:249` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:276` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:287` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:396` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:409` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:303` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:318` = "posN" +- Reader (gate declared here) `AffixTemplate.requiredPartsOfSpeech`: `grammar.xml:422` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentCont__b969c67599.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentCont__b969c67599.md new file mode 100644 index 000000000..97f4bb202 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentCont__b969c67599.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGate__c60c86e42d.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGate__c60c86e42d.md new file mode 100644 index 000000000..569a39893 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGate__c60c86e42d.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentCon__6d253d349b.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentCon__6d253d349b.md new file mode 100644 index 000000000..7095e1384 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentCon__6d253d349b.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGat__54fd0d6f25.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGat__54fd0d6f25.md new file mode 100644 index 000000000..1f65d3944 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGat__54fd0d6f25.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__19541eeb94.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__19541eeb94.md new file mode 100644 index 000000000..05a1d5ae6 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__19541eeb94.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__ae41c75a2d.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__ae41c75a2d.md new file mode 100644 index 000000000..763418e39 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__ae41c75a2d.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__c42ca36802.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__c42ca36802.md new file mode 100644 index 000000000..e30805065 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__c42ca36802.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__fb4f734412.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__fb4f734412.md new file mode 100644 index 000000000..5d7159873 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__fb4f734412.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.headPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.headPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed headPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:340` = "posN1" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:361` = "posN2 posV2" +- Reader (gate declared here) `CompoundingRule.headPartsOfSpeech`: `grammar.xml:411` = "posCompH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentC__774842682d.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentC__774842682d.md new file mode 100644 index 000000000..8510807e7 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentC__774842682d.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentG__26b0dd909c.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentG__26b0dd909c.md new file mode 100644 index 000000000..59ec9f2e8 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentG__26b0dd909c.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__4bf5878f74.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__4bf5878f74.md new file mode 100644 index 000000000..c824d0e9a --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__4bf5878f74.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__ade210aed3.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__ade210aed3.md new file mode 100644 index 000000000..6c858da4d --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__ade210aed3.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__72b8aeb0e2.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__72b8aeb0e2.md new file mode 100644 index 000000000..259050fdd --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__72b8aeb0e2.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__80c226ec4d.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__80c226ec4d.md new file mode 100644 index 000000000..8c128c15b --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__80c226ec4d.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__82b1cca985.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__82b1cca985.md new file mode 100644 index 000000000..dc3c2189f --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__82b1cca985.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__a2fb797fca.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__a2fb797fca.md new file mode 100644 index 000000000..9ffeeca7b --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__a2fb797fca.md @@ -0,0 +1,66 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `CompoundingRule.nonHeadPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`CompoundingRule.nonHeadPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed nonHeadPartsOfSpeech from 3 element(s)" + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:340` = "posN1 posV1" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:361` = "posN2" +- Reader (gate declared here) `CompoundingRule.nonHeadPartsOfSpeech`: `grammar.xml:411` = "posCompNH" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__d6b52bd12c.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__d6b52bd12c.md new file mode 100644 index 000000000..522bb98a0 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__d6b52bd12c.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__f631365150.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__f631365150.md new file mode 100644 index 000000000..fed28438c --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__f631365150.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__453218f588.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__453218f588.md new file mode 100644 index 000000000..2869a6c7d --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__453218f588.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__7330f2a456.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__7330f2a456.md new file mode 100644 index 000000000..4d67b7bae --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__7330f2a456.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__82861b30e0.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__82861b30e0.md new file mode 100644 index 000000000..1a09e25d7 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__82861b30e0.md @@ -0,0 +1,78 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 16 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:102` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:114` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:125` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:137` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:150` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:188` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:238` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:249` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:276` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:287` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:396` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:409` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:102` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:114` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:125` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:137` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:150` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:188` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:238` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:249` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:276` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:287` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:396` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:409` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__84690737ed.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__84690737ed.md new file mode 100644 index 000000000..35f4037cd --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__84690737ed.md @@ -0,0 +1,80 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 17 element(s)", example: 'mano': ok::STEM+P1|mano -> ok::STEM+ABLAUT+P1|mano;STEM+P1|mano + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:233` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:271` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:283` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:302` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:316` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:350` = "posV1" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:371` = "posV2" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:386` = "posAblautV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:590` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:600` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:610` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:621` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:631` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__c736a92af2.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__c736a92af2.md new file mode 100644 index 000000000..ea0dd1a39 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__c736a92af2.md @@ -0,0 +1,78 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: edge-cases/morphotactic-attribute-breadth declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `edge-cases/morphotactic-attribute-breadth` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `edge-cases/morphotactic-attribute-breadth`): verdict=Unobservable, mutation="removed requiredPartsOfSpeech from 16 element(s)" + +## Grammar citations + +### `edge-cases/morphotactic-attribute-breadth/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:102` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:114` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:125` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:137` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:150` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:188` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:238` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:249` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:276` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:287` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:396` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:409` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:102` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:114` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:125` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:137` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:150` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:188` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:238` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:249` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:276` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:287` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:396` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:409` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__e0be41ea08.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__e0be41ea08.md new file mode 100644 index 000000000..7c3b247cd --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__e0be41ea08.md @@ -0,0 +1,80 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `MorphologicalRule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/fusional-realizational-morphology declares 18 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/fusional-realizational-morphology` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 17 element(s)" +- Reader (`MorphologicalRule.requiredPartsOfSpeech` in `languages/fusional-realizational-morphology`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 17 element(s)", example: 'mano': ok::STEM+P1|mano -> ok::STEM+ABLAUT+P1|mano;STEM+P1|mano + +## Grammar citations + +### `languages/fusional-realizational-morphology/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:199` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:210` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:221` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:233` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:260` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:271` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:283` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:302` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:316` = "posV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:350` = "posV1" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:371` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:386` = "posAblautV" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:590` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:600` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:610` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:621` = "posN" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:631` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:199` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:210` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:221` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:233` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:260` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:271` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:283` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:302` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:316` = "posV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:350` = "posV1" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:371` = "posV2" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:386` = "posAblautV" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:590` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:600` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:610` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:621` = "posN" +- Reader (gate declared here) `MorphologicalRule.requiredPartsOfSpeech`: `grammar.xml:631` = "posN" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__4124c8ccda.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__4124c8ccda.md new file mode 100644 index 000000000..edcfce348 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__4124c8ccda.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__e38c5f5e3f.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__e38c5f5e3f.md new file mode 100644 index 000000000..3dec10453 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__e38c5f5e3f.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__6b3ebfd8d1.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__6b3ebfd8d1.md new file mode 100644 index 000000000..9ddcec69a --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__6b3ebfd8d1.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__ac9f4c05a9.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__ac9f4c05a9.md new file mode 100644 index 000000000..136a49288 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__ac9f4c05a9.md @@ -0,0 +1,43 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__3dcb262312.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__3dcb262312.md new file mode 100644 index 000000000..85b465eeb --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__3dcb262312.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:359` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:382` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:392` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:402` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:413` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:423` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:438` = "posV5" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:450` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:460` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:470` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:486` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:498` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:514` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:527` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:563` = "posV3req" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:581` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__4512b08b79.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__4512b08b79.md new file mode 100644 index 000000000..0d3fca2d8 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__4512b08b79.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:359` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:382` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:392` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:402` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:413` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:423` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:438` = "posV5" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:450` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:460` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:470` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:486` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:498` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:514` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:527` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:563` = "posV3req" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:581` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__628cb178e0.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__628cb178e0.md new file mode 100644 index 000000000..cc821d6cc --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__628cb178e0.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is ABSENT from the path. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:359` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:382` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:392` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:402` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:413` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:423` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:438` = "posV5" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:450` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:460` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:470` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:486` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:498` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:514` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:527` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:563` = "posV3req" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:581` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__b28ff4fcb5.md b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__b28ff4fcb5.md new file mode 100644 index 000000000..d3f8f11b3 --- /dev/null +++ b/conformance/evidence-cards/PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__b28ff4fcb5.md @@ -0,0 +1,65 @@ +# PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech overwrites an earlier part-of-speech write via PriorityUnion) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `MorphologicalRule.outputPartOfSpeech` +- Payload type: `PartOfSpeech` +- Reader: `PhonologicalSubrule.requiredPartsOfSpeech` +- Cell kind: `Mutator`, mutator class: `PosPriorityUnion` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares 16 outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`MorphologicalRule.outputPartOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Unobservable, mutation="removed outputPartOfSpeech from 16 element(s)" +- Reader (`PhonologicalSubrule.requiredPartsOfSpeech` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredPartsOfSpeech from 3 element(s)", example: 'mbe': ok::- -> ok::PPE|mbe + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:359` = "posV2" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:382` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:392` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:402` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:413` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:423` = "posV3" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:438` = "posV5" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:450` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:460` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:470` = "posV4" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:486` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:498` = "posV6" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:514` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:527` = "posV7" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:563` = "posV3req" +- Writer (payload declared here) `MorphologicalRule.outputPartOfSpeech`: `grammar.xml:581` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:308` = "posV" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:325` = "posV3req" +- Reader (gate declared here) `PhonologicalSubrule.requiredPartsOfSpeech`: `grammar.xml:340` = "posV3excl" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentControl__80b3a351fe.md b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentControl__80b3a351fe.md new file mode 100644 index 000000000..63376c6be --- /dev/null +++ b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentControl__80b3a351fe.md @@ -0,0 +1,43 @@ +# StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT, and the reader does NOT block (control case: normal operation without the payload). + +## Chain + +- Writer: `Allomorph.stemName` +- Payload type: `StemName` +- Reader: `MorphologicalRule.requiredStemName` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentGatedForm__6826e8cb31.md b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentGatedForm__6826e8cb31.md new file mode 100644 index 000000000..fd76be28c --- /dev/null +++ b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentGatedForm__6826e8cb31.md @@ -0,0 +1,43 @@ +# StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload is ABSENT and the gated form IS blocked. + +## Chain + +- Writer: `Allomorph.stemName` +- Payload type: `StemName` +- Reader: `MorphologicalRule.requiredStemName` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentControl__a23884cfb4.md b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentControl__a23884cfb4.md new file mode 100644 index 000000000..9774e811e --- /dev/null +++ b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentControl__a23884cfb4.md @@ -0,0 +1,43 @@ +# StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:PresentControl + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present, and the reader does NOT block (control case: normal operation with the payload present). + +## Chain + +- Writer: `Allomorph.stemName` +- Payload type: `StemName` +- Reader: `MorphologicalRule.requiredStemName` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentGatedForm__8ebc5bd646.md b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentGatedForm__8ebc5bd646.md new file mode 100644 index 000000000..cb557096f --- /dev/null +++ b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentGatedForm__8ebc5bd646.md @@ -0,0 +1,43 @@ +# StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:PresentGatedForm + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +the payload IS present and the gated form IS blocked. + +## Chain + +- Writer: `Allomorph.stemName` +- Payload type: `StemName` +- Reader: `MorphologicalRule.requiredStemName` +- Cell kind: `McDc` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm + +## Fixture and word + +- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none. + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +No fixture is identified for this cell, so no witness row can be looked up. + +## Grammar citations + +No fixture is identified for this cell, so no `grammar.xml` lines can be cited. +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorAbsent_Blocking__8c73af3032.md b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorAbsent_Blocking__8c73af3032.md new file mode 100644 index 000000000..0f990c174 --- /dev/null +++ b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorAbsent_Blocking__8c73af3032.md @@ -0,0 +1,48 @@ +# StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::Mutator:MutatorAbsent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +no mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is ABSENT from the path. + +## Chain + +- Writer: `Allomorph.stemName` +- Payload type: `StemName` +- Reader: `MorphologicalRule.requiredStemName` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`Allomorph.stemName` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed stemName from 1 element(s)", example: 'daleh': ok::DAL+STEMREQ|daleh -> ok::- +- Reader (`MorphologicalRule.requiredStemName` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredStemName from 1 element(s)", example: 'daheh': ok::- -> ok::DAH+STEMREQ|daheh + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `Allomorph.stemName`: `grammar.xml:701` = "snG5" +- Reader (gate declared here) `MorphologicalRule.requiredStemName`: `grammar.xml:527` = "snG5" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorPresent_Blocking__61c9f3cf5c.md b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorPresent_Blocking__61c9f3cf5c.md new file mode 100644 index 000000000..a993d3636 --- /dev/null +++ b/conformance/evidence-cards/StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorPresent_Blocking__61c9f3cf5c.md @@ -0,0 +1,48 @@ +# StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::Mutator:MutatorPresent:Blocking + +GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead. + +## Role, in plain English + +a mutator sits between the write and the read: blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing and reseeding MPR features, part of speech, and stem name) is PRESENT and structurally capable of killing the payload before the reader sees it. + +## Chain + +- Writer: `Allomorph.stemName` +- Payload type: `StemName` +- Reader: `MorphologicalRule.requiredStemName` +- Cell kind: `Mutator`, mutator class: `Blocking` + +## Machine status + +**Unknown** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review verdict. A human sign-off is a separate fact and is never recorded here. + +Ledger evidence: structurally hazardous: languages/suffixing-extension-slot-ordering declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here + +## Fixture and word + +- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific word -- only fixture `languages/suffixing-extension-slot-ordering` (extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)). + +## Exact mutation and before/after parse + +No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell. + +### Machine witness (`conformance/interface-witness.tsv`) + +- Writer (`Allomorph.stemName` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed stemName from 1 element(s)", example: 'daleh': ok::DAL+STEMREQ|daleh -> ok::- +- Reader (`MorphologicalRule.requiredStemName` in `languages/suffixing-extension-slot-ordering`): verdict=Evidenced, mutation="removed requiredStemName from 1 element(s)", example: 'daheh': ok::- -> ok::DAH+STEMREQ|daheh + +## Grammar citations + +### `languages/suffixing-extension-slot-ordering/grammar.xml` + +- Writer (payload declared here) `Allomorph.stemName`: `grammar.xml:701` = "snG5" +- Reader (gate declared here) `MorphologicalRule.requiredStemName`: `grammar.xml:527` = "snG5" + +## Author's prose + +- No prose recorded: no claim, and no word is identified for this cell. + +## `distinct_from` counterpart + +No claim exists for this cell, so no `distinct_from` counterpart is recorded. diff --git a/conformance/evidence-cards/index.tsv b/conformance/evidence-cards/index.tsv new file mode 100644 index 000000000..0b79fb0a2 --- /dev/null +++ b/conformance/evidence-cards/index.tsv @@ -0,0 +1,352 @@ +# GENERATED by hc-conformance --write-evidence-cards. Maps each conformance/dataflow-obligations.tsv +# cell_id to the Markdown card that renders it under conformance/evidence-cards/ -- file names are +# a truncated, sanitized slug of the cell id plus a stable content hash (cell ids contain ':'/'.' +# /'->' and can exceed Windows path-length limits verbatim), so this index is the lookup a +# human or gate uses instead of reconstructing the file name by hand. +cell_id file_name +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__a2eb8294a4.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c458c1ff29.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__c6138fd4fd.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__465d14e7ea.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__12c1dd278b.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__93c811f4d5.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__aa369d5755.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__ef1546bf5d.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__567ab12323.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__abc75d50e6.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__7e8dfce20c.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__fd29133b69.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__052ae9e692.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__467816e969.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__b0e58b74f2.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_CompoundingR__0a7b6ab127.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__96581b2cd9.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__35c72b2b37.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__1eda51418f.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9226354c95.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__97b09dae7d.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__9299596233.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__56ff64b77c.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__37c442dab7.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__4d08fbcb7c.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__5fea2ced00.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__cddbf27789.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__415b26f386.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__e66f1ca54a.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d796a07fa2.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__d99534f349.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_HeadMorpholo__405a9614b4.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2f467ca65b.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__eb45ca963c.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__78f6bef8c8.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cfcaf6aad9.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__dcb5cdf354.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__6b8f280520.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__1517146226.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe09105f72.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2758486360.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__2e5601a4c2.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__64995b1c65.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__9075d6cf1e.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__906fe66113.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__8bd9dcbef2.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__ce747db9c8.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__d5e5d69c61.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__cc92c992f8.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__fe117dd02d.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__b0b0b46a1a.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Morphologica__790befcd64.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__421fa34556.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__abda497cb4.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__ebb45949a6.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1c84ebb58a.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__5eca01cd32.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__864a3c00a3.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f3ebd9210b.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__dd4151c4fe.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c1a283bb40.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c775f67d2b.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__1f2b9caf36.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f749d716c7.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__f8b238ecbe.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__a60574b201.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__b54787693b.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__6374bee20a.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__d4c7012b97.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__253ea8070c.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__c4d80b41ec.md +MorphologicalPhonologicalRuleFeature::CompoundingRule.outputProdRestrictionsMprFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_CompoundingRule.outputProdRestrictionsMprFeatures-_Phonological__27d1114083.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a92ba2d57e.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__babe17f79e.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__58bce01d05.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__9b745dcd86.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__a46fb6d267.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__effb1f89e2.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__203812db54.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.headProdRestrictions__98401f9202.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__c494cd5fcb.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__62cc6f6e55.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__a339c69438.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__9ae48b649a.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__54bf8baa0b.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__8bacba3d80.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__adb12adc76.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_CompoundingRule.nonHeadProdRestricti__1b3451751a.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__0b282120a4.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__e721931de3.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__a1d7e84b20.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__6f38e7a899.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__5603689493.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__357f5a25bc.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__087a1ee277.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.excludedMPRFe__3b313cba38.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__5000df9f32.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__1f9a1ccadc.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__caf3c5dd47.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__65217a5ef6.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7291112a11.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__de9acd72d5.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__7f676b3fc5.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_HeadMorphologicalInput.requiredMPRFe__ffff27d9b0.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__7a25f70cd7.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__702762c0f9.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__a65827b3c9.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__bd8e009600.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__0d618c944c.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__5026df6a95.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__ebbec8602a.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b7765fce5a.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__e5f69f5a64.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.excludedMPRFeatur__b991bc3075.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3Control:languages/fusional-realizational-morphology MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__2c09dc0c6a.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3GatedForm:languages/fusional-realizational-morphology MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__e4dac625a8.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__41e8e8056f.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__0f3d86ac4b.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__6c132d754d.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__57f78eca98.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__44f82457d0.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__1c74446857.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__bc8720c649.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__fc52e807aa.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__a6edbbf91c.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_MorphologicalInput.requiredMPRFeatur__480dfb8ea4.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__046705cf46.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__9238acddc7.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__0e07ff724c.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__accfca0bda.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e09a3fc53a.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__e31f5ff6a6.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__02e8c1d4b0.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__4dab0fc534.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__d082d864eb.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.excludedMPRFeatu__b2d1b47c42.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__439a31b7db.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__cf84a64879.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__babdf41edb.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__5e88566ca5.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__be70f8a294.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__0c716ed680.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__e2d2525d54.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__2b3161f60e.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4eb890fcf9.md +MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_LexicalEntry.ruleFeatures-_PhonologicalSubrule.requiredMPRFeatu__4860eb4802.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__7b2b736272.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__eabac31439.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__9818f76507.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__f50c9ea523.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__960586fc20.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5d1391448.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__0c9d8962c6.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.headProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.headProdRestri__a5c2ae3b0b.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ed79a7fd12.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__2c1970a9d0.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__ca5bb9f72b.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__5a11107cca.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f8d1a8842d.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__c11d047cc3.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f2861c0957.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->CompoundingRule.nonHeadProdRestrictionsMprFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_CompoundingRule.nonHeadProdRes__f9938dd123.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__51153ce7b8.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__d0d2dfe62c.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__ff7a5f84e6.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__276bbeee50.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__bab91881f5.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__7144b8b154.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__8940376b9e.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.exclude__072c9ca1bf.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__96f5b25fd2.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__af77f63865.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__359421269f.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__560fba93ef.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__da47e0486f.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__7f5e095707.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__00d5cacf7c.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->HeadMorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_HeadMorphologicalInput.require__3464c8928b.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a1365c87bf.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__82cc2c30cf.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__5e8b2b839e.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__46a77463a4.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__03b5f060c4.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__3e2b83906f.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__a0b4289d2a.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__897627234b.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__c1bf9a3742.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.excludedMPR__541dc27660.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3Control:edge-cases/mpr-overwrite-order-dependence MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__1d7a649164.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::ConditionExtension:McDcVector3GatedForm:edge-cases/mpr-overwrite-order-dependence MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__33aaa87cb8.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__9a427b5040.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e46cfee1d1.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__4d56ef58ab.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__423093b89f.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__dff8d6ff95.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__e68235eebb.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6f6a3c7be2.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__6a0738e58d.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__c43b787c90.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_MorphologicalInput.requiredMPR__7ad6be3e44.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a5e2ccf42a.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__a524525471.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__5d863899ec.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__3a50ce58d4.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__6d8ca45a01.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__bd77eb6f30.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9901ca7838.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__e1cb70b918.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__9f07bc6b34.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.excludedMP__dcacddbe6b.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__15619d7374.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__272f2eff25.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentControl MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__724988ff85.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:PresentGatedForm MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__cfa6a04091.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__613c3bd08b.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__ee64baff46.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorAbsent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__fe6bfd4ffe.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Blocking MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__67552876cb.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:CompoundingNonHeadDrop MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__82cd28b991.md +MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::Mutator:MutatorPresent:Overwrite MorphologicalPhonologicalRuleFeature_MorphologicalOutput.MPRFeatures-_PhonologicalSubrule.requiredMP__c5e8f0bdd2.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCont__1279c82367.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGate__e809525828.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentCon__69fa993ea6.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGat__07a16a4cfe.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__243845d05e.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__d06fe8ee83.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__ab2424673d.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutator__0b9bd700b1.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentContro__d836fc0cf4.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedF__482ad3d9ed.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentContr__d78150d7c7.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGated__30da04ee2f.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__466ff08aae.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAb__cc6cb61e70.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__0c340e4205.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPr__83594721ef.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentCon__2274b0e237.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGat__a0adb93408.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentCo__e3487dd647.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGa__d9159f1374.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__8e6c8a918f.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__1113ca565a.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__75faacc83a.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Mutato__b1a3af58f4.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__bce657e908.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Absent__343dd24ada.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__4d5c16475f.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Presen__cf6c32cac7.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__756edf94e4.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5c53e2628d.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__5d88ceb7e6.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_Mut__118ae9565e.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__26b5ae41c5.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Abse__a12e4b86ee.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__44c6571023.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pres__8bddaa7cca.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__4bc935f0cc.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__562b30b100.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__739fd876fc.md +PartOfSpeech::CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_CompoundingRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_M__0f7ddf55bf.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentControl__a5b4995baa.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGatedForm__dc25dce562.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentControl__3da410288c.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentGatedForm__0fc1fd9740.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Bl__e47d3d51db.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorAbsent_Po__c731ce6cd5.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_B__54bb99a44b.md +PartOfSpeech::LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_MutatorPresent_P__a4060dd34c.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentControl__f3e516d6fd.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGatedForm__1bea7c3fa6.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentControl__09151a056b.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGatedForm__c71a480a3b.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_Bloc__f0e1fcf009.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorAbsent_PosP__0d0dd22ef9.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Blo__79033eb224.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_MutatorPresent_Pos__aa1b56f9fa.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentControl__79a58b0237.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentGatedForm__396b84ab5a.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentControl__ce8026bc83.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_PresentGatedForm__26ced6d991.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_B__e400b4a993.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorAbsent_P__335516f509.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___3a7a548bf6.md +PartOfSpeech::LexicalEntry.partOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_MutatorPresent___0685342ef3.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentControl__29a6b50f8a.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_AbsentGatedForm__19788af842.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentControl__5c0774a54a.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_PresentGatedFor__7589d364d6.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3e506284e1.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorAbsen__3aaacd2922.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f261d96931.md +PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_MutatorPrese__f8386bced5.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentControl__cd479494ba.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_AbsentGatedFo__918bf3ccbd.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentContro__9f6e2a8199.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_PresentGatedF__146e6d44f8.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__1c868fac61.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorAbs__5d14512c40.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__91e275055b.md +PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_LexicalEntry.partOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator_MutatorPre__19c2a7e90c.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentCo__427b970f16.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_AbsentGa__07d26442ca.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentC__275363a4e6.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_McDc_PresentG__2c21324b11.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__fd652643d4.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__ae5db4f350.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__d510fa6c76.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_AffixTemplate.requiredPartsOfSpeech_Mutator_Mutat__de951125fb.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentCont__b969c67599.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_AbsentGate__c60c86e42d.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentCon__6d253d349b.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_McDc_PresentGat__54fd0d6f25.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__ae41c75a2d.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__fb4f734412.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__c42ca36802.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.headPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.headPartsOfSpeech_Mutator_Mutator__19541eeb94.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentC__774842682d.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_AbsentG__26b0dd909c.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__ade210aed3.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_McDc_Present__4bf5878f74.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__82b1cca985.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__80c226ec4d.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__a2fb797fca.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->CompoundingRule.nonHeadPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_CompoundingRule.nonHeadPartsOfSpeech_Mutator_Muta__72b8aeb0e2.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__f631365150.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Abse__d6b52bd12c.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__7330f2a456.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_McDc_Pres__453218f588.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__c736a92af2.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__e0be41ea08.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__82861b30e0.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_MorphologicalRule.requiredPartsOfSpeech_Mutator_M__84690737ed.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__e38c5f5e3f.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Ab__4124c8ccda.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentControl PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__ac9f4c05a9.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:PresentGatedForm PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_McDc_Pr__6b3ebfd8d1.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__3dcb262312.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorAbsent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__628cb178e0.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:Blocking PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__4512b08b79.md +PartOfSpeech::MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::Mutator:MutatorPresent:PosPriorityUnion PartOfSpeech_MorphologicalRule.outputPartOfSpeech-_PhonologicalSubrule.requiredPartsOfSpeech_Mutator__b28ff4fcb5.md +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentControl StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentControl__80b3a351fe.md +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentGatedForm StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_AbsentGatedForm__6826e8cb31.md +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:PresentControl StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentControl__a23884cfb4.md +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:PresentGatedForm StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_McDc_PresentGatedForm__8ebc5bd646.md +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::Mutator:MutatorAbsent:Blocking StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorAbsent_Blocking__8c73af3032.md +StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::Mutator:MutatorPresent:Blocking StemName_Allomorph.stemName-_MorphologicalRule.requiredStemName_Mutator_MutatorPresent_Blocking__61c9f3cf5c.md diff --git a/conformance/fieldworks-producibility.tsv b/conformance/fieldworks-producibility.tsv new file mode 100644 index 000000000..0bdab7ad6 --- /dev/null +++ b/conformance/fieldworks-producibility.tsv @@ -0,0 +1,92 @@ +# GENERATED by conformance/tools/generate-fieldworks-producibility.ps1. One row per subject, +# where subjects are every SIL.Machine.Morphology.HermitCrab.FailureReason enum member (except +# None) plus every (element, attribute) row in conformance/interface-inventory.tsv. Authority: +# FieldWorks' HCLoader.cs (Src/LexText/ParserCore/HCLoader.cs) -- the component that turns a +# real FieldWorks/LibLCM project into an HC grammar. producible=No means no FieldWorks user can +# ever produce this construct, so covering it elsewhere in this suite proves nothing about real +# use. See conformance/docs/how-it-is-computed.md for the full explanation, including why this +# ledger is a point-in-time snapshot of an external repo that cannot be drift-checked here. +subject_kind subject producible hcloader_sites notes +failure-reason ObligatorySyntacticFeatures No HCLoader never sets AffixProcessRule.ObligatorySyntacticFeatures or CompoundingRule.ObligatorySyntacticFeatures (checked LoadDerivAffixProcessRule HCLoader.cs:926-974, LoadInflAffixProcessRule 976-1006, LoadEndoCompoundingRule 1842-1912, LoadExoCompoundingRule 1922-2001 -- zero assignments). The only engine trigger, Morpher.cs:603-613, gates on word.ObligatorySyntacticFeatures, fed exclusively by those two rule properties, so this reason can never fire for a FieldWorks-produced grammar. Searched HCLoader.cs for: ObligatorySyntacticFeatures, OutputObligatoryFeatures, obligatoryHeadFeatures, obligatoryFootFeatures, Obligatory -- zero hits beyond unrelated identifiers. Matches this task's stated known data point exactly, and is the same underlying gap behind interface rows CompoundingRule.outputObligatoryFeatures and MorphologicalRule.outputObligatoryFeatures (also No). +failure-reason AllomorphCoOccurrenceRules Yes HCLoader.cs:2163-2189 (LoadAllomorphCoOccurrenceRules); HCLoader.cs:341-345 (call site, gated on IMoAlloAdhocProhibRepository) Corroborated by HCLoaderTests.cs:1046-1047 (AllomorphCoOccurrenceRules.Count/First asserted). +failure-reason Environments Yes HCLoader.cs:815-829 (LoadRootAllomorph); HCLoader.cs:1322 (LoadCircumfixAffixProcessAllomorph); HCLoader.cs:1577,1604 (LoadFormAffixProcessAllomorph) Any phonologically-conditioned allomorph environment a FieldWorks user enters produces this; one of the most routine constructs in the loader. +failure-reason MorphemeCoOccurrenceRules Yes HCLoader.cs:2213-2239 (LoadMorphemeCoOccurrenceRules); HCLoader.cs:347-351 (call site, gated on IMoMorphAdhocProhibRepository) Corroborated by HCLoaderTests.cs:1066-1067 (MorphemeCoOccurrenceRules.Count/First asserted). +failure-reason DisjunctiveAllomorph Yes HCLoader.cs:716-728 (LoadLexEntry, multiple RootAllomorph added per entry); engine repo Allomorph.cs:127-151 derives this purely from allomorph index/environment ordering Not gated by a distinct DTD attribute; fires whenever an entry HCLoader builds has more than one ordered, differently-conditioned allomorph -- ordinary FieldWorks allomorphy. +failure-reason SurfaceFormMismatch Yes HCLoader.cs:204,2669-2743 (LoadCharacterDefinitionTable, always invoked once); HCLoader.cs:233 (Surface stratum, always created) Intrinsic engine self-check (engine repo Morpher.cs:620-633) comparing a synthesized shape to the surface stratum's table; exercised on every FieldWorks-produced grammar, not gated by an optional construct. +failure-reason Pattern Yes HCLoader.cs:2313-2418 (LoadPatternNode/LoadPatternNodes, used throughout affix and phonological rule construction) Fires on any Lhs pattern mismatch; reachable trivially for any grammar with at least one rule, which every FieldWorks project produces. +failure-reason HeadPattern Yes HCLoader.cs:1808-1840 (DefaultCompoundingRules, always generated unless NoDefaultCompounding is set); HCLoader.cs:1878-1904 (LoadEndoCompoundingRule head/nonhead pattern); HCLoader.cs:1943-1965 (LoadExoCompoundingRule head/nonhead pattern) Default compounding rules alone make this reachable even with zero user-defined compound rules. +failure-reason NonHeadPattern Yes HCLoader.cs:1808-1840 (DefaultCompoundingRules); HCLoader.cs:1878-1904,1943-1965 (Endo/Exo nonhead pattern) Same reachability as HeadPattern. +failure-reason RequiredSyntacticFeatureStruct Yes HCLoader.cs:930-936 (LoadDerivAffixProcessRule); HCLoader.cs:985-991 (LoadInflAffixProcessRule); HCLoader.cs:1016-1020 (LoadUnclassifiedAffixProcessRule); HCLoader.cs:1034-1038 (LoadCliticAffixProcessRule); HCLoader.cs:2051-2055 (LoadRewriteRule) +failure-reason HeadRequiredSyntacticFeatureStruct Yes HCLoader.cs:1844-1892 (LoadEndoCompoundingRule); HCLoader.cs:1922-1957 (LoadExoCompoundingRule, right rule) +failure-reason NonHeadRequiredSyntacticFeatureStruct Yes HCLoader.cs:1844-1892 (LoadEndoCompoundingRule); HCLoader.cs:1922-1984 (LoadExoCompoundingRule, both rules) +failure-reason HeadProdRestrictMprFeatures Yes HCLoader.cs:1888 (LoadEndoCompoundingRule); HCLoader.cs:1953,1980 (LoadExoCompoundingRule, both rules) Matches this task's stated known data point (~6 total hits across Head+NonHead assignments). +failure-reason NonHeadProdRestrictMprFeatures Yes HCLoader.cs:1889 (LoadEndoCompoundingRule); HCLoader.cs:1954,1981 (LoadExoCompoundingRule, both rules) Engine trigger site (AnalysisCompoundingRule.cs) is analysis/parse direction only, not synthesis -- still reachable since parsing text is FLEx's primary use of HC. +failure-reason RequiredMprFeatures Yes HCLoader.cs:968,1001,1069,1096,1123 (AffixProcessAllomorph.RequiredMprFeatures); HCLoader.cs:2057 (RewriteSubrule.RequiredMprFeatures) The CompoundingSubrule.RequiredMprFeatures path (HeadMorphologicalInput.requiredMPRFeatures) is never populated (see that interface row, No), but the affix/phonological paths alone make this reachable. +failure-reason ExcludedMprFeatures Yes HCLoader.cs:1717 (slot-blocking of irregularly-inflected forms); HCLoader.cs:2058 (RewriteSubrule.ExcludedMprFeatures) +failure-reason RequiredStemName Yes HCLoader.cs:960-962 (LoadDerivAffixProcessRule) Corroborated by HCLoaderTests.cs:698. +failure-reason ExcludedStemName Yes HCLoader.cs:831-833 (LoadRootAllomorph sets Allomorph.stemName; nothing prevents >1 stem-named allomorph per entry); engine repo RootAllomorph.cs:72-91 derives ExcludedStemName purely from a second, differently stem-named sibling allomorph Structural consequence of a stem-name-restricted paradigm with more than one region on one entry's allomorphs -- ordinary FieldWorks usage, same underlying attribute as Allomorph.stemName (Yes). +failure-reason PartialParse Yes HCLoader.cs:708 (LoadLexEntry, IsPartial when entry has no POS); HCLoader.cs:982 (LoadInflAffixProcessRule, IsPartial when no slots); HCLoader.cs:1013 (LoadUnclassifiedAffixProcessRule, always IsPartial) Corroborated by HCLoaderTests.cs:662,726,845. +failure-reason BoundRoot Yes HCLoader.cs:835-841 (LoadRootAllomorph, IsBound for bound-root/bound-stem morph types) Corroborated by HCLoaderTests.cs:818. +failure-reason NonPartialRuleProhibitedAfterFinalTemplate Yes HCLoader.cs:1678 (AffixTemplate.IsFinal from LibLCM template.Final); HCLoader.cs:708,982,1013 (rule IsPartial sites) Corroborated by HCLoaderTests.cs:750,789 (IsFinal). Reachable whenever a non-final template is followed by a non-partial, non-template rule such as a derivational affix or clitic. +failure-reason NonPartialRuleRequiredAfterNonFinalTemplate Yes HCLoader.cs:1678 (AffixTemplate.IsFinal); HCLoader.cs:708,982,1013 (rule IsPartial sites) Same drivers as NonPartialRuleProhibitedAfterFinalTemplate, opposite polarity of the same engine check. +failure-reason MaxApplicationCount Yes HCLoader.cs:103-112 (ParserParameters CompoundRules/maxApps parsed into m_CompoundRuleLookup); HCLoader.cs:1894-1896 (CompoundingRule.MaxApplicationCount assignment) Only ever wired for CompoundingRule, not AffixProcessRule (grep-confirmed single assignment site) -- still reachable via the compounding path. +interface-attribute AffixTemplate.requiredPartsOfSpeech Yes HCLoader.cs:1681-1684 (LoadAffixTemplate) +interface-attribute AffixTemplate.requiredSubcategorizedRules No Subcategorization/SyntacticRule is dead schema across the WHOLE engine, not just HCLoader: grepping src/SIL.Machine.Morphology.HermitCrab for 'Subcategoriz' outside the DTD file itself returns zero hits (no C# class implements it), and HCLoader.cs / HCLoaderTests.cs likewise have zero hits for 'Subcategoriz' or 'SyntacticRule'. Confirmed by this repo's own InteractionChainLedger.cs comments ('dead (subcategorization)') on all 9 subcategorization-family attributes (rows 12,20,23,27,35(no -- separate reason),40,52,55,56,57). +interface-attribute Allomorph.stemName Yes HCLoader.cs:831-833 (LoadRootAllomorph) Corroborated by HCLoaderTests.cs:817. +interface-attribute AllomorphCoOccurrenceRule.otherAllomorphs Yes HCLoader.cs:2163-2189 +interface-attribute AllomorphCoOccurrenceRule.primaryAllomorph Yes HCLoader.cs:2166,2181-2186 +interface-attribute AlphaVariable.variableFeature Yes HCLoader.cs:2005-2011 (LoadRewriteRule, variable naming); HCLoader.cs:2765-2773 (GetVariables ties a variable name to a specific phonological feature) The Machine engine has no runtime 'AlphaVariable' class (grep-confirmed) -- the DTD's two-hop AlphaVariable->VariableFeature->feature indirection collapses at runtime to SymbolicFeatureValue(feature, variableName, agree), which HCLoader constructs directly. +interface-attribute BoundaryMarker.boundary Yes HCLoader.cs:2698-2712 (LoadCharacterDefinitionTable loads BoundaryMarkersOC into m_charDefs); HCLoader.cs:2348-2360 (LoadPatternNode, PhSimpleContextBdry emits a Constraint referencing that charDef) +interface-attribute CompoundingRule.headPartsOfSpeech Yes HCLoader.cs:1848-1869 (LoadEndoCompoundingRule); HCLoader.cs:1924-1931 (LoadExoCompoundingRule) +interface-attribute CompoundingRule.headProdRestrictionsMprFeatures Yes HCLoader.cs:1888,1953,1980 Matches this task's stated known data point (~6 hits). +interface-attribute CompoundingRule.headSubcategorizedRules No Subcategorization, dead (see AffixTemplate.requiredSubcategorizedRules). +interface-attribute CompoundingRule.nonHeadPartsOfSpeech Yes HCLoader.cs:1852-1864,1929-1930 +interface-attribute CompoundingRule.nonHeadProdRestrictionsMprFeatures Yes HCLoader.cs:1889,1954,1981 interface-inventory.tsv shows present=no because no CONFORMANCE FIXTURE happens to exercise it -- a corpus-coverage fact, not an HCLoader-capability fact. The code path is identical to headProdRestrictionsMprFeatures. +interface-attribute CompoundingRule.nonHeadSubcategorizedRules No Subcategorization, dead. +interface-attribute CompoundingRule.outputObligatoryFeatures No Absence confirmed across LoadEndoCompoundingRule (HCLoader.cs:1842-1912) and LoadExoCompoundingRule (HCLoader.cs:1922-2001) -- neither ever touches CompoundingRule.ObligatorySyntacticFeatures. The engine fully implements this (CompoundingRule.cs:54-57, XmlLanguageLoader.cs:1227-1231), so this is a FieldWorks-specific gap, not dead schema -- the same absence drives FailureReason.ObligatorySyntacticFeatures=No. Searched: ObligatorySyntacticFeatures, outputObligatoryFeatures, Obligatory. +interface-attribute CompoundingRule.outputPartOfSpeech Yes HCLoader.cs:1873-1876,1932-1935 +interface-attribute CompoundingRule.outputProdRestrictionsMprFeatures No Property OutputProdRestrictionsMprFeatures exists on CompoundingRule (engine repo CompoundingRule.cs:25,50) and is never set by HCLoader (checked LoadEndoCompoundingRule HCLoader.cs:1842-1912 and LoadExoCompoundingRule 1922-2001; grep-confirmed zero hits for 'OutputProdRestrictionsMprFeatures' across all of HCLoader.cs). Only OutMprFeatures, HeadProdRestrictionsMprFeatures and NonHeadProdRestrictionsMprFeatures are ever populated. +interface-attribute CompoundingRule.outputSubcategorization No Subcategorization, dead. +interface-attribute CopyFromInput.index Yes HCLoader.cs:1310,1384,1454-1518,1547-1601 (pervasive) +interface-attribute FeatureValue.feature Yes HCLoader.cs:2500-2530 (LoadFeatureStruct) +interface-attribute FeatureValue.symbolValues Yes HCLoader.cs:2507-2516 +interface-attribute HeadMorphologicalInput.excludedMPRFeatures No Absence confirmed across both compounding-rule loaders (HCLoader.cs:1898-1910 Endo, 1959-1971/1986-1998 Exo) -- CompoundingSubrule.ExcludedMprFeatures (engine repo CompoundingSubrule.cs:48-51) is never set by HCLoader; grep-confirmed only OutMprFeatures is ever touched on a CompoundingSubrule. Ground truth for which runtime property this DTD attribute maps to: engine repo XmlLanguageLoader.cs:1278-1279. +interface-attribute HeadMorphologicalInput.requiredMPRFeatures No Same absence and citations as HeadMorphologicalInput.excludedMPRFeatures (CompoundingSubrule.RequiredMprFeatures is likewise never set; XmlLanguageLoader.cs:1278 is the ground-truth mapping). +interface-attribute InsertSegments.characterDefinitionTable No HCLoader.cs:204 loads exactly one PhonemeSetsOS[0] as the whole grammar's character table; HCLoader.cs:2831-2835 (Segments() helper) and every InsertSegments call always route through that single m_table field; HCLoader.cs:2742 adds it to m_language.CharacterDefinitionTables exactly once. HCLoader architecturally never builds more than one CharacterDefinitionTable, so an explicit override to a non-default table -- what this attribute exists for -- can never carry a meaningful value, in any FieldWorks project or configuration. +interface-attribute LexicalEntry.family No Full-file grep of HCLoader.cs for 'family'/'Family' returns zero hits. The engine's LexFamily/LexEntry.Family mechanism exists (engine repo LexEntry.cs:92, LexFamily.cs) and HCLoader's own TODO comment (HCLoader.cs:744, 'irregularly inflected forms should be handled by rule blocking in HC') shows it deliberately uses a different, MPR-feature-based mechanism instead of the engine's native Family-blocking feature for exactly the case (irregular/variant forms) the DTD comment says Family exists for. +interface-attribute LexicalEntry.morphologicalRules No Dead even in the engine's own reference XML loader (this repo's InteractionChainLedger.cs:79, 'dead: no loader reference at all'). LexEntry has no MorphologicalRules property at all in the runtime object model (grep-confirmed against engine repo LexEntry.cs), so HCLoader cannot set it regardless of what LibLCM data exists. +interface-attribute LexicalEntry.obligatoryFootFeatures No Dead even in the engine's own reference XML loader (InteractionChainLedger.cs:80). LexEntry has no such property (only MprFeatures, SyntacticFeatureStruct -- engine repo LexEntry.cs:80,86). +interface-attribute LexicalEntry.obligatoryHeadFeatures No Dead even in the engine's own reference XML loader (InteractionChainLedger.cs:81). Matches this task's stated expectation. Searched HCLoader.cs and engine repo LexEntry.cs for: obligatoryHeadFeatures, ObligatoryHeadFeatures, Obligatory -- zero hits beyond the unrelated ObligatorySyntacticFeatures mechanism. +interface-attribute LexicalEntry.partOfSpeech Yes HCLoader.cs:705-708 +interface-attribute LexicalEntry.ruleFeatures Yes HCLoader.cs:695-701,737-746 (inflection-class and productivity-restriction features unioned into hcEntry.MprFeatures) +interface-attribute LexicalEntry.subcategorizations No Subcategorization, dead. +interface-attribute MetathesisRule.leftSwitch Yes HCLoader.cs:2103-2161 (LoadMetathesisRule); HCLoader.cs:322-336 (call site, gated on LeftSwitchIndex/RightSwitchIndex != -1) +interface-attribute MetathesisRule.rightSwitch Yes HCLoader.cs:2103-2161; HCLoader.cs:322-336 +interface-attribute ModifyFromInput.index Yes HCLoader.cs:1409-1419 +interface-attribute MorphemeCoOccurrenceRule.otherMorphemes Yes HCLoader.cs:2213-2239 +interface-attribute MorphemeCoOccurrenceRule.primaryMorpheme Yes HCLoader.cs:2215-2235 +interface-attribute MorphologicalInput.excludedMPRFeatures Yes HCLoader.cs:1717 (AffixProcessAllomorph.ExcludedMprFeatures) Ground-truth mapping via engine repo XmlLanguageLoader.cs:1057-1062. +interface-attribute MorphologicalInput.requiredMPRFeatures Yes HCLoader.cs:968,1001,1069,1096,1123 +interface-attribute MorphologicalOutput.MPRFeatures Yes HCLoader.cs:969 (AffixProcessAllomorph.OutMprFeatures); HCLoader.cs:1901,1961,1988 (CompoundingSubrule.OutMprFeatures) +interface-attribute MorphologicalPhonologicalRuleFeatureGroup.features Yes HCLoader.cs:168-192 (LoadLanguage, three MprFeatureGroups); HCLoader.cs:571-577 (LoadMprFeature, group.MprFeatures.Add(feat)) +interface-attribute MorphologicalRule.outputObligatoryFeatures No Absence confirmed across all four AffixProcessRule loaders (HCLoader.cs:926-1046). AffixProcessRule.ObligatorySyntacticFeatures (engine repo AffixProcessRule.cs:68) is never set. Same underlying gap as CompoundingRule.outputObligatoryFeatures and FailureReason.ObligatorySyntacticFeatures (both also No). +interface-attribute MorphologicalRule.outputPartOfSpeech Yes HCLoader.cs:938-944 +interface-attribute MorphologicalRule.outputSubcategorization No Subcategorization, dead. +interface-attribute MorphologicalRule.requiredPartsOfSpeech Yes HCLoader.cs:930-936,985-991,1016-1020,1034-1038 +interface-attribute MorphologicalRule.requiredStemName Yes HCLoader.cs:960-962 Corroborated by HCLoaderTests.cs:698. +interface-attribute MorphologicalRule.requiredSubcategorizedRules No Subcategorization, dead. +interface-attribute OutputSubcategorizationOverride.inputSubcategorization No Subcategorization, dead; the OutputSubcategorizationOverride element is never referenced anywhere in HCLoader.cs. +interface-attribute OutputSubcategorizationOverride.outputSubcategorization No Subcategorization, dead; see inputSubcategorization. +interface-attribute PhonologicalSubrule.excludedMPRFeatures Yes HCLoader.cs:2058 interface-inventory.tsv shows present=no (no fixture exercises it) but the HCLoader code path is live -- a corpus-coverage fact, not a capability fact. +interface-attribute PhonologicalSubrule.requiredMPRFeatures Yes HCLoader.cs:2057 Same corpus-coverage caveat as excludedMPRFeatures. +interface-attribute PhonologicalSubrule.requiredPartsOfSpeech Yes HCLoader.cs:2051-2055 +interface-attribute Segment.segment Yes HCLoader.cs:2362-2374 (LoadPatternNode, PhSimpleContextSeg) +interface-attribute Segments.characterDefinitionTable No Same reasoning and citations as InsertSegments.characterDefinitionTable: HCLoader always builds exactly one CharacterDefinitionTable (HCLoader.cs:204,2742) so a per-instance override to a different table can never carry a meaningful value. +interface-attribute SimpleContext.naturalClass Yes HCLoader.cs:2745-2786 (TryLoadSimpleContext, both overloads) +interface-attribute Slot.morphologicalRules Yes HCLoader.cs:1702-1731 (LoadAffixTemplate slot/rule assembly) +interface-attribute StemName.partsOfSpeech Yes HCLoader.cs:206-224 (LoadLanguage, StemName regions) +interface-attribute Stratum.characterDefinitionTable Yes HCLoader.cs:227-233 (default strata); HCLoader.cs:374 (CreateStrata, custom strata) +interface-attribute Stratum.morphologicalRules Yes HCLoader.cs:237,246,250 (compounding rules); HCLoader.cs:290-292,916-923 (AddMorphologicalRule) +interface-attribute Stratum.phonologicalRules Yes HCLoader.cs:314-333 +interface-attribute SymbolicFeature.defaultSymbol No HCLoader.cs:2650-2667 (LoadFeatureSystem) never sets a default value on any SymbolicFeature it builds. The engine property is SymbolicFeature.DefaultSymbolID/DefaultValue (engine repo FeatureModel/SymbolicFeature.cs:34-36), read by XmlLanguageLoader.cs:644 -- so this is a FieldWorks-specific gap, not dead schema. Searched HCLoader.cs for: Default, DefaultSymbol, DefaultValue -- only unrelated hits (writing-system/inflection-class/compounding defaults). +interface-attribute VariableFeature.phonologicalFeature Yes HCLoader.cs:2765-2773 (GetVariables) Same runtime-collapse caveat as AlphaVariable.variableFeature -- no 'VariableFeature' class exists in the engine's runtime object model (grep-confirmed), so this is evaluated via the equivalent runtime construct HCLoader actually builds. diff --git a/conformance/fixtures.csv b/conformance/fixtures.csv new file mode 100644 index 000000000..f9e7043d7 --- /dev/null +++ b/conformance/fixtures.csv @@ -0,0 +1,26 @@ +directory,category,grammar_name,exercises +edge-cases/bistratal-overlapping-segment-representation,edge-cases,BistratalOverlappingSegmentRepresentation,"CharacterDefinitionTable: more than one table, one per stratum" +edge-cases/deep-optional-affix-nesting,edge-cases,PathologicalDeepOptionalAffixNesting,Affix template slots (obligatory/disjunctive/ordering) +edge-cases/diacritic-segments,edge-cases,LatinDiacriticProbe,Affix template slots (obligatory/disjunctive/ordering);AffixProcessRule: prefix/suffix/circumfix/infix;Boundary markers (CharacterDefinitionTable);MorphologicalOutputAction: CopyFromInput/InsertSegments;NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +edge-cases/disjunctive-recheck,edge-cases,DisjunctiveRecheckProbe,Disjunctive allomorphs / free-fluctuation +edge-cases/free-fluctuating-allomorph-pair,edge-cases,FreeFluctuatingAllomorphPair,Disjunctive allomorphs / free-fluctuation +edge-cases/loader-default-symbol,edge-cases,N2-DefaultSymbol,Boundary markers (CharacterDefinitionTable) +edge-cases/loader-isactive,edge-cases,N1-IsActive,Boundary markers (CharacterDefinitionTable) +edge-cases/loader-pattern-shapes,edge-cases,N3-PatternShapes,Boundary markers (CharacterDefinitionTable);CharacterDefinitionTable pattern shapes: optional group / Kleene star +edge-cases/mpr-gated-exception,edge-cases,Ranavu,RewriteRule direction (Dir): left-to-right +edge-cases/mpr-group-overwrite-without-realizational,edge-cases,MprGroupOverwriteWithoutRealizational,MPR features/groups +edge-cases/process-morphology-in-place-mutation,edge-cases,ProcessMorphologyInPlaceMutation,MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext +edge-cases/right-to-left-anchor-environment,edge-cases,RightToLeftAnchorEnvironment,RewriteRule direction (Dir): right-to-left +edge-cases/simultaneous-epenthesis-cascade,edge-cases,IterativeEpenthesisCascadeProbe,RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +edge-cases/stem-name-restricted-root-allomorph,edge-cases,StemNameRestrictedRootAllomorph,Stem names +edge-cases/strrep-identity,edge-cases,StrRepIdentityProbe,NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision +edge-cases/subrule-morphosyntactic-gating,edge-cases,SubruleMorphosyntacticGating,RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level +edge-cases/truncate-morphotactic,edge-cases,TruncateRulesProbe,AffixProcessRule: subtraction/truncation +languages/fusional-realizational-morphology,languages,FusionalRealizationalMorphology,AffixProcessRule: prefix/suffix/circumfix/infix;CompoundingRule;CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features);MPR features/groups;MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext;RealizationalAffixProcessRule;Stem names +languages/metathesis-phase-isolation,languages,MetathesisPhaseIsolation,AffixProcessRule: prefix/suffix/circumfix/infix;AffixProcessRule: reduplication (ReduplicationHint);AffixProcessRule: subtraction/truncation;Boundary markers (CharacterDefinitionTable);MetathesisRule;MorphologicalOutputAction: CopyFromInput/InsertSegments;RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) +languages/polysynthetic-stratal-derivation-chain,languages,PolysyntheticStratalDerivationChain,AffixProcessRule: prefix/suffix/circumfix/infix;Boundary markers (CharacterDefinitionTable);CompoundingRule;Guesser/LexicalGuess;RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge);Stratum (Linear/Unordered rule order) +languages/prefixal-discontinuous-slot-dependency,languages,PrefixalDiscontinuousSlotDependency,Affix template slots (obligatory/disjunctive/ordering) +languages/suffixing-evidential-adjacency-chain,languages,SuffixingEvidentialAdjacencyChain,Affix template slots (obligatory/disjunctive/ordering);Disjunctive allomorphs / free-fluctuation;MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule +languages/suffixing-extension-slot-ordering,languages,SuffixingExtensionSlotOrdering,Affix template slots (obligatory/disjunctive/ordering);AffixProcessRule: reduplication (ReduplicationHint);MPR features/groups;Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable);RealizationalAffixProcessRule;RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge);Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) +languages/suffixing-vowel-harmony,languages,SuffixingVowelHarmony,Affix template slots (obligatory/disjunctive/ordering);AffixProcessRule: prefix/suffix/circumfix/infix;Alpha-variable phonological environments (VariableFeature/AlphaVariables);Boundary markers (CharacterDefinitionTable);NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision;RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge);RewriteRule Simultaneous +languages/templatic-root-modification,languages,TemplaticRootModification,MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule;MorphologicalOutputAction: CopyFromInput/InsertSegments;MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext;RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge);RewriteRule Simultaneous;Stem names diff --git a/conformance/fold-in-candidates.tsv b/conformance/fold-in-candidates.tsv new file mode 100644 index 000000000..7b1efdf23 --- /dev/null +++ b/conformance/fold-in-candidates.tsv @@ -0,0 +1,103 @@ +# GENERATED by hc-conformance --write-coverage-traceability. Obligations a language- +# family grammar could pick up by growing an existing fixture, keyed on WITNESS (a real +# word-level counterfactual delta) never mere presence -- see FoldInCategory's own doc +# comments for exactly what each category claims and does not claim. +# EdgeCaseOnly only a fabricated edge case witnesses this; folding +# it in needs new grammar content +# PresentInLanguageGrammarAlready surface layer only: a language grammar already +# structurally contains it; new WORDS may be enough +# NeverWitnessed interface layer only: present somewhere, witnessed +# nowhere -- not a fold-in target, a named gap +layer obligation category detail +Surface dtd:element/AssignedFootFeatures PresentInLanguageGrammarAlready recorded best evidence: edge-cases/compounding-breadth; also structurally present in a languages/* grammar +Surface dtd:element/ExcludedEnvironments EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:element/HeadRequiredFootFeatures EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:element/HeadRequiredHeadFeatures EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:element/NonHeadRequiredFootFeatures EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:element/NonHeadRequiredHeadFeatures EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:element/PhoneticSequence PresentInLanguageGrammarAlready recorded best evidence: edge-cases/alpha-variable-name-collision; also structurally present in a languages/* grammar +Surface dtd:element/RequiredFootFeatures PresentInLanguageGrammarAlready recorded best evidence: edge-cases/feature-gating-breadth; also structurally present in a languages/* grammar +Surface dtd:element/RequiredHeadFeatures PresentInLanguageGrammarAlready recorded best evidence: edge-cases/feature-gating-breadth; also structurally present in a languages/* grammar +Surface dtd:element/Segments EdgeCaseOnly recorded best evidence: edge-cases/strrep-identity; no languages/* grammar contains this surface at all +Surface dtd:element/SimpleContext PresentInLanguageGrammarAlready recorded best evidence: edge-cases/alpha-variable-name-collision; also structurally present in a languages/* grammar +Surface dtd:enum/AffixTemplate/final/false EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AffixTemplate/final/true EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AffixTemplate/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AffixTemplate/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Allomorph/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Allomorph/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Allomorph/isBound/false EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Allomorph/isBound/true EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToLeft EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToRight EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToLeft EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToRight EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AllomorphCoOccurrenceRule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AllomorphCoOccurrenceRule/type/require EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/AlphaVariable/polarity/minus EdgeCaseOnly recorded best evidence: edge-cases/alpha-variable-name-collision; no languages/* grammar contains this surface at all +Surface dtd:enum/AlphaVariable/polarity/plus PresentInLanguageGrammarAlready recorded best evidence: edge-cases/alpha-variable-name-collision; also structurally present in a languages/* grammar +Surface dtd:enum/BoundaryDefinition/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/CharacterDefinitionTable/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/ComplexFeature/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/CompoundingRule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/CompoundingRule/multipleApplication/0 EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/CompoundingSubrule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/compounding-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Family/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/FeatureNaturalClass/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/FeatureValue/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/LexicalEntry/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/LexicalEntry/partial/false EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/LexicalEntry/partial/true EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MetathesisRule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MetathesisRule/multipleApplicationOrder/rightToLeftIterative EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphemeCoOccurrenceRule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/append EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalRule/blockable/false EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalRule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalRule/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalRule/multipleApplication/0 EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalRule/multipleApplication/2 EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalRule/partial/true EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/MorphologicalSubrule/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/PhoneticTemplate/finalBoundaryCondition/true PresentInLanguageGrammarAlready recorded best evidence: edge-cases/right-to-left-anchor-environment; also structurally present in a languages/* grammar +Surface dtd:enum/PhonologicalRule/multipleApplicationOrder/rightToLeftIterative EdgeCaseOnly recorded best evidence: edge-cases/right-to-left-anchor-environment; no languages/* grammar contains this surface at all +Surface dtd:enum/PhonologicalSubrule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/RealizationalRule/blockable/false EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/RealizationalRule/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/morphotactic-attribute-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/SegmentDefinition/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/SegmentNaturalClass/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Slot/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Slot/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/Stratum/isActive/yes EdgeCaseOnly recorded best evidence: edge-cases/loader-isactive-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/SymbolicFeature/isActive/no EdgeCaseOnly recorded best evidence: edge-cases/feature-system-breadth; no languages/* grammar contains this surface at all +Surface dtd:enum/VariableFeature/name/%CE%B1 PresentInLanguageGrammarAlready recorded best evidence: edge-cases/alpha-variable-name-collision; also structurally present in a languages/* grammar +Surface dtd:enum/VariableFeature/name/%CE%B2 EdgeCaseOnly recorded best evidence: edge-cases/alpha-variable-name-collision; no languages/* grammar contains this surface at all +Interface AllomorphCoOccurrenceRule.otherAllomorphs NeverWitnessed present in 2 fixture(s), witnessed by none +Interface AllomorphCoOccurrenceRule.primaryAllomorph NeverWitnessed present in 2 fixture(s), witnessed by none +Interface AlphaVariable.variableFeature NeverWitnessed present in 3 fixture(s), witnessed by none +Interface BoundaryMarker.boundary NeverWitnessed present in 1 fixture(s), witnessed by none +Interface CompoundingRule.nonHeadPartsOfSpeech NeverWitnessed present in 3 fixture(s), witnessed by none +Interface CompoundingRule.outputObligatoryFeatures NeverWitnessed present in 1 fixture(s), witnessed by none +Interface CompoundingRule.outputPartOfSpeech EdgeCaseOnly witnessed only by: edge-cases/compounding-breadth +Interface CopyFromInput.index NeverWitnessed present in 24 fixture(s), witnessed by none +Interface FeatureValue.feature NeverWitnessed present in 23 fixture(s), witnessed by none +Interface FeatureValue.symbolValues NeverWitnessed present in 23 fixture(s), witnessed by none +Interface HeadMorphologicalInput.excludedMPRFeatures NeverWitnessed present in 1 fixture(s), witnessed by none +Interface HeadMorphologicalInput.requiredMPRFeatures NeverWitnessed present in 1 fixture(s), witnessed by none +Interface MetathesisRule.leftSwitch NeverWitnessed present in 3 fixture(s), witnessed by none +Interface MetathesisRule.rightSwitch NeverWitnessed present in 3 fixture(s), witnessed by none +Interface ModifyFromInput.index NeverWitnessed present in 3 fixture(s), witnessed by none +Interface MorphemeCoOccurrenceRule.otherMorphemes NeverWitnessed present in 3 fixture(s), witnessed by none +Interface MorphemeCoOccurrenceRule.primaryMorpheme NeverWitnessed present in 3 fixture(s), witnessed by none +Interface MorphologicalInput.excludedMPRFeatures EdgeCaseOnly witnessed only by: edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception +Interface MorphologicalPhonologicalRuleFeatureGroup.features NeverWitnessed present in 5 fixture(s), witnessed by none +Interface MorphologicalRule.outputObligatoryFeatures NeverWitnessed present in 1 fixture(s), witnessed by none +Interface Segment.segment NeverWitnessed present in 17 fixture(s), witnessed by none +Interface SimpleContext.naturalClass NeverWitnessed present in 30 fixture(s), witnessed by none +Interface Slot.morphologicalRules NeverWitnessed present in 8 fixture(s), witnessed by none +Interface StemName.partsOfSpeech NeverWitnessed present in 4 fixture(s), witnessed by none +Interface Stratum.characterDefinitionTable NeverWitnessed present in 33 fixture(s), witnessed by none +Interface SymbolicFeature.defaultSymbol NeverWitnessed present in 1 fixture(s), witnessed by none +Interface VariableFeature.phonologicalFeature NeverWitnessed present in 3 fixture(s), witnessed by none diff --git a/conformance/gate-obligations.tsv b/conformance/gate-obligations.tsv new file mode 100644 index 000000000..5cb596588 --- /dev/null +++ b/conformance/gate-obligations.tsv @@ -0,0 +1,57 @@ +# GENERATED by hc-conformance --write-gate-obligations. One row per (gate, arm) pair, gate +# ranging over all 23 SIL.Machine.Morphology.HermitCrab.FailureReason members (excluding None) +# and arm in {Blocked, Control} -- the two arms MC/DC demands for each of the engine's own +# decision points, as opposed to conformance/dataflow-obligations.tsv's DTD-attribute-pair +# denominator (kept, not superseded -- see conformance/docs/how-it-is-computed.md). xml_reachable +# and flex_producible are the two layer verdicts a gate must clear to be worth_covering; +# status is Evidenced only for a same-word severance flip whose baseline trace names the gate +# directly (Blocked) or a same-fixture rule-id match proving the gated rule fires successfully +# elsewhere (Control); evidence always names which layer or mechanism blocks an unevidenced cell +# rather than collapsing to a bare "Unknown". +gate arm xml_reachable flex_producible worth_covering status fixture word evidence +AllomorphCoOccurrenceRules Blocked Yes Yes Yes NotEvidenced - - no severance of {AllomorphCoOccurrenceRule.primaryAllomorph} across {edge-cases/morphotactic-attribute-breadth, languages/suffixing-evidential-adjacency-chain} produced a same-word fail-to-pass flip whose baseline trace also names AllomorphCoOccurrenceRules -- the gate may only fire as noise against a candidate unrelated to the word's final result (see FailureRuleAttributor's own doc comment) +AllomorphCoOccurrenceRules Control Yes Yes Yes NotEvidenced - - Blocked arm unevidenced; Control arm requires a confirmed blocking instance to identify which rule to check +BoundRoot Blocked Yes Yes Yes Evidenced edge-cases/morphotactic-attribute-breadth kur severing Allomorph.isBound in edge-cases/morphotactic-attribute-breadth flips 'kur' from ok::- to ok::KUL|kur (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'kur''s own baseline trace names BoundRoot directly (this ledger's own traced sweep) +BoundRoot Control Yes Yes Yes NotEvidenced - - the Allomorph instance carrying isBound in edge-cases/morphotactic-attribute-breadth has no rule-element ancestor GrammarRuleIndex can resolve (conformance/docs/severance-mechanics.md) -- it sits outside any rule, so no rule id exists to attribute a Control arm to +DisjunctiveAllomorph Blocked Yes Yes Yes NotEvidenced - - xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section) +DisjunctiveAllomorph Control Yes Yes Yes NotEvidenced - - xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section) +Environments Blocked Yes Yes Yes NotEvidenced - - xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section) +Environments Control Yes Yes Yes NotEvidenced - - xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section) +ExcludedMprFeatures Blocked Yes Yes Yes Evidenced edge-cases/morphotactic-attribute-breadth topdori severing MorphologicalInput.excludedMPRFeatures in edge-cases/morphotactic-attribute-breadth flips 'topdori' from ok::- to ok::TOP+CONFEREXCL+EXCLREADER|topdori (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'topdori''s own baseline trace names ExcludedMprFeatures directly (this ledger's own traced sweep) +ExcludedMprFeatures Control Yes Yes Yes Evidenced edge-cases/morphotactic-attribute-breadth topri rule 'mrExclReader' (MorphologicalInput) also fires in a successful parse of 'topri' in edge-cases/morphotactic-attribute-breadth (TraceRuleAttributor over this ledger's own baseline sweep), proving it can apply outside the blocked condition +ExcludedStemName Blocked Yes Yes Yes Evidenced languages/fusional-realizational-morphology muno severing Allomorph.stemName in languages/fusional-realizational-morphology flips 'muno' from ok::- to ok::STEM+P1|muno (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'muno''s own baseline trace names ExcludedStemName directly (this ledger's own traced sweep) +ExcludedStemName Control Yes Yes Yes NotEvidenced - - the Allomorph instance carrying stemName in languages/fusional-realizational-morphology has no rule-element ancestor GrammarRuleIndex can resolve (conformance/docs/severance-mechanics.md) -- it sits outside any rule, so no rule id exists to attribute a Control arm to +HeadPattern Blocked Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +HeadPattern Control Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +HeadProdRestrictMprFeatures Blocked Yes Yes Yes Evidenced languages/fusional-realizational-morphology seclav severing CompoundingRule.headProdRestrictionsMprFeatures in languages/fusional-realizational-morphology flips 'seclav' from ok::- to ok::SEC+LAV|sec+?lav (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'seclav''s own baseline trace names HeadProdRestrictMprFeatures directly (this ledger's own traced sweep) +HeadProdRestrictMprFeatures Control Yes Yes Yes Evidenced languages/fusional-realizational-morphology mitlav rule 'mrCompoundConstrained' (CompoundingRule) also fires in a successful parse of 'mitlav' in languages/fusional-realizational-morphology (TraceRuleAttributor over this ledger's own baseline sweep), proving it can apply outside the blocked condition +HeadRequiredSyntacticFeatureStruct Blocked Yes Yes Yes Evidenced languages/polysynthetic-stratal-derivation-chain silaaku severing CompoundingRule.headPartsOfSpeech in languages/polysynthetic-stratal-derivation-chain flips 'silaaku' from ok::- to ok::SILA+AKU|sila+?aku;SILA+AKU|sila+?aku (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'silaaku''s own baseline trace names HeadRequiredSyntacticFeatureStruct directly (this ledger's own traced sweep) +HeadRequiredSyntacticFeatureStruct Control Yes Yes Yes Evidenced languages/polysynthetic-stratal-derivation-chain akutat rule 'mrCompoundHN' (CompoundingRule) also fires in a successful parse of 'akutat' in languages/polysynthetic-stratal-derivation-chain (TraceRuleAttributor over this ledger's own baseline sweep), proving it can apply outside the blocked condition +MaxApplicationCount Blocked Yes Yes Yes NotEvidenced - - no severance of {MorphologicalRule.multipleApplication, CompoundingRule.multipleApplication} across {edge-cases/feature-gating-breadth, languages/fusional-realizational-morphology, languages/suffixing-extension-slot-ordering} produced a same-word fail-to-pass flip whose baseline trace also names MaxApplicationCount -- the gate may only fire as noise against a candidate unrelated to the word's final result (see FailureRuleAttributor's own doc comment) +MaxApplicationCount Control Yes Yes Yes NotEvidenced - - Blocked arm unevidenced; Control arm requires a confirmed blocking instance to identify which rule to check +MorphemeCoOccurrenceRules Blocked Yes Yes Yes NotEvidenced - - no severance of {MorphemeCoOccurrenceRule.primaryMorpheme} across {languages/suffixing-evidential-adjacency-chain, languages/templatic-root-modification} produced a same-word fail-to-pass flip whose baseline trace also names MorphemeCoOccurrenceRules -- the gate may only fire as noise against a candidate unrelated to the word's final result (see FailureRuleAttributor's own doc comment) +MorphemeCoOccurrenceRules Control Yes Yes Yes NotEvidenced - - Blocked arm unevidenced; Control arm requires a confirmed blocking instance to identify which rule to check +NonHeadPattern Blocked Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonHeadPattern Control Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonHeadProdRestrictMprFeatures Blocked Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonHeadProdRestrictMprFeatures Control Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonHeadRequiredSyntacticFeatureStruct Blocked Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonHeadRequiredSyntacticFeatureStruct Control Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonPartialRuleProhibitedAfterFinalTemplate Blocked Yes Yes Yes NotEvidenced - - no severance of {AffixTemplate.final, MorphologicalRule.partial} across {edge-cases/disjunctive-recheck, edge-cases/free-fluctuating-allomorph-pair, edge-cases/mpr-gated-exception, edge-cases/mpr-overwrite-order-dependence, edge-cases/process-morphology-in-place-mutation, edge-cases/stem-name-restricted-root-allomorph, edge-cases/strrep-identity, edge-cases/truncate-morphotactic, languages/fusional-realizational-morphology, languages/metathesis-phase-isolation, languages/polysynthetic-stratal-derivation-chain, languages/suffixing-vowel-harmony, languages/templatic-root-modification} produced a same-word fail-to-pass flip whose baseline trace also names NonPartialRuleProhibitedAfterFinalTemplate -- the gate may only fire as noise against a candidate unrelated to the word's final result (see FailureRuleAttributor's own doc comment) +NonPartialRuleProhibitedAfterFinalTemplate Control Yes Yes Yes NotEvidenced - - Blocked arm unevidenced; Control arm requires a confirmed blocking instance to identify which rule to check +NonPartialRuleRequiredAfterNonFinalTemplate Blocked Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +NonPartialRuleRequiredAfterNonFinalTemplate Control Yes Yes Yes NotEvidenced - - gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm +ObligatorySyntacticFeatures Blocked Yes No No NotEvidenced - - not worth covering: flex_producible=No -- FieldWorks' HCLoader never sets AffixProcessRule/CompoundingRule.ObligatorySyntacticFeatures for any construct FLEx exposes -- conformance/fieldworks-producibility.tsv +ObligatorySyntacticFeatures Control Yes No No NotEvidenced - - not worth covering: flex_producible=No -- FieldWorks' HCLoader never sets AffixProcessRule/CompoundingRule.ObligatorySyntacticFeatures for any construct FLEx exposes -- conformance/fieldworks-producibility.tsv +PartialParse Blocked Yes Yes Yes Evidenced edge-cases/morphotactic-attribute-breadth kulpu severing AffixTemplate.final in edge-cases/morphotactic-attribute-breadth flips 'kulpu' from ok::- to ok::KUL+NF|kulpu (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'kulpu''s own baseline trace names PartialParse directly (this ledger's own traced sweep) +PartialParse Control Yes Yes Yes NotEvidenced - - the AffixTemplate instance carrying final in edge-cases/morphotactic-attribute-breadth has no rule-element ancestor GrammarRuleIndex can resolve (conformance/docs/severance-mechanics.md) -- it sits outside any rule, so no rule id exists to attribute a Control arm to +Pattern Blocked Yes Yes Yes NotEvidenced - - xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section) +Pattern Control Yes Yes Yes NotEvidenced - - xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section) +RequiredMprFeatures Blocked Yes Yes Yes Evidenced edge-cases/mpr-group-overwrite-without-realizational wudofq severing MorphologicalInput.requiredMPRFeatures in edge-cases/mpr-group-overwrite-without-realizational flips 'wudofq' from ok::- to ok::THEMEB+THEMEA+DOF+ENDC|wudofq (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'wudofq''s own baseline trace names RequiredMprFeatures directly (this ledger's own traced sweep) +RequiredMprFeatures Control Yes Yes Yes Evidenced edge-cases/mpr-group-overwrite-without-realizational udofq rule 'mrEndC' (MorphologicalInput) also fires in a successful parse of 'udofq' in edge-cases/mpr-group-overwrite-without-realizational (TraceRuleAttributor over this ledger's own baseline sweep), proving it can apply outside the blocked condition +RequiredStemName Blocked Yes Yes Yes Evidenced edge-cases/stem-name-restricted-root-allomorph kap severing Allomorph.stemName in edge-cases/stem-name-restricted-root-allomorph flips 'kap' from ok::- to ok::ROOT|kap (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'kap''s own baseline trace names RequiredStemName directly (this ledger's own traced sweep) +RequiredStemName Control Yes Yes Yes NotEvidenced - - the Allomorph instance carrying stemName in edge-cases/stem-name-restricted-root-allomorph has no rule-element ancestor GrammarRuleIndex can resolve (conformance/docs/severance-mechanics.md) -- it sits outside any rule, so no rule id exists to attribute a Control arm to +RequiredSyntacticFeatureStruct Blocked Yes Yes Yes Evidenced languages/metathesis-phase-isolation idil severing PhonologicalSubrule.requiredPartsOfSpeech in languages/metathesis-phase-isolation flips 'idil' from ok::- to ok::ADIL|idil (conformance/interface-witness.tsv or a fresh equivalent severance run), and 'idil''s own baseline trace names RequiredSyntacticFeatureStruct directly (this ledger's own traced sweep) +RequiredSyntacticFeatureStruct Control Yes Yes Yes Evidenced languages/metathesis-phase-isolation katibɯd rule 'prNonContig' (PhonologicalSubrule) also fires in a successful parse of 'katibɯd' in languages/metathesis-phase-isolation (TraceRuleAttributor over this ledger's own baseline sweep), proving it can apply outside the blocked condition +SurfaceFormMismatch Blocked No Yes No NotEvidenced - - not worth covering: xml_reachable=No -- pure engine-internal reconstruction check (Morpher.cs's confirming-synthesis IsMatch) with no grammar attribute or element input at all -- see EngineGateInventoryLedger.DtdAttributes +SurfaceFormMismatch Control No Yes No NotEvidenced - - not worth covering: xml_reachable=No -- pure engine-internal reconstruction check (Morpher.cs's confirming-synthesis IsMatch) with no grammar attribute or element input at all -- see EngineGateInventoryLedger.DtdAttributes diff --git a/conformance/generated/hc-conformance-manifest.v1.json b/conformance/generated/hc-conformance-manifest.v1.json new file mode 100644 index 000000000..d8a514639 --- /dev/null +++ b/conformance/generated/hc-conformance-manifest.v1.json @@ -0,0 +1 @@ +{"dtdPath":"conformance/HermitCrabInput.dtd","dtdSha256":"0818ce23d3fb76ed0374d68a80bb6e0fe9a331c22f13be3e005749c76873cb7f","fixtures":[{"caseCount":2,"category":"edge-case","displayLanguage":"AlphaVariableNameCollision","expectedCrash":false,"fixtureId":"edge-cases/alpha-variable-name-collision","grammarPath":"conformance/edge-cases/alpha-variable-name-collision/grammar.xml","grammarSha256":"fd80ccd8826850e09afd04014e0cbed94fcf3cbaf4d47bb2b13922a4aba909b4","wordsPath":"conformance/edge-cases/alpha-variable-name-collision/words.yaml","wordsSha256":"3fe298850f6e0d338bfd1b15c324313b29d363cc316d04c3a33c7f85e51f8c7a"},{"caseCount":5,"category":"edge-case","displayLanguage":"BistratalOverlappingSegmentRepresentation","expectedCrash":false,"fixtureId":"edge-cases/bistratal-overlapping-segment-representation","grammarPath":"conformance/edge-cases/bistratal-overlapping-segment-representation/grammar.xml","grammarSha256":"b593e480ed7baa4851a1a784511377713fffc7a5036161a86c6f6df716a0d843","wordsPath":"conformance/edge-cases/bistratal-overlapping-segment-representation/words.yaml","wordsSha256":"ddd410ae53cead5343aec9f606709b761893f90c5a8c1ba40ec82d600ea0ceee"},{"caseCount":11,"category":"edge-case","displayLanguage":"CompoundingBreadth","expectedCrash":false,"fixtureId":"edge-cases/compounding-breadth","grammarPath":"conformance/edge-cases/compounding-breadth/grammar.xml","grammarSha256":"2d18f61bdda8a3d4d62185a13afafbaaef359c0508ce3fd710c7791c9279cb39","wordsPath":"conformance/edge-cases/compounding-breadth/words.yaml","wordsSha256":"2097d774c4746496a1a1ec3815438cfe44ffc2745b1df25b3f3040477ca4befa"},{"caseCount":3,"category":"edge-case","displayLanguage":"PathologicalDeepOptionalAffixNesting","expectedCrash":false,"fixtureId":"edge-cases/deep-optional-affix-nesting","grammarPath":"conformance/edge-cases/deep-optional-affix-nesting/grammar.xml","grammarSha256":"ca08b180c5eccbee358c0d3609df3d0b43130b13c0d8be5900235f4f69c63112","wordsPath":"conformance/edge-cases/deep-optional-affix-nesting/words.yaml","wordsSha256":"c0caa1bf06ad91878a3f833fdedcdc2eacdd04e74ca5a328fef9598d92ee248c"},{"caseCount":13,"category":"edge-case","displayLanguage":"LatinDiacriticProbe","expectedCrash":false,"fixtureId":"edge-cases/diacritic-segments","grammarPath":"conformance/edge-cases/diacritic-segments/grammar.xml","grammarSha256":"bf41b716eb7ea5f6e12c09432bead513eb279dc32a1dfa6a369f56a2568795c1","wordsPath":"conformance/edge-cases/diacritic-segments/words.yaml","wordsSha256":"b07552b355b197be00ae64626c5ee20e64160c99b50311d4a1a4dc79eb6ab6d9"},{"caseCount":12,"category":"edge-case","displayLanguage":"DisjunctiveRecheckProbe","expectedCrash":false,"fixtureId":"edge-cases/disjunctive-recheck","grammarPath":"conformance/edge-cases/disjunctive-recheck/grammar.xml","grammarSha256":"2aa29599b8ec8fcc5b9eaf557985c1810b89eef078b8a5d3ca6e2c332d65db09","wordsPath":"conformance/edge-cases/disjunctive-recheck/words.yaml","wordsSha256":"d004dac7aab0d8c25854a2b3bd6b3da0e229b85322400d5aeef79f39b86b4e0b"},{"caseCount":15,"category":"edge-case","displayLanguage":"FeatureGatingBreadth","expectedCrash":false,"fixtureId":"edge-cases/feature-gating-breadth","grammarPath":"conformance/edge-cases/feature-gating-breadth/grammar.xml","grammarSha256":"867f163d50fa6056d7f31d538d4ee4c28463b7e43cf03498efbb888a949946d4","wordsPath":"conformance/edge-cases/feature-gating-breadth/words.yaml","wordsSha256":"0b13db69d02c51a8023cb60e522ae9a58f218cee376241c3b996e828e6938d00"},{"caseCount":18,"category":"edge-case","displayLanguage":"FeatureSystemBreadth","expectedCrash":false,"fixtureId":"edge-cases/feature-system-breadth","grammarPath":"conformance/edge-cases/feature-system-breadth/grammar.xml","grammarSha256":"e06aa1d734113af7b4f3d76d664c535250f1d25fcdcdb48e193c3df206caf0fe","wordsPath":"conformance/edge-cases/feature-system-breadth/words.yaml","wordsSha256":"406fc0f521aa338ce8472f7e73715bd70d5f6432a39611bbe5f7fe400b47a2c3"},{"caseCount":6,"category":"edge-case","displayLanguage":"FreeFluctuatingAllomorphPair","expectedCrash":false,"fixtureId":"edge-cases/free-fluctuating-allomorph-pair","grammarPath":"conformance/edge-cases/free-fluctuating-allomorph-pair/grammar.xml","grammarSha256":"35168efeadb9ba903c077ec2f750c2be9b41308c4fec2eccfb945937ba1e856f","wordsPath":"conformance/edge-cases/free-fluctuating-allomorph-pair/words.yaml","wordsSha256":"7e49226a39e573821f2f377efd771773da06dc57951615dea12acc8b0c252fe6"},{"caseCount":2,"category":"edge-case","displayLanguage":"N2-DefaultSymbol","expectedCrash":false,"fixtureId":"edge-cases/loader-default-symbol","grammarPath":"conformance/edge-cases/loader-default-symbol/grammar.xml","grammarSha256":"28ef4ed9b247d4307d5d982fc5a2711b387de6b75ab93c2d2d678c02fc5b1b16","wordsPath":"conformance/edge-cases/loader-default-symbol/words.yaml","wordsSha256":"00bed83db4d876d50dc683e9f98ae9226fc5fd13b534e18c4892704a3a722dad"},{"caseCount":2,"category":"edge-case","displayLanguage":"N1-IsActive","expectedCrash":false,"fixtureId":"edge-cases/loader-isactive","grammarPath":"conformance/edge-cases/loader-isactive/grammar.xml","grammarSha256":"d2cfcadcaa81e38f254e6674f40d50cc71d75cdbb6e472e8b8f76889f6bd231c","wordsPath":"conformance/edge-cases/loader-isactive/words.yaml","wordsSha256":"31361bd55e718210b626d62b71cbbb2ea22e808cd3b1c9f91e6a13da1d4c2a61"},{"caseCount":18,"category":"edge-case","displayLanguage":"IsActiveBreadth","expectedCrash":false,"fixtureId":"edge-cases/loader-isactive-breadth","grammarPath":"conformance/edge-cases/loader-isactive-breadth/grammar.xml","grammarSha256":"a1f43bc32ab463e783cabfffd5a5bd52dea15538c1830a7580d5ef02e17c1b79","wordsPath":"conformance/edge-cases/loader-isactive-breadth/words.yaml","wordsSha256":"0f293dc89d58f98116ebf4fa978d96872696d60188c54478cdfd3c7aed231d2f"},{"caseCount":4,"category":"edge-case","displayLanguage":"N3-PatternShapes","expectedCrash":false,"fixtureId":"edge-cases/loader-pattern-shapes","grammarPath":"conformance/edge-cases/loader-pattern-shapes/grammar.xml","grammarSha256":"e167d4285ad1ed1b149266d89f61154fb7b70cfbe3f4bf597fc297a42f0ef4d0","wordsPath":"conformance/edge-cases/loader-pattern-shapes/words.yaml","wordsSha256":"8a2b888c180c65bd72d16647e514e5e9d29f4bfc50d5c4f2a88c4dffdf4bcda6"},{"caseCount":1,"category":"edge-case","displayLanguage":"MetathesisComparisonCrash","expectedCrash":false,"fixtureId":"edge-cases/metathesis-comparison-crash","grammarPath":"conformance/edge-cases/metathesis-comparison-crash/grammar.xml","grammarSha256":"454a501018692412fb63bdd1a6a1c02c20db51de8ca795602953fbdfb5c5c03b","wordsPath":"conformance/edge-cases/metathesis-comparison-crash/words.yaml","wordsSha256":"57b95b0b208ee4aa5f490df2cf998acb3be024ef850d9e77e0656a154848d21d"},{"caseCount":33,"category":"edge-case","displayLanguage":"MorphotacticAttributeBreadth","expectedCrash":false,"fixtureId":"edge-cases/morphotactic-attribute-breadth","grammarPath":"conformance/edge-cases/morphotactic-attribute-breadth/grammar.xml","grammarSha256":"575cc7ad0a077623bd22a2479262a205fa0173a285ac5f94af52bb7ee0c28f59","wordsPath":"conformance/edge-cases/morphotactic-attribute-breadth/words.yaml","wordsSha256":"93706c048e74838190c88893f8bcaf70f1b524bccbd70bf03c2b95171743d1d3"},{"caseCount":12,"category":"edge-case","displayLanguage":"Ranavu","expectedCrash":false,"fixtureId":"edge-cases/mpr-gated-exception","grammarPath":"conformance/edge-cases/mpr-gated-exception/grammar.xml","grammarSha256":"788a893f12b86889434e7167c91eda819fd0d589fb46d3664bd2553e1f799272","wordsPath":"conformance/edge-cases/mpr-gated-exception/words.yaml","wordsSha256":"a220f78d1d89939c357cee51bb4f6cc445d1ca6fb6c191bd03695b6b8f1f82e2"},{"caseCount":5,"category":"edge-case","displayLanguage":"MprGroupOverwriteWithoutRealizational","expectedCrash":false,"fixtureId":"edge-cases/mpr-group-overwrite-without-realizational","grammarPath":"conformance/edge-cases/mpr-group-overwrite-without-realizational/grammar.xml","grammarSha256":"3aff3be8f218a659ae165fbe9ad438ba0ec68c89d50e42ef15e34001f2c9cc89","wordsPath":"conformance/edge-cases/mpr-group-overwrite-without-realizational/words.yaml","wordsSha256":"306bce641fdcd64ecc69c1bb371ac0a29c1557f79ccb43e2af56b0c73e9d83f9"},{"caseCount":10,"category":"edge-case","displayLanguage":"MprOverwriteOrderDependence","expectedCrash":false,"fixtureId":"edge-cases/mpr-overwrite-order-dependence","grammarPath":"conformance/edge-cases/mpr-overwrite-order-dependence/grammar.xml","grammarSha256":"c36b60781c3dac707afdf52ce778c7613f700c463bd5e48c8a5afc3be7504a09","wordsPath":"conformance/edge-cases/mpr-overwrite-order-dependence/words.yaml","wordsSha256":"892b970e5ecd540d75d29c085aba03432451126c2c6b456a5b674f00533a98ee"},{"caseCount":3,"category":"edge-case","displayLanguage":"ProcessMorphologyInPlaceMutation","expectedCrash":false,"fixtureId":"edge-cases/process-morphology-in-place-mutation","grammarPath":"conformance/edge-cases/process-morphology-in-place-mutation/grammar.xml","grammarSha256":"6dbc5549f00d8f11f8b476197717769ce0358e029acfee0c4e832dafb2372b54","wordsPath":"conformance/edge-cases/process-morphology-in-place-mutation/words.yaml","wordsSha256":"a3507eee729e9054a3a86c92d35853fa5945b791a2a01f73690496fe6bca84f4"},{"caseCount":9,"category":"edge-case","displayLanguage":"RightToLeftAnchorEnvironment","expectedCrash":false,"fixtureId":"edge-cases/right-to-left-anchor-environment","grammarPath":"conformance/edge-cases/right-to-left-anchor-environment/grammar.xml","grammarSha256":"7d0ae338c34afa224b1eedb274e990f6538ab3539edbec547e3e78a98d40048c","wordsPath":"conformance/edge-cases/right-to-left-anchor-environment/words.yaml","wordsSha256":"c3cea5934da3ffad30bb8db1f93fcfa4e7e65186e977027056b3e37842c57fa1"},{"caseCount":1,"category":"edge-case","displayLanguage":"IterativeEpenthesisCascadeProbe","expectedCrash":true,"fixtureId":"edge-cases/simultaneous-epenthesis-cascade","grammarPath":"conformance/edge-cases/simultaneous-epenthesis-cascade/grammar.xml","grammarSha256":"ae856436476273263c7a0b886cb7403e33bcbeea115422091d89cac77c0a03ad","wordsPath":"conformance/edge-cases/simultaneous-epenthesis-cascade/words.yaml","wordsSha256":"0beaf7604e85d742a95719540051df74cbec8b9de345c8ec68c67f8477687019"},{"caseCount":6,"category":"edge-case","displayLanguage":"StemNameRestrictedRootAllomorph","expectedCrash":false,"fixtureId":"edge-cases/stem-name-restricted-root-allomorph","grammarPath":"conformance/edge-cases/stem-name-restricted-root-allomorph/grammar.xml","grammarSha256":"239b696e43198f865d376b4ec4c04bc7e263e84cde815b04acdac1fc8419b9fa","wordsPath":"conformance/edge-cases/stem-name-restricted-root-allomorph/words.yaml","wordsSha256":"f45b40d7bbee66150c71b8b71d0f453fb550807c0f15f7f083e570d4b53309f5"},{"caseCount":12,"category":"edge-case","displayLanguage":"StrRepIdentityProbe","expectedCrash":false,"fixtureId":"edge-cases/strrep-identity","grammarPath":"conformance/edge-cases/strrep-identity/grammar.xml","grammarSha256":"183f9d19fbb4c9c1de2739d82e266bdebe07ca4d5171c3e3fe2e14237819f9e5","wordsPath":"conformance/edge-cases/strrep-identity/words.yaml","wordsSha256":"8e6f83fb6c2976d567905d672c26d5791f0aa99cc31c48279f99cd9bc985c7d7"},{"caseCount":2,"category":"edge-case","displayLanguage":"SubruleMorphosyntacticGating","expectedCrash":false,"fixtureId":"edge-cases/subrule-morphosyntactic-gating","grammarPath":"conformance/edge-cases/subrule-morphosyntactic-gating/grammar.xml","grammarSha256":"fe28d05d2aaf3f592293374a7caee5d105d85d579b361be82d4ccd1d44be9e9c","wordsPath":"conformance/edge-cases/subrule-morphosyntactic-gating/words.yaml","wordsSha256":"637ca1b0b76ae07cbebb9a1324c8a3bb653aceb42fc22e661f7c12f3a009c1f0"},{"caseCount":9,"category":"edge-case","displayLanguage":"TruncateRulesProbe","expectedCrash":false,"fixtureId":"edge-cases/truncate-morphotactic","grammarPath":"conformance/edge-cases/truncate-morphotactic/grammar.xml","grammarSha256":"f329bdf510656ee3be36d4e9ac3845d04ef71b56eed0c897f5e53de995d08831","wordsPath":"conformance/edge-cases/truncate-morphotactic/words.yaml","wordsSha256":"ee8bb0e263bd24e458609d78cd0e60dc3aee574f1c4856a2386f1772ff21a129"},{"caseCount":63,"category":"language","displayLanguage":"FusionalRealizationalMorphology","expectedCrash":false,"fixtureId":"languages/fusional-realizational-morphology","grammarPath":"conformance/languages/fusional-realizational-morphology/grammar.xml","grammarSha256":"5ce5147091b3cdcb36514ca50826e00798ea65ffb5ebaaf37a591b456fdf6058","wordsPath":"conformance/languages/fusional-realizational-morphology/words.yaml","wordsSha256":"9e0fcb4378adcc749edd970ab9c30807b96f333d05b907f7162f88f7bb3cdd2b"},{"caseCount":20,"category":"language","displayLanguage":"MetathesisPhaseIsolation","expectedCrash":false,"fixtureId":"languages/metathesis-phase-isolation","grammarPath":"conformance/languages/metathesis-phase-isolation/grammar.xml","grammarSha256":"2ccb7a1e98115efff0f3443b98076c52912d7389899a384fe55aa99b03df1301","wordsPath":"conformance/languages/metathesis-phase-isolation/words.yaml","wordsSha256":"19a73ca5022d5ab619cab7006b9956819a91c2a090ca03461e5847bff3341e51"},{"caseCount":24,"category":"language","displayLanguage":"PolysyntheticStratalDerivationChain","expectedCrash":false,"fixtureId":"languages/polysynthetic-stratal-derivation-chain","grammarPath":"conformance/languages/polysynthetic-stratal-derivation-chain/grammar.xml","grammarSha256":"fa1980a60d446daddaf6ddf9de823cbebc0e108e78dfc6c76cadbe0c6195c0dc","wordsPath":"conformance/languages/polysynthetic-stratal-derivation-chain/words.yaml","wordsSha256":"e23f9f41d8ee43e9e4ba16adda0364a635faa54df4b534fa65d5f40751cfa440"},{"caseCount":10,"category":"language","displayLanguage":"PrefixalDiscontinuousSlotDependency","expectedCrash":false,"fixtureId":"languages/prefixal-discontinuous-slot-dependency","grammarPath":"conformance/languages/prefixal-discontinuous-slot-dependency/grammar.xml","grammarSha256":"4b7d72637db8f1d0752607c046aeb16afcaa07418c877696040f883941d88701","wordsPath":"conformance/languages/prefixal-discontinuous-slot-dependency/words.yaml","wordsSha256":"16b37be27b8342c700a91036a0c9794ba6fc7dafb0d0155d1edef962b07d7c22"},{"caseCount":28,"category":"language","displayLanguage":"SuffixingEvidentialAdjacencyChain","expectedCrash":false,"fixtureId":"languages/suffixing-evidential-adjacency-chain","grammarPath":"conformance/languages/suffixing-evidential-adjacency-chain/grammar.xml","grammarSha256":"6330c1b82a000ad7df68684464292a3b1e9938d9c5552c831ed824930f4b34e9","wordsPath":"conformance/languages/suffixing-evidential-adjacency-chain/words.yaml","wordsSha256":"d539bfe2dfa4acaa79c3d7d7500e47ac6db0359387c8d96b4c0762ac9d53bc2b"},{"caseCount":53,"category":"language","displayLanguage":"SuffixingExtensionSlotOrdering","expectedCrash":false,"fixtureId":"languages/suffixing-extension-slot-ordering","grammarPath":"conformance/languages/suffixing-extension-slot-ordering/grammar.xml","grammarSha256":"87a9914c121a58cc289335957e511da7f77bfaada1554b1bb5843a96aa60fb2d","wordsPath":"conformance/languages/suffixing-extension-slot-ordering/words.yaml","wordsSha256":"22352d05c2dcee4012ada8b9c0e9c3190e61eeb20601d3f35164997d3556b52e"},{"caseCount":27,"category":"language","displayLanguage":"SuffixingVowelHarmony","expectedCrash":false,"fixtureId":"languages/suffixing-vowel-harmony","grammarPath":"conformance/languages/suffixing-vowel-harmony/grammar.xml","grammarSha256":"888dd81d11e04aebf6efae76b63849b3a6747ca22e82f7fbf2b07cfa90045223","wordsPath":"conformance/languages/suffixing-vowel-harmony/words.yaml","wordsSha256":"ee8e5a38ab4666fa4fb7c860628a1729af1803dca31612870e03ac3dbe0063a3"},{"caseCount":25,"category":"language","displayLanguage":"TemplaticRootModification","expectedCrash":false,"fixtureId":"languages/templatic-root-modification","grammarPath":"conformance/languages/templatic-root-modification/grammar.xml","grammarSha256":"7fe80608c5ac668196b2ad4ccb2c016e9146701a9c08f65e6393d5a8505b701e","wordsPath":"conformance/languages/templatic-root-modification/words.yaml","wordsSha256":"d7ce20fd435761c7db473526bea9ead1e231e062e24efad803af0df090153b63"}],"formatVersion":"hc-conformance-manifest/v1","grammarFormatVersion":"sil-machine-hermit-crab-input-xml/v1","sourceHash":"0f4038d5425891d670d0423258bd9c180d9bb214152eb73a55bcc490c842963d","wordsAuthoringFormatVersion":"hc-conformance-words/v1"} diff --git a/conformance/grammar-coverage-ledger.tsv b/conformance/grammar-coverage-ledger.tsv new file mode 100644 index 000000000..8286aed15 --- /dev/null +++ b/conformance/grammar-coverage-ledger.tsv @@ -0,0 +1,657 @@ +# GENERATED by hc-conformance --write-coverage-traceability. One row per (fixture, +# obligation) pair this fixture witnesses, joined from three already-checked-in ledgers -- +# never recomputed here, so this file costs no re-parse of its own. layer is Surface +# (semantic-coverage-evidence.tsv), Interface (interface-inventory.tsv + +# interface-witness.tsv), or Construct (construct-claim-corroboration.tsv); the chain/ +# junction layer is out of scope (owned by interaction-chains.tsv's own generator). +# status vocabulary differs per layer -- see GrammarCoverageLedger's *Status methods -- +# but 'witnessed' always means the same thing: a word-level counterfactual delta, never +# mere presence. detail carries the underlying verdict/claim-count for that reason. +fixture layer obligation status detail +edge-cases/alpha-variable-name-collision Surface dtd:element/Allomorph required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Allomorphs required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/AlphaVariable required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/AlphaVariables witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:element/CharacterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/FeatureValue witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:element/HermitCrabInput required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Language required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/LexicalEntries witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:element/LexicalEntry required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/MorphemeId witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:element/Name required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/NaturalClasses required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PartOfSpeech required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PartsOfSpeech required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhoneticInput required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhoneticOutput required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhoneticSequence witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:element/PhoneticShape required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhonologicalFeatureSystem required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhonologicalRule required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhonologicalRuleDefinitions required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhonologicalSubrule required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/PhonologicalSubrules required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Representation required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Representations required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/SegmentDefinition required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/SegmentDefinitions required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/SegmentNaturalClass required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/SimpleContext witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:element/Strata required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Stratum required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Symbol required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/SymbolicFeature required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/Symbols required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/VariableFeature required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:element/VariableFeatures required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Surface dtd:enum/AlphaVariable/polarity/minus witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:enum/AlphaVariable/polarity/plus witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:enum/VariableFeature/name/%CE%B1 witnessed Evidenced +edge-cases/alpha-variable-name-collision Surface dtd:enum/VariableFeature/name/%CE%B2 witnessed Evidenced +edge-cases/alpha-variable-name-collision Interface AlphaVariable.variableFeature required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/alpha-variable-name-collision Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/alpha-variable-name-collision Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/alpha-variable-name-collision Interface VariableFeature.phonologicalFeature required-by-dtd RequiredByDtd +edge-cases/alpha-variable-name-collision Construct Alpha-variable phonological environments (VariableFeature/AlphaVariables) claimed-confirmed 2 claim(s) +edge-cases/bistratal-overlapping-segment-representation Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/bistratal-overlapping-segment-representation Construct CharacterDefinitionTable: more than one table, one per stratum claimed-confirmed 5 claim(s) +edge-cases/compounding-breadth Surface dtd:element/AssignedFootFeatures witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/AssignedHeadFeatures witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/CompoundingRule required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/CompoundingSubrule required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/CompoundingSubrules required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/CopyFromInput witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/FeatureNaturalClass required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/FootFeatures required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/HeadFeatures required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/HeadMorphologicalInput required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/HeadRequiredFootFeatures witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/HeadRequiredHeadFeatures witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/MorphologicalOutput required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/MorphologicalRuleDefinitions required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/NonHeadMorphologicalInput required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Surface dtd:element/NonHeadRequiredFootFeatures witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/NonHeadRequiredHeadFeatures witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:element/OptionalSegmentSequence witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:enum/CompoundingRule/isActive/no witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:enum/CompoundingRule/multipleApplication/0 witnessed Evidenced +edge-cases/compounding-breadth Surface dtd:enum/CompoundingSubrule/isActive/no witnessed Evidenced +edge-cases/compounding-breadth Interface CompoundingRule.headPartsOfSpeech present-but-inert Unobservable +edge-cases/compounding-breadth Interface CompoundingRule.nonHeadPartsOfSpeech present-but-inert Unobservable +edge-cases/compounding-breadth Interface CompoundingRule.outputPartOfSpeech witnessed Evidenced +edge-cases/compounding-breadth Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/compounding-breadth Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/compounding-breadth Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/compounding-breadth Interface MorphologicalRule.requiredPartsOfSpeech witnessed Evidenced +edge-cases/compounding-breadth Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/compounding-breadth Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/compounding-breadth Construct CompoundingRule claimed-confirmed 2 claim(s) +edge-cases/compounding-breadth Construct CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) claimed-confirmed 7 claim(s) +edge-cases/compounding-breadth Construct Element deactivation (isActive) across loader collections claimed-confirmed 2 claim(s) +edge-cases/deep-optional-affix-nesting Interface AffixTemplate.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/deep-optional-affix-nesting Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/deep-optional-affix-nesting Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/deep-optional-affix-nesting Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/deep-optional-affix-nesting Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/deep-optional-affix-nesting Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/deep-optional-affix-nesting Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +edge-cases/deep-optional-affix-nesting Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/deep-optional-affix-nesting Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 2 claim(s) +edge-cases/diacritic-segments Surface dtd:element/AffixTemplate required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:element/InsertSegments witnessed Evidenced +edge-cases/diacritic-segments Surface dtd:element/LeftEnvironment witnessed Evidenced +edge-cases/diacritic-segments Surface dtd:element/MorphologicalInput required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:element/MorphologicalRule required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:element/MorphologicalSubrule required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:element/MorphologicalSubrules required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:element/PhoneticTemplate required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:element/RequiredEnvironments witnessed Evidenced +edge-cases/diacritic-segments Surface dtd:element/Segment witnessed Evidenced +edge-cases/diacritic-segments Surface dtd:element/Slot required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Surface dtd:enum/Slot/optional/true witnessed Evidenced +edge-cases/diacritic-segments Interface AffixTemplate.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/diacritic-segments Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/diacritic-segments Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/diacritic-segments Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/diacritic-segments Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/diacritic-segments Interface Stratum.morphologicalRules present-but-inert Unobservable +edge-cases/diacritic-segments Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 6 claim(s) +edge-cases/diacritic-segments Construct AffixProcessRule: prefix/suffix/circumfix/infix claimed-unmapped 6 claim(s) +edge-cases/diacritic-segments Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 1 claim(s) +edge-cases/diacritic-segments Construct MorphologicalOutputAction: CopyFromInput/InsertSegments claimed-confirmed 6 claim(s) +edge-cases/diacritic-segments Construct NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision claimed-confirmed 4 claim(s) +edge-cases/disjunctive-recheck Surface dtd:element/RightEnvironment witnessed Evidenced +edge-cases/disjunctive-recheck Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/disjunctive-recheck Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/disjunctive-recheck Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/disjunctive-recheck Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/disjunctive-recheck Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/disjunctive-recheck Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/disjunctive-recheck Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/disjunctive-recheck Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/disjunctive-recheck Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/disjunctive-recheck Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/disjunctive-recheck Construct Disjunctive allomorphs / free-fluctuation claimed-unmapped 10 claim(s) +edge-cases/feature-gating-breadth Surface dtd:element/OutputFootFeatures witnessed Evidenced +edge-cases/feature-gating-breadth Surface dtd:element/Property required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Surface dtd:element/RealizationalFeatures required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Surface dtd:element/RealizationalRule required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Surface dtd:element/RequiredFootFeatures witnessed Evidenced +edge-cases/feature-gating-breadth Surface dtd:element/RequiredHeadFeatures witnessed Evidenced +edge-cases/feature-gating-breadth Surface dtd:enum/Stratum/morphologicalRuleOrder/linear witnessed Evidenced +edge-cases/feature-gating-breadth Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/feature-gating-breadth Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/feature-gating-breadth Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/feature-gating-breadth Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/feature-gating-breadth Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/feature-gating-breadth Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/feature-gating-breadth Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 1 claim(s) +edge-cases/feature-gating-breadth Construct RealizationalAffixProcessRule claimed-unmapped 3 claim(s) +edge-cases/feature-gating-breadth Construct Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) claimed-confirmed 11 claim(s) +edge-cases/feature-system-breadth Surface dtd:element/ComplexFeature required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Surface dtd:element/ExcludedEnvironments witnessed Evidenced +edge-cases/feature-system-breadth Surface dtd:element/MetathesisRule required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Surface dtd:element/StructuralDescription required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Surface dtd:enum/ComplexFeature/isActive/no witnessed EvidencedJointly +edge-cases/feature-system-breadth Surface dtd:enum/FeatureNaturalClass/isActive/no witnessed EvidencedJointly +edge-cases/feature-system-breadth Surface dtd:enum/FeatureValue/isActive/no witnessed Evidenced +edge-cases/feature-system-breadth Surface dtd:enum/LexicalEntry/isActive/no required-by-loader RequiredByLoader +edge-cases/feature-system-breadth Surface dtd:enum/MetathesisRule/isActive/no witnessed Evidenced +edge-cases/feature-system-breadth Surface dtd:enum/MetathesisRule/multipleApplicationOrder/rightToLeftIterative witnessed Evidenced +edge-cases/feature-system-breadth Surface dtd:enum/PhonologicalRule/isActive/no required-by-loader RequiredByLoader +edge-cases/feature-system-breadth Surface dtd:enum/PhonologicalSubrule/isActive/no witnessed Evidenced +edge-cases/feature-system-breadth Surface dtd:enum/SegmentNaturalClass/isActive/no witnessed EvidencedJointly +edge-cases/feature-system-breadth Surface dtd:enum/SymbolicFeature/isActive/no witnessed EvidencedJointly +edge-cases/feature-system-breadth Interface AlphaVariable.variableFeature required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/feature-system-breadth Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/feature-system-breadth Interface MetathesisRule.leftSwitch required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface MetathesisRule.rightSwitch required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/feature-system-breadth Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/feature-system-breadth Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/feature-system-breadth Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/feature-system-breadth Interface VariableFeature.phonologicalFeature required-by-dtd RequiredByDtd +edge-cases/feature-system-breadth Construct AffixProcessRule: prefix/suffix/circumfix/infix claimed-unmapped 1 claim(s) +edge-cases/feature-system-breadth Construct Alpha-variable phonological environments (VariableFeature/AlphaVariables) claimed-confirmed 2 claim(s) +edge-cases/feature-system-breadth Construct Element deactivation (isActive) across loader collections claimed-confirmed 1 claim(s) +edge-cases/feature-system-breadth Construct MetathesisRule claimed-confirmed 10 claim(s) +edge-cases/feature-system-breadth Construct NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision claimed-confirmed 3 claim(s) +edge-cases/feature-system-breadth Construct RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) claimed-unmapped 2 claim(s) +edge-cases/free-fluctuating-allomorph-pair Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/free-fluctuating-allomorph-pair Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/free-fluctuating-allomorph-pair Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/free-fluctuating-allomorph-pair Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/free-fluctuating-allomorph-pair Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/free-fluctuating-allomorph-pair Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/free-fluctuating-allomorph-pair Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/free-fluctuating-allomorph-pair Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/free-fluctuating-allomorph-pair Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/free-fluctuating-allomorph-pair Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/free-fluctuating-allomorph-pair Construct Disjunctive allomorphs / free-fluctuation claimed-unmapped 6 claim(s) +edge-cases/loader-default-symbol Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/loader-default-symbol Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/loader-default-symbol Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/loader-default-symbol Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/loader-default-symbol Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/loader-default-symbol Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/loader-default-symbol Interface SymbolicFeature.defaultSymbol present-but-inert Unobservable +edge-cases/loader-default-symbol Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 2 claim(s) +edge-cases/loader-isactive Surface dtd:element/BoundaryDefinition required-by-dtd RequiredByDtd +edge-cases/loader-isactive Surface dtd:enum/PhonologicalFeatureSystem/isActive/no required-by-loader RequiredByLoader +edge-cases/loader-isactive Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/loader-isactive Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/loader-isactive Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/loader-isactive Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/loader-isactive Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 2 claim(s) +edge-cases/loader-isactive-breadth Surface dtd:element/AffixTemplates witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:element/BoundaryDefinitions required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Surface dtd:element/Families required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Surface dtd:element/Family required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Surface dtd:element/MorphologicalPhonologicalRuleFeature required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Surface dtd:element/MorphologicalPhonologicalRuleFeatures required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Surface dtd:enum/AffixTemplate/final/true witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/AffixTemplate/isActive/no witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/AffixTemplate/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/Allomorph/isActive/no witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/Allomorph/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/Allomorph/isBound/false witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/BoundaryDefinition/isActive/no witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/BoundaryDefinition/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/CharacterDefinitionTable/isActive/no witnessed EvidencedJointly +edge-cases/loader-isactive-breadth Surface dtd:enum/CharacterDefinitionTable/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/Family/isActive/no witnessed EvidencedJointly +edge-cases/loader-isactive-breadth Surface dtd:enum/Family/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/FeatureNaturalClass/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/Language/isActive/no required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/Language/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/LexicalEntry/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/LexicalEntry/partial/false witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/no witnessed EvidencedJointly +edge-cases/loader-isactive-breadth Surface dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/MorphologicalRule/isActive/no witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/MorphologicalRule/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/MorphologicalSubrule/isActive/no required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/MorphologicalSubrule/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/SegmentDefinition/isActive/no witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/SegmentDefinition/isActive/yes required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/Slot/isActive/no witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/Slot/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Surface dtd:enum/Stratum/isActive/no required-by-loader RequiredByLoader +edge-cases/loader-isactive-breadth Surface dtd:enum/Stratum/isActive/yes witnessed Evidenced +edge-cases/loader-isactive-breadth Interface AffixTemplate.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/loader-isactive-breadth Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Interface LexicalEntry.family present-but-inert Unobservable +edge-cases/loader-isactive-breadth Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/loader-isactive-breadth Interface LexicalEntry.ruleFeatures present-but-inert Unobservable +edge-cases/loader-isactive-breadth Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/loader-isactive-breadth Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/loader-isactive-breadth Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/loader-isactive-breadth Construct Element deactivation (isActive) across loader collections claimed-confirmed 18 claim(s) +edge-cases/loader-pattern-shapes Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/loader-pattern-shapes Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/loader-pattern-shapes Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/loader-pattern-shapes Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 3 claim(s) +edge-cases/loader-pattern-shapes Construct CharacterDefinitionTable pattern shapes: optional group / Kleene star claimed-confirmed 1 claim(s) +edge-cases/metathesis-comparison-crash Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/metathesis-comparison-crash Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/metathesis-comparison-crash Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/metathesis-comparison-crash Interface MetathesisRule.leftSwitch required-by-dtd RequiredByDtd +edge-cases/metathesis-comparison-crash Interface MetathesisRule.rightSwitch required-by-dtd RequiredByDtd +edge-cases/metathesis-comparison-crash Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/metathesis-comparison-crash Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/metathesis-comparison-crash Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/metathesis-comparison-crash Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/metathesis-comparison-crash Construct MetathesisRule claimed-confirmed 1 claim(s) +edge-cases/morphotactic-attribute-breadth Surface dtd:element/AllomorphCoOccurrenceRule required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Surface dtd:element/AllomorphCoOccurrenceRules witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:element/MorphemeCoOccurrenceRule required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AffixTemplate/final/false witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/Allomorph/isBound/true witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToLeft witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToRight witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToLeft witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToRight witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AllomorphCoOccurrenceRule/isActive/no witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/AllomorphCoOccurrenceRule/type/require witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/LexicalEntry/partial/true witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphemeCoOccurrenceRule/adjacency/anywhere witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphemeCoOccurrenceRule/isActive/no witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphemeCoOccurrenceRule/type/require witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/no witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/append witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphologicalRule/blockable/false witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphologicalRule/multipleApplication/0 witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphologicalRule/multipleApplication/2 witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/MorphologicalRule/partial/true witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/RealizationalRule/blockable/false witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/RealizationalRule/isActive/no witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Surface dtd:enum/Stratum/morphologicalRuleOrder/unordered witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Interface AffixTemplate.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface AllomorphCoOccurrenceRule.otherAllomorphs required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface AllomorphCoOccurrenceRule.primaryAllomorph required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/morphotactic-attribute-breadth Interface LexicalEntry.family present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface LexicalEntry.ruleFeatures present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface MorphemeCoOccurrenceRule.otherMorphemes required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface MorphemeCoOccurrenceRule.primaryMorpheme required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface MorphologicalInput.excludedMPRFeatures witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Interface MorphologicalInput.requiredMPRFeatures present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Interface MorphologicalPhonologicalRuleFeatureGroup.features required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/morphotactic-attribute-breadth Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/morphotactic-attribute-breadth Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/morphotactic-attribute-breadth Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 5 claim(s) +edge-cases/morphotactic-attribute-breadth Construct Disjunctive allomorphs / free-fluctuation claimed-unmapped 1 claim(s) +edge-cases/morphotactic-attribute-breadth Construct Element deactivation (isActive) across loader collections claimed-confirmed 1 claim(s) +edge-cases/morphotactic-attribute-breadth Construct MPR features/groups claimed-unmapped 2 claim(s) +edge-cases/morphotactic-attribute-breadth Construct MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule claimed-confirmed 2 claim(s) +edge-cases/morphotactic-attribute-breadth Construct Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) claimed-contradicted 15 claim(s) +edge-cases/morphotactic-attribute-breadth Construct RealizationalAffixProcessRule claimed-unmapped 1 claim(s) +edge-cases/morphotactic-attribute-breadth Construct Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) claimed-confirmed 3 claim(s) +edge-cases/mpr-gated-exception Surface dtd:element/Environment witnessed Evidenced +edge-cases/mpr-gated-exception Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/mpr-gated-exception Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/mpr-gated-exception Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/mpr-gated-exception Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/mpr-gated-exception Interface LexicalEntry.ruleFeatures witnessed Evidenced +edge-cases/mpr-gated-exception Interface MorphologicalInput.excludedMPRFeatures witnessed Evidenced +edge-cases/mpr-gated-exception Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +edge-cases/mpr-gated-exception Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/mpr-gated-exception Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/mpr-gated-exception Interface PhonologicalSubrule.excludedMPRFeatures witnessed Evidenced +edge-cases/mpr-gated-exception Interface PhonologicalSubrule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/mpr-gated-exception Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/mpr-gated-exception Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/mpr-gated-exception Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/mpr-gated-exception Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/mpr-gated-exception Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/mpr-gated-exception Construct RewriteRule direction (Dir): left-to-right claimed-unmapped 1 claim(s) +edge-cases/mpr-group-overwrite-without-realizational Surface dtd:element/MorphologicalPhonologicalRuleFeatureGroup witnessed Evidenced +edge-cases/mpr-group-overwrite-without-realizational Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/overwrite witnessed Evidenced +edge-cases/mpr-group-overwrite-without-realizational Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/mpr-group-overwrite-without-realizational Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/mpr-group-overwrite-without-realizational Interface MorphologicalInput.requiredMPRFeatures witnessed Evidenced +edge-cases/mpr-group-overwrite-without-realizational Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +edge-cases/mpr-group-overwrite-without-realizational Interface MorphologicalPhonologicalRuleFeatureGroup.features required-by-dtd RequiredByDtd +edge-cases/mpr-group-overwrite-without-realizational Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/mpr-group-overwrite-without-realizational Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/mpr-group-overwrite-without-realizational Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/mpr-group-overwrite-without-realizational Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/mpr-group-overwrite-without-realizational Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/mpr-group-overwrite-without-realizational Construct MPR features/groups claimed-unmapped 4 claim(s) +edge-cases/mpr-overwrite-order-dependence Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/mpr-overwrite-order-dependence Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/mpr-overwrite-order-dependence Interface MorphologicalInput.requiredMPRFeatures witnessed Evidenced +edge-cases/mpr-overwrite-order-dependence Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +edge-cases/mpr-overwrite-order-dependence Interface MorphologicalPhonologicalRuleFeatureGroup.features required-by-dtd RequiredByDtd +edge-cases/mpr-overwrite-order-dependence Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/mpr-overwrite-order-dependence Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/mpr-overwrite-order-dependence Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/mpr-overwrite-order-dependence Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/mpr-overwrite-order-dependence Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/process-morphology-in-place-mutation Surface dtd:element/ModifyFromInput witnessed Evidenced +edge-cases/process-morphology-in-place-mutation Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/process-morphology-in-place-mutation Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/process-morphology-in-place-mutation Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/process-morphology-in-place-mutation Interface ModifyFromInput.index required-by-dtd RequiredByDtd +edge-cases/process-morphology-in-place-mutation Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/process-morphology-in-place-mutation Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/process-morphology-in-place-mutation Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/process-morphology-in-place-mutation Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/process-morphology-in-place-mutation Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/process-morphology-in-place-mutation Construct MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext claimed-confirmed 1 claim(s) +edge-cases/right-to-left-anchor-environment Surface dtd:enum/PhoneticTemplate/finalBoundaryCondition/true witnessed Evidenced +edge-cases/right-to-left-anchor-environment Surface dtd:enum/PhonologicalRule/multipleApplicationOrder/rightToLeftIterative witnessed Evidenced +edge-cases/right-to-left-anchor-environment Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/right-to-left-anchor-environment Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/right-to-left-anchor-environment Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/right-to-left-anchor-environment Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/right-to-left-anchor-environment Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/right-to-left-anchor-environment Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/right-to-left-anchor-environment Construct RewriteRule direction (Dir): right-to-left claimed-unmapped 9 claim(s) +edge-cases/simultaneous-epenthesis-cascade Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/simultaneous-epenthesis-cascade Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/simultaneous-epenthesis-cascade Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/simultaneous-epenthesis-cascade Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/simultaneous-epenthesis-cascade Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/simultaneous-epenthesis-cascade Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/stem-name-restricted-root-allomorph Surface dtd:element/OutputHeadFeatures witnessed Evidenced +edge-cases/stem-name-restricted-root-allomorph Surface dtd:element/Region required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Surface dtd:element/Regions required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Surface dtd:element/StemName required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Surface dtd:element/StemNames required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Interface Allomorph.stemName witnessed Evidenced +edge-cases/stem-name-restricted-root-allomorph Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/stem-name-restricted-root-allomorph Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/stem-name-restricted-root-allomorph Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/stem-name-restricted-root-allomorph Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/stem-name-restricted-root-allomorph Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Interface StemName.partsOfSpeech required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/stem-name-restricted-root-allomorph Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/stem-name-restricted-root-allomorph Construct Stem names claimed-unmapped 6 claim(s) +edge-cases/strrep-identity Surface dtd:element/Segments witnessed Evidenced +edge-cases/strrep-identity Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/strrep-identity Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/strrep-identity Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +edge-cases/strrep-identity Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/strrep-identity Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/strrep-identity Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/strrep-identity Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/strrep-identity Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/strrep-identity Construct NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision claimed-confirmed 17 claim(s) +edge-cases/subrule-morphosyntactic-gating Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/subrule-morphosyntactic-gating Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/subrule-morphosyntactic-gating Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/subrule-morphosyntactic-gating Interface LexicalEntry.partOfSpeech witnessed Evidenced +edge-cases/subrule-morphosyntactic-gating Interface MorphologicalRule.outputPartOfSpeech witnessed Evidenced +edge-cases/subrule-morphosyntactic-gating Interface PhonologicalSubrule.requiredPartsOfSpeech witnessed Evidenced +edge-cases/subrule-morphosyntactic-gating Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/subrule-morphosyntactic-gating Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/subrule-morphosyntactic-gating Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/subrule-morphosyntactic-gating Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/subrule-morphosyntactic-gating Interface Stratum.phonologicalRules witnessed Evidenced +edge-cases/subrule-morphosyntactic-gating Construct RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level claimed-unmapped 2 claim(s) +edge-cases/truncate-morphotactic Interface CopyFromInput.index required-by-dtd RequiredByDtd +edge-cases/truncate-morphotactic Interface FeatureValue.feature required-by-dtd RequiredByDtd +edge-cases/truncate-morphotactic Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +edge-cases/truncate-morphotactic Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +edge-cases/truncate-morphotactic Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +edge-cases/truncate-morphotactic Interface Segment.segment required-by-dtd RequiredByDtd +edge-cases/truncate-morphotactic Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +edge-cases/truncate-morphotactic Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +edge-cases/truncate-morphotactic Interface Stratum.morphologicalRules witnessed Evidenced +edge-cases/truncate-morphotactic Construct AffixProcessRule: subtraction/truncation claimed-unmapped 10 claim(s) +languages/fusional-realizational-morphology Surface dtd:enum/CompoundingRule/blockable/false witnessed Evidenced +languages/fusional-realizational-morphology Surface dtd:enum/CompoundingRule/blockable/true witnessed Evidenced +languages/fusional-realizational-morphology Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/yes witnessed Evidenced +languages/fusional-realizational-morphology Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/all witnessed Evidenced +languages/fusional-realizational-morphology Surface dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/any witnessed Evidenced +languages/fusional-realizational-morphology Interface Allomorph.stemName witnessed Evidenced +languages/fusional-realizational-morphology Interface CompoundingRule.headPartsOfSpeech present-but-inert Unobservable +languages/fusional-realizational-morphology Interface CompoundingRule.headProdRestrictionsMprFeatures witnessed Evidenced +languages/fusional-realizational-morphology Interface CompoundingRule.nonHeadPartsOfSpeech present-but-inert Unobservable +languages/fusional-realizational-morphology Interface CompoundingRule.outputObligatoryFeatures present-but-inert Unobservable +languages/fusional-realizational-morphology Interface CompoundingRule.outputPartOfSpeech present-but-inert Unobservable +languages/fusional-realizational-morphology Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface FeatureValue.feature required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +languages/fusional-realizational-morphology Interface HeadMorphologicalInput.excludedMPRFeatures present-but-inert Unobservable +languages/fusional-realizational-morphology Interface HeadMorphologicalInput.requiredMPRFeatures present-but-inert Unobservable +languages/fusional-realizational-morphology Interface LexicalEntry.family witnessed Evidenced +languages/fusional-realizational-morphology Interface LexicalEntry.partOfSpeech witnessed Evidenced +languages/fusional-realizational-morphology Interface LexicalEntry.ruleFeatures witnessed Evidenced +languages/fusional-realizational-morphology Interface ModifyFromInput.index required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface MorphologicalInput.requiredMPRFeatures witnessed Evidenced +languages/fusional-realizational-morphology Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +languages/fusional-realizational-morphology Interface MorphologicalPhonologicalRuleFeatureGroup.features required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/fusional-realizational-morphology Interface MorphologicalRule.requiredPartsOfSpeech witnessed Evidenced +languages/fusional-realizational-morphology Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface StemName.partsOfSpeech required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/fusional-realizational-morphology Interface Stratum.morphologicalRules witnessed Evidenced +languages/fusional-realizational-morphology Construct AffixProcessRule: prefix/suffix/circumfix/infix claimed-unmapped 6 claim(s) +languages/fusional-realizational-morphology Construct CompoundingRule claimed-confirmed 8 claim(s) +languages/fusional-realizational-morphology Construct CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features) claimed-confirmed 6 claim(s) +languages/fusional-realizational-morphology Construct MPR features/groups claimed-unmapped 16 claim(s) +languages/fusional-realizational-morphology Construct MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext claimed-confirmed 1 claim(s) +languages/fusional-realizational-morphology Construct RealizationalAffixProcessRule claimed-unmapped 6 claim(s) +languages/fusional-realizational-morphology Construct Stem names claimed-unmapped 12 claim(s) +languages/metathesis-phase-isolation Surface dtd:enum/MorphologicalOutput/redupMorphType/prefix witnessed Evidenced +languages/metathesis-phase-isolation Interface BoundaryMarker.boundary required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface FeatureValue.feature required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +languages/metathesis-phase-isolation Interface LexicalEntry.partOfSpeech witnessed Evidenced +languages/metathesis-phase-isolation Interface MetathesisRule.leftSwitch required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface MetathesisRule.rightSwitch required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/metathesis-phase-isolation Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +languages/metathesis-phase-isolation Interface PhonologicalSubrule.requiredPartsOfSpeech witnessed Evidenced +languages/metathesis-phase-isolation Interface Segment.segment required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/metathesis-phase-isolation Interface Stratum.morphologicalRules witnessed Evidenced +languages/metathesis-phase-isolation Interface Stratum.phonologicalRules witnessed Evidenced +languages/metathesis-phase-isolation Construct AffixProcessRule: prefix/suffix/circumfix/infix claimed-unmapped 5 claim(s) +languages/metathesis-phase-isolation Construct AffixProcessRule: reduplication (ReduplicationHint) claimed-unmapped 2 claim(s) +languages/metathesis-phase-isolation Construct AffixProcessRule: subtraction/truncation claimed-unmapped 1 claim(s) +languages/metathesis-phase-isolation Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 1 claim(s) +languages/metathesis-phase-isolation Construct MetathesisRule claimed-confirmed 3 claim(s) +languages/metathesis-phase-isolation Construct MorphologicalOutputAction: CopyFromInput/InsertSegments claimed-confirmed 3 claim(s) +languages/metathesis-phase-isolation Construct RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) claimed-unmapped 3 claim(s) +languages/polysynthetic-stratal-derivation-chain Interface CompoundingRule.headPartsOfSpeech witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Interface CompoundingRule.nonHeadPartsOfSpeech present-but-inert Unobservable +languages/polysynthetic-stratal-derivation-chain Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/polysynthetic-stratal-derivation-chain Interface FeatureValue.feature required-by-dtd RequiredByDtd +languages/polysynthetic-stratal-derivation-chain Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +languages/polysynthetic-stratal-derivation-chain Interface LexicalEntry.partOfSpeech witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Interface MorphologicalRule.outputPartOfSpeech witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Interface MorphologicalRule.requiredPartsOfSpeech witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Interface PhonologicalSubrule.requiredPartsOfSpeech witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Interface Segment.segment required-by-dtd RequiredByDtd +languages/polysynthetic-stratal-derivation-chain Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/polysynthetic-stratal-derivation-chain Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/polysynthetic-stratal-derivation-chain Interface Stratum.morphologicalRules witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Interface Stratum.phonologicalRules witnessed Evidenced +languages/polysynthetic-stratal-derivation-chain Construct AffixProcessRule: prefix/suffix/circumfix/infix claimed-unmapped 3 claim(s) +languages/polysynthetic-stratal-derivation-chain Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 4 claim(s) +languages/polysynthetic-stratal-derivation-chain Construct CompoundingRule claimed-confirmed 9 claim(s) +languages/polysynthetic-stratal-derivation-chain Construct Guesser/LexicalGuess claimed-unmapped 4 claim(s) +languages/polysynthetic-stratal-derivation-chain Construct RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) claimed-unmapped 13 claim(s) +languages/polysynthetic-stratal-derivation-chain Construct Stratum (Linear/Unordered rule order) claimed-confirmed 2 claim(s) +languages/prefixal-discontinuous-slot-dependency Interface AffixTemplate.requiredPartsOfSpeech present-but-inert Unobservable +languages/prefixal-discontinuous-slot-dependency Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/prefixal-discontinuous-slot-dependency Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +languages/prefixal-discontinuous-slot-dependency Interface LexicalEntry.ruleFeatures witnessed Evidenced +languages/prefixal-discontinuous-slot-dependency Interface MorphologicalInput.requiredMPRFeatures witnessed Evidenced +languages/prefixal-discontinuous-slot-dependency Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +languages/prefixal-discontinuous-slot-dependency Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/prefixal-discontinuous-slot-dependency Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +languages/prefixal-discontinuous-slot-dependency Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/prefixal-discontinuous-slot-dependency Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +languages/prefixal-discontinuous-slot-dependency Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/prefixal-discontinuous-slot-dependency Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 10 claim(s) +languages/suffixing-evidential-adjacency-chain Surface dtd:element/MorphemeCoOccurrenceRules witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/AllomorphCoOccurrenceRule/adjacency/anywhere witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/AllomorphCoOccurrenceRule/isActive/yes witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/AllomorphCoOccurrenceRule/type/exclude witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToLeft witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToRight witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToLeft witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToRight witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/MorphemeCoOccurrenceRule/isActive/yes witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Surface dtd:enum/MorphemeCoOccurrenceRule/type/exclude witnessed Evidenced +languages/suffixing-evidential-adjacency-chain Interface AffixTemplate.requiredPartsOfSpeech present-but-inert Unobservable +languages/suffixing-evidential-adjacency-chain Interface AllomorphCoOccurrenceRule.otherAllomorphs required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface AllomorphCoOccurrenceRule.primaryAllomorph required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface LexicalEntry.partOfSpeech present-but-inert Unobservable +languages/suffixing-evidential-adjacency-chain Interface MorphemeCoOccurrenceRule.otherMorphemes required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface MorphemeCoOccurrenceRule.primaryMorpheme required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/suffixing-evidential-adjacency-chain Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +languages/suffixing-evidential-adjacency-chain Interface Segment.segment required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/suffixing-evidential-adjacency-chain Interface Stratum.morphologicalRules present-but-inert Unobservable +languages/suffixing-evidential-adjacency-chain Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 12 claim(s) +languages/suffixing-evidential-adjacency-chain Construct Disjunctive allomorphs / free-fluctuation claimed-unmapped 2 claim(s) +languages/suffixing-evidential-adjacency-chain Construct MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule claimed-confirmed 15 claim(s) +languages/suffixing-extension-slot-ordering Surface dtd:enum/MorphologicalOutput/redupMorphType/suffix witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface AffixTemplate.requiredPartsOfSpeech witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface Allomorph.stemName witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface FeatureValue.feature required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +languages/suffixing-extension-slot-ordering Interface LexicalEntry.family witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface LexicalEntry.partOfSpeech witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface LexicalEntry.ruleFeatures witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface MorphologicalInput.requiredMPRFeatures required-by-loader RequiredByLoader +languages/suffixing-extension-slot-ordering Interface MorphologicalOutput.MPRFeatures witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface MorphologicalPhonologicalRuleFeatureGroup.features required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface MorphologicalRule.outputObligatoryFeatures present-but-inert Unobservable +languages/suffixing-extension-slot-ordering Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/suffixing-extension-slot-ordering Interface MorphologicalRule.requiredPartsOfSpeech witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface MorphologicalRule.requiredStemName witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface PhonologicalSubrule.excludedMPRFeatures witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface PhonologicalSubrule.requiredMPRFeatures witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface PhonologicalSubrule.requiredPartsOfSpeech witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface StemName.partsOfSpeech required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/suffixing-extension-slot-ordering Interface Stratum.morphologicalRules witnessed Evidenced +languages/suffixing-extension-slot-ordering Interface Stratum.phonologicalRules witnessed Evidenced +languages/suffixing-extension-slot-ordering Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 6 claim(s) +languages/suffixing-extension-slot-ordering Construct AffixProcessRule: reduplication (ReduplicationHint) claimed-unmapped 1 claim(s) +languages/suffixing-extension-slot-ordering Construct MPR features/groups claimed-unmapped 18 claim(s) +languages/suffixing-extension-slot-ordering Construct Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable) claimed-confirmed 8 claim(s) +languages/suffixing-extension-slot-ordering Construct RealizationalAffixProcessRule claimed-unmapped 3 claim(s) +languages/suffixing-extension-slot-ordering Construct RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) claimed-unmapped 2 claim(s) +languages/suffixing-extension-slot-ordering Construct RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level claimed-unmapped 2 claim(s) +languages/suffixing-extension-slot-ordering Construct Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures) claimed-confirmed 6 claim(s) +languages/suffixing-vowel-harmony Surface dtd:enum/PhoneticTemplate/initialBoundaryCondition/true witnessed Evidenced +languages/suffixing-vowel-harmony Interface AffixTemplate.requiredPartsOfSpeech witnessed Evidenced +languages/suffixing-vowel-harmony Interface AlphaVariable.variableFeature required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface FeatureValue.feature required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +languages/suffixing-vowel-harmony Interface LexicalEntry.partOfSpeech witnessed Evidenced +languages/suffixing-vowel-harmony Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/suffixing-vowel-harmony Interface MorphologicalRule.requiredPartsOfSpeech present-but-inert Unobservable +languages/suffixing-vowel-harmony Interface PhonologicalSubrule.requiredPartsOfSpeech witnessed Evidenced +languages/suffixing-vowel-harmony Interface Segment.segment required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface Slot.morphologicalRules required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Interface Stratum.morphologicalRules witnessed Evidenced +languages/suffixing-vowel-harmony Interface Stratum.phonologicalRules witnessed Evidenced +languages/suffixing-vowel-harmony Interface VariableFeature.phonologicalFeature required-by-dtd RequiredByDtd +languages/suffixing-vowel-harmony Construct Affix template slots (obligatory/disjunctive/ordering) claimed-unmapped 7 claim(s) +languages/suffixing-vowel-harmony Construct AffixProcessRule: prefix/suffix/circumfix/infix claimed-unmapped 3 claim(s) +languages/suffixing-vowel-harmony Construct Alpha-variable phonological environments (VariableFeature/AlphaVariables) claimed-confirmed 6 claim(s) +languages/suffixing-vowel-harmony Construct Boundary markers (CharacterDefinitionTable) claimed-confirmed 2 claim(s) +languages/suffixing-vowel-harmony Construct NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision claimed-confirmed 1 claim(s) +languages/suffixing-vowel-harmony Construct RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) claimed-unmapped 8 claim(s) +languages/suffixing-vowel-harmony Construct RewriteRule Simultaneous claimed-unmapped 9 claim(s) +languages/templatic-root-modification Surface dtd:element/InsertSimpleContext witnessed Evidenced +languages/templatic-root-modification Surface dtd:enum/PhonologicalRule/multipleApplicationOrder/simultaneous witnessed Evidenced +languages/templatic-root-modification Interface Allomorph.stemName witnessed Evidenced +languages/templatic-root-modification Interface CopyFromInput.index required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface FeatureValue.feature required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface FeatureValue.symbolValues required-by-loader RequiredByLoader +languages/templatic-root-modification Interface LexicalEntry.partOfSpeech witnessed Evidenced +languages/templatic-root-modification Interface ModifyFromInput.index required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface MorphemeCoOccurrenceRule.otherMorphemes required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface MorphemeCoOccurrenceRule.primaryMorpheme required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface MorphologicalRule.outputPartOfSpeech present-but-inert Unobservable +languages/templatic-root-modification Interface MorphologicalRule.requiredPartsOfSpeech witnessed Evidenced +languages/templatic-root-modification Interface PhonologicalSubrule.requiredPartsOfSpeech witnessed Evidenced +languages/templatic-root-modification Interface Segment.segment required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface SimpleContext.naturalClass required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface StemName.partsOfSpeech required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface Stratum.characterDefinitionTable required-by-dtd RequiredByDtd +languages/templatic-root-modification Interface Stratum.morphologicalRules witnessed Evidenced +languages/templatic-root-modification Interface Stratum.phonologicalRules witnessed Evidenced +languages/templatic-root-modification Construct MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule claimed-confirmed 1 claim(s) +languages/templatic-root-modification Construct MorphologicalOutputAction: CopyFromInput/InsertSegments claimed-confirmed 2 claim(s) +languages/templatic-root-modification Construct MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext claimed-confirmed 2 claim(s) +languages/templatic-root-modification Construct RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge) claimed-unmapped 6 claim(s) +languages/templatic-root-modification Construct RewriteRule Simultaneous claimed-unmapped 4 claim(s) +languages/templatic-root-modification Construct Stem names claimed-unmapped 8 claim(s) diff --git a/conformance/harness-runs/first-pass-yield.tsv b/conformance/harness-runs/first-pass-yield.tsv new file mode 100644 index 000000000..707499d14 --- /dev/null +++ b/conformance/harness-runs/first-pass-yield.tsv @@ -0,0 +1,12 @@ +attempt_id cell_id skill_version set phase_reached outcome failure_class notes +1 StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentGatedForm cbd1321f reference 3 fail false-impossibility no words authored; argued severance cannot flip fail-to-pass on a required* reader +2 MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm cbd1321f reference 3 fail false-impossibility same argument, three exercising fixtures checked +3 MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm cbd1321f reference 3 fail false-impossibility same argument +4 MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm cbd1321f reference 3 fail false-impossibility complementary-subrule argument; may be genuinely blocked, untested by authoring +5 MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm cbd1321f reference 3 fail false-impossibility mirror of 4 +6 PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm cbd1321f reference 6 pass - idil in metathesis-phase-isolation; first attempt; disproves attempts 1-5 general argument +7 StemName::Allomorph.stemName->MorphologicalRule.requiredStemName::McDc:AbsentGatedForm 51b1344c reference 5 fail no-witness exhaustive sweep over 46 words; hard object-ref equality in SynthesisAffixProcessRule.cs:106; falsified against all 4 satisfied cells +8 MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm 51b1344c reference 5 fail no-witness swept all 71 words in both viable hosts; ruleFeatures is a plain UnionWith preset, never an Overwrite trigger +9 MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm 51b1344c reference 6 pass - ygofz; Overwrite group destroys a lexically-preset feature before the reader gate is checked +10 MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm 51b1344c reference 5 fail no-witness authored novlav to exhaust the 5-word lexicon; both readers Unobservable; needs a grammar edit +11 MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->HeadMorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm 51b1344c reference 5 fail no-witness mirror of 10; complementary subrule pair is exhaustive over one binary feature diff --git a/conformance/interaction-chains.tsv b/conformance/interaction-chains.tsv new file mode 100644 index 000000000..1b6782dcc --- /dev/null +++ b/conformance/interaction-chains.tsv @@ -0,0 +1,52 @@ +# GENERATED by hc-conformance --write-interaction-chains. One row per (writer edge, payload +# type, reader edge) at each ChainJunction -- a payload type reached by both a write- and a +# read-direction declared interface, per SemanticInterfaceDirection's engine-checked judgment +# of what each interface does (NOT interface-inventory.tsv's own name-prefix heuristic, which +# a real field grammar disproved -- see SemanticInterfaceDirection's doc comment). payload_type +# also covers interfaces no fixture exercises yet (see UnexercisedInterfaceDeclaredPayloadTypes), +# so an entirely-untested reader still appears in its own denominator instead of silently +# vanishing. exercising_fixtures lists every fixture where the SAME id appears in both the +# writer's and the reader's attribute values; hazardous means at least one of those fixtures +# also has a MutatingConstructs entry (today: an overwrite-type +# MorphologicalPhonologicalRuleFeatureGroup) covering that id. +writer_element writer_attribute payload_type reader_element reader_attribute exercised exercising_fixtures hazardous +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures no no +CompoundingRule outputProdRestrictionsMprFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures no no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures yes languages/fusional-realizational-morphology no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures no no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures yes languages/fusional-realizational-morphology no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures yes languages/fusional-realizational-morphology no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures yes edge-cases/mpr-gated-exception no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures yes languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering yes +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures yes languages/suffixing-extension-slot-ordering no +LexicalEntry ruleFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures yes languages/suffixing-extension-slot-ordering yes +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule headProdRestrictionsMprFeatures yes languages/fusional-realizational-morphology no +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature CompoundingRule nonHeadProdRestrictionsMprFeatures no no +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput excludedMPRFeatures no no +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature HeadMorphologicalInput requiredMPRFeatures no no +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput excludedMPRFeatures yes edge-cases/morphotactic-attribute-breadth no +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature MorphologicalInput requiredMPRFeatures yes edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering yes +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule excludedMPRFeatures yes edge-cases/mpr-gated-exception no +MorphologicalOutput MPRFeatures MorphologicalPhonologicalRuleFeature PhonologicalSubrule requiredMPRFeatures yes languages/suffixing-extension-slot-ordering yes +CompoundingRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech no no +CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech yes edge-cases/compounding-breadth,languages/fusional-realizational-morphology no +CompoundingRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech yes edge-cases/compounding-breadth no +CompoundingRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech yes edge-cases/compounding-breadth no +CompoundingRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech no no +LexicalEntry partOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech yes edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony no +LexicalEntry partOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech yes edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain no +LexicalEntry partOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech yes edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain no +LexicalEntry partOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech yes edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification no +LexicalEntry partOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech yes edge-cases/mpr-gated-exception,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification no +MorphologicalRule outputPartOfSpeech PartOfSpeech AffixTemplate requiredPartsOfSpeech yes edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony no +MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule headPartsOfSpeech yes languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain no +MorphologicalRule outputPartOfSpeech PartOfSpeech CompoundingRule nonHeadPartsOfSpeech yes languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain no +MorphologicalRule outputPartOfSpeech PartOfSpeech MorphologicalRule requiredPartsOfSpeech yes edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification no +MorphologicalRule outputPartOfSpeech PartOfSpeech PhonologicalSubrule requiredPartsOfSpeech yes edge-cases/mpr-gated-exception,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification no +Allomorph stemName StemName MorphologicalRule requiredStemName yes languages/suffixing-extension-slot-ordering no diff --git a/conformance/interface-inventory.tsv b/conformance/interface-inventory.tsv new file mode 100644 index 000000000..f83dcf843 --- /dev/null +++ b/conformance/interface-inventory.tsv @@ -0,0 +1,70 @@ +# GENERATED by hc-conformance --write-interface-inventory. One row per IDREF/IDREFS attribute +# declared anywhere in HermitCrabInput.dtd -- a fixed denominator that moves only when the DTD +# changes, never when a fixture is added. observed_target_types is the set of element types the +# attribute's IDREF(S) tokens actually resolved to, across every fixture's own id-to-element map; +# empty when not present. direction (write/read/ref) is SemanticInterfaceDirection's engine- +# checked judgment, not a naming-convention guess -- see its doc comment for what each entry means. +# present is STRUCTURAL ONLY -- the attribute resolves to a real IDREF somewhere in fixtures +# (comma-joined, sorted). It is NOT evidence the interface does anything: an attribute can be +# present and inert. See conformance/interface-witness.tsv for the severance-tested claim. +element attribute ref_kind observed_target_types present direction fixtures +AffixTemplate requiredPartsOfSpeech IdRefs PartOfSpeech yes Read edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony +AffixTemplate requiredSubcategorizedRules IdRefs no Read - +Allomorph stemName IdRef StemName yes Write edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +AllomorphCoOccurrenceRule otherAllomorphs IdRefs Allomorph,MorphologicalSubrule yes Ref edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain +AllomorphCoOccurrenceRule primaryAllomorph IdRef Allomorph,MorphologicalSubrule yes Ref edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain +AlphaVariable variableFeature IdRef VariableFeature yes Ref edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,languages/suffixing-vowel-harmony +BoundaryMarker boundary IdRef BoundaryDefinition yes Ref languages/metathesis-phase-isolation +CompoundingRule headPartsOfSpeech IdRefs PartOfSpeech yes Read edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +CompoundingRule headProdRestrictionsMprFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read languages/fusional-realizational-morphology +CompoundingRule headSubcategorizedRules IdRefs no Read - +CompoundingRule nonHeadPartsOfSpeech IdRefs PartOfSpeech yes Read edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +CompoundingRule nonHeadProdRestrictionsMprFeatures IdRefs no Read - +CompoundingRule nonHeadSubcategorizedRules IdRefs no Read - +CompoundingRule outputObligatoryFeatures IdRefs SymbolicFeature yes Write languages/fusional-realizational-morphology +CompoundingRule outputPartOfSpeech IdRef PartOfSpeech yes Write edge-cases/compounding-breadth,languages/fusional-realizational-morphology +CompoundingRule outputProdRestrictionsMprFeatures IdRefs no Write - +CompoundingRule outputSubcategorization IdRefs no Write - +CopyFromInput index IdRef PhoneticSequence yes Ref edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +FeatureValue feature IdRef ComplexFeature,SymbolicFeature yes Ref edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/metathesis-comparison-crash,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/simultaneous-epenthesis-cascade,edge-cases/stem-name-restricted-root-allomorph,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +FeatureValue symbolValues IdRefs Symbol yes Ref edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/metathesis-comparison-crash,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/simultaneous-epenthesis-cascade,edge-cases/stem-name-restricted-root-allomorph,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +HeadMorphologicalInput excludedMPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read languages/fusional-realizational-morphology +HeadMorphologicalInput requiredMPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read languages/fusional-realizational-morphology +InsertSegments characterDefinitionTable IdRef no Ref - +LexicalEntry family IdRef Family yes Ref edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +LexicalEntry morphologicalRules IdRefs no Ref - +LexicalEntry obligatoryFootFeatures IdRefs no Read - +LexicalEntry obligatoryHeadFeatures IdRefs no Read - +LexicalEntry partOfSpeech IdRef PartOfSpeech yes Write edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/metathesis-comparison-crash,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/simultaneous-epenthesis-cascade,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +LexicalEntry ruleFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Write edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering +LexicalEntry subcategorizations IdRefs no Ref - +MetathesisRule leftSwitch IdRef SimpleContext yes Ref edge-cases/feature-system-breadth,edge-cases/metathesis-comparison-crash,languages/metathesis-phase-isolation +MetathesisRule rightSwitch IdRef SimpleContext yes Ref edge-cases/feature-system-breadth,edge-cases/metathesis-comparison-crash,languages/metathesis-phase-isolation +ModifyFromInput index IdRef PhoneticSequence yes Ref edge-cases/process-morphology-in-place-mutation,languages/fusional-realizational-morphology,languages/templatic-root-modification +MorphemeCoOccurrenceRule otherMorphemes IdRefs LexicalEntry,MorphologicalRule yes Ref edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +MorphemeCoOccurrenceRule primaryMorpheme IdRef MorphologicalRule yes Ref edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +MorphologicalInput excludedMPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception +MorphologicalInput requiredMPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering +MorphologicalOutput MPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Write edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering +MorphologicalPhonologicalRuleFeatureGroup features IdRefs MorphologicalPhonologicalRuleFeature yes Ref edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +MorphologicalRule outputObligatoryFeatures IdRefs SymbolicFeature yes Write languages/suffixing-extension-slot-ordering +MorphologicalRule outputPartOfSpeech IdRef PartOfSpeech yes Write edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +MorphologicalRule outputSubcategorization IdRefs no Write - +MorphologicalRule requiredPartsOfSpeech IdRefs PartOfSpeech yes Read edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +MorphologicalRule requiredStemName IdRef StemName yes Read languages/suffixing-extension-slot-ordering +MorphologicalRule requiredSubcategorizedRules IdRefs no Read - +OutputSubcategorizationOverride inputSubcategorization IdRef no Ref - +OutputSubcategorizationOverride outputSubcategorization IdRef no Write - +PhonologicalSubrule excludedMPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read edge-cases/mpr-gated-exception,languages/suffixing-extension-slot-ordering +PhonologicalSubrule requiredMPRFeatures IdRefs MorphologicalPhonologicalRuleFeature yes Read languages/suffixing-extension-slot-ordering +PhonologicalSubrule requiredPartsOfSpeech IdRefs PartOfSpeech yes Read edge-cases/mpr-gated-exception,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +Segment segment IdRef SegmentDefinition yes Ref edge-cases/alpha-variable-name-collision,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-pattern-shapes,edge-cases/metathesis-comparison-crash,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-evidential-adjacency-chain,languages/suffixing-vowel-harmony,languages/templatic-root-modification +Segments characterDefinitionTable IdRef no Ref - +SimpleContext naturalClass IdRef FeatureNaturalClass,SegmentNaturalClass yes Ref edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive-breadth,edge-cases/metathesis-comparison-crash,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/simultaneous-epenthesis-cascade,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +Slot morphologicalRules IdRefs MorphologicalRule,RealizationalRule yes Ref edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony +StemName partsOfSpeech IdRefs PartOfSpeech yes Ref edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +Stratum characterDefinitionTable IdRef CharacterDefinitionTable yes Ref edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/deep-optional-affix-nesting,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/metathesis-comparison-crash,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/simultaneous-epenthesis-cascade,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +Stratum morphologicalRules IdRefs CompoundingRule,MorphologicalRule,RealizationalRule yes Ref edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +Stratum phonologicalRules IdRefs MetathesisRule,PhonologicalRule yes Ref edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/metathesis-comparison-crash,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/simultaneous-epenthesis-cascade,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +SymbolicFeature defaultSymbol IdRef Symbol yes Ref edge-cases/loader-default-symbol +VariableFeature phonologicalFeature IdRef SymbolicFeature yes Ref edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,languages/suffixing-vowel-harmony diff --git a/conformance/interface-witness.tsv b/conformance/interface-witness.tsv new file mode 100644 index 000000000..37255f1d5 --- /dev/null +++ b/conformance/interface-witness.tsv @@ -0,0 +1,380 @@ +# GENERATED by hc-conformance --write-coverage-traceability. One row per (element, attribute, +# fixture) triple InterfaceInventoryLedger marks present -- i.e. one severance run per place the +# interface actually shows up. Presence (interface-inventory.tsv) only means the attribute +# resolves to a real IDREF somewhere; it says nothing about whether the interface DOES anything. +# This ledger answers that by emptying the attribute out of every occurrence in the fixture and +# re-parsing every word against the mutant, exactly as CounterfactualLedger does for a unit +# surface. verdict is CounterfactualVerdict: only Evidenced is a word-level witness; +# RequiredByLoader/RequiredByDtd mean severing it made the grammar fail to load (a real but weaker +# signal -- no word was ever reached); Unobservable means the interface is present but INERT in +# this fixture -- every word parsed identically with it severed. Absent fields are "-". +element attribute fixture verdict mutation delta example_word example_outcome counterexample_kind counterexample_outcome +AffixTemplate requiredPartsOfSpeech edge-cases/deep-optional-affix-nesting Unobservable removed requiredPartsOfSpeech from 1 element(s) all 3 word(s) unchanged - - None - +AffixTemplate requiredPartsOfSpeech edge-cases/diacritic-segments Unobservable removed requiredPartsOfSpeech from 1 element(s) all 13 word(s) unchanged - - None - +AffixTemplate requiredPartsOfSpeech edge-cases/loader-isactive-breadth Unobservable removed requiredPartsOfSpeech from 2 element(s) all 18 word(s) unchanged - - None - +AffixTemplate requiredPartsOfSpeech edge-cases/morphotactic-attribute-breadth Unobservable removed requiredPartsOfSpeech from 3 element(s) all 33 word(s) unchanged - - None - +AffixTemplate requiredPartsOfSpeech languages/prefixal-discontinuous-slot-dependency Unobservable removed requiredPartsOfSpeech from 1 element(s) all 10 word(s) unchanged - - None - +AffixTemplate requiredPartsOfSpeech languages/suffixing-evidential-adjacency-chain Unobservable removed requiredPartsOfSpeech from 1 element(s) all 28 word(s) unchanged - - None - +AffixTemplate requiredPartsOfSpeech languages/suffixing-extension-slot-ordering Evidenced removed requiredPartsOfSpeech from 1 element(s) 'mpe': ok::PPE|mpe -> ok::- mpe ok::PPE|mpe Word ok::- +AffixTemplate requiredPartsOfSpeech languages/suffixing-vowel-harmony Evidenced removed requiredPartsOfSpeech from 1 element(s) 'gan': ok::GAN|gan -> ok::- gan ok::GAN|gan Word ok::- +Allomorph stemName edge-cases/stem-name-restricted-root-allomorph Evidenced removed stemName from 1 element(s) 'kap': ok::- -> ok::ROOT|kap kap ok::- Word ok::ROOT|kap +Allomorph stemName languages/fusional-realizational-morphology Evidenced removed stemName from 2 element(s) 'muno': ok::- -> ok::STEM+P1|muno muno ok::- Word ok::STEM+P1|muno +Allomorph stemName languages/suffixing-extension-slot-ordering Evidenced removed stemName from 1 element(s) 'daleh': ok::DAL+STEMREQ|daleh -> ok::- daleh ok::DAL+STEMREQ|daleh Word ok::- +Allomorph stemName languages/templatic-root-modification Evidenced removed stemName from 2 element(s) 'halaku': ok::- -> ok::HLK+IMPF|halaku halaku ok::- Word ok::HLK+IMPF|halaku +AllomorphCoOccurrenceRule otherAllomorphs edge-cases/morphotactic-attribute-breadth RequiredByDtd removed otherAllomorphs from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherAllom... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherAllom... +AllomorphCoOccurrenceRule otherAllomorphs languages/suffixing-evidential-adjacency-chain RequiredByDtd removed otherAllomorphs from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherAllom... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherAllom... +AllomorphCoOccurrenceRule primaryAllomorph edge-cases/morphotactic-attribute-breadth RequiredByDtd removed primaryAllomorph from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryAll... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryAll... +AllomorphCoOccurrenceRule primaryAllomorph languages/suffixing-evidential-adjacency-chain RequiredByDtd removed primaryAllomorph from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryAll... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryAll... +AlphaVariable variableFeature edge-cases/alpha-variable-name-collision RequiredByDtd removed variableFeature from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'variableFe... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'variableFe... +AlphaVariable variableFeature edge-cases/feature-system-breadth RequiredByDtd removed variableFeature from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'variableFe... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'variableFe... +AlphaVariable variableFeature languages/suffixing-vowel-harmony RequiredByDtd removed variableFeature from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'variableFe... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'variableFe... +BoundaryMarker boundary languages/metathesis-phase-isolation RequiredByDtd removed boundary from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'boundary' ... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'boundary' ... +CompoundingRule headPartsOfSpeech edge-cases/compounding-breadth Unobservable removed headPartsOfSpeech from 4 element(s) all 11 word(s) unchanged - - None - +CompoundingRule headPartsOfSpeech languages/fusional-realizational-morphology Unobservable removed headPartsOfSpeech from 3 element(s) all 63 word(s) unchanged - - None - +CompoundingRule headPartsOfSpeech languages/polysynthetic-stratal-derivation-chain Evidenced removed headPartsOfSpeech from 2 element(s) 'silaaku': ok::- -> ok::SILA+AKU|sila+?aku;SILA+AKU|sila+?aku silaaku ok::- Word ok::SILA+AKU|sila+?aku;SILA+AKU|sila+?aku +CompoundingRule headProdRestrictionsMprFeatures languages/fusional-realizational-morphology Evidenced removed headProdRestrictionsMprFeatures from 1 element(s) 'seclav': ok::- -> ok::SEC+LAV|sec+?lav seclav ok::- Word ok::SEC+LAV|sec+?lav +CompoundingRule nonHeadPartsOfSpeech edge-cases/compounding-breadth Unobservable removed nonHeadPartsOfSpeech from 4 element(s) all 11 word(s) unchanged - - None - +CompoundingRule nonHeadPartsOfSpeech languages/fusional-realizational-morphology Unobservable removed nonHeadPartsOfSpeech from 3 element(s) all 63 word(s) unchanged - - None - +CompoundingRule nonHeadPartsOfSpeech languages/polysynthetic-stratal-derivation-chain Unobservable removed nonHeadPartsOfSpeech from 2 element(s) all 24 word(s) unchanged - - None - +CompoundingRule outputObligatoryFeatures languages/fusional-realizational-morphology Unobservable removed outputObligatoryFeatures from 1 element(s) all 63 word(s) unchanged - - None - +CompoundingRule outputPartOfSpeech edge-cases/compounding-breadth Evidenced removed outputPartOfSpeech from 4 element(s) 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi katumi ok::- Word ok::KA+TU+TPLSUF|katumi +CompoundingRule outputPartOfSpeech languages/fusional-realizational-morphology Unobservable removed outputPartOfSpeech from 1 element(s) all 63 word(s) unchanged - - None - +CopyFromInput index edge-cases/compounding-breadth RequiredByDtd removed index from 9 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/deep-optional-affix-nesting RequiredByDtd removed index from 12 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... k ok::K|k LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/diacritic-segments RequiredByDtd removed index from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/disjunctive-recheck RequiredByDtd removed index from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... wak ok::|wak LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/feature-gating-breadth RequiredByDtd removed index from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/feature-system-breadth RequiredByDtd removed index from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/free-fluctuating-allomorph-pair RequiredByDtd removed index from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... pol ok::ALT|pol LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/loader-isactive-breadth RequiredByDtd removed index from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/morphotactic-attribute-breadth RequiredByDtd removed index from 18 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/mpr-gated-exception RequiredByDtd removed index from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... tulik ok::TULIK|tulik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/mpr-group-overwrite-without-realizational RequiredByDtd removed index from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... dof ok::DOF|dof LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/mpr-overwrite-order-dependence RequiredByDtd removed index from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... dabo ok::DABO|dabo LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/stem-name-restricted-root-allomorph RequiredByDtd removed index from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/strrep-identity RequiredByDtd removed index from 5 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... pat ok::+|[(^0)∅]?+?pat;|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/subrule-morphosyntactic-gating RequiredByDtd removed index from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... pat ok::ROOT1|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index edge-cases/truncate-morphotactic RequiredByDtd removed index from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... sag ok::|sag LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/fusional-realizational-morphology RequiredByDtd removed index from 28 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/metathesis-phase-isolation RequiredByDtd removed index from 15 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/polysynthetic-stratal-derivation-chain RequiredByDtd removed index from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... nuna ok::NUNA|nuna LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/prefixal-discontinuous-slot-dependency RequiredByDtd removed index from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/suffixing-evidential-adjacency-chain RequiredByDtd removed index from 13 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/suffixing-extension-slot-ordering RequiredByDtd removed index from 19 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/suffixing-vowel-harmony RequiredByDtd removed index from 7 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +CopyFromInput index languages/templatic-root-modification RequiredByDtd removed index from 9 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +FeatureValue feature edge-cases/alpha-variable-name-collision RequiredByDtd removed feature from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/compounding-breadth RequiredByDtd removed feature from 20 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/disjunctive-recheck RequiredByDtd removed feature from 13 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... wak ok::|wak LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/feature-gating-breadth RequiredByDtd removed feature from 15 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/feature-system-breadth RequiredByDtd removed feature from 27 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/free-fluctuating-allomorph-pair RequiredByDtd removed feature from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... pol ok::ALT|pol LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/loader-default-symbol RequiredByDtd removed feature from 14 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... bat ok::|bat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/loader-isactive RequiredByDtd removed feature from 9 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/metathesis-comparison-crash RequiredByDtd removed feature from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/morphotactic-attribute-breadth RequiredByDtd removed feature from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/mpr-gated-exception RequiredByDtd removed feature from 110 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... tulik ok::TULIK|tulik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/process-morphology-in-place-mutation RequiredByDtd removed feature from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... i ok::ROOT|i LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/right-to-left-anchor-environment RequiredByDtd removed feature from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... aae ok::ROOT1|aae LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/simultaneous-epenthesis-cascade RequiredByDtd removed feature from 23 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... bubu threw::InfiniteLoopException LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/stem-name-restricted-root-allomorph RequiredByDtd removed feature from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/subrule-morphosyntactic-gating RequiredByDtd removed feature from 16 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... pat ok::ROOT1|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature edge-cases/truncate-morphotactic RequiredByDtd removed feature from 19 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... sag ok::|sag LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature languages/fusional-realizational-morphology RequiredByDtd removed feature from 43 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature languages/metathesis-phase-isolation RequiredByDtd removed feature from 140 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature languages/polysynthetic-stratal-derivation-chain RequiredByDtd removed feature from 121 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... nuna ok::NUNA|nuna LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature languages/suffixing-extension-slot-ordering RequiredByDtd removed feature from 131 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature languages/suffixing-vowel-harmony RequiredByDtd removed feature from 116 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue feature languages/templatic-root-modification RequiredByDtd removed feature from 127 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'feature' i... +FeatureValue symbolValues edge-cases/alpha-variable-name-collision RequiredByLoader removed symbolValues from 8 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/compounding-breadth RequiredByLoader removed symbolValues from 20 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/disjunctive-recheck RequiredByLoader removed symbolValues from 13 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... wak ok::|wak LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/feature-gating-breadth RequiredByLoader removed symbolValues from 15 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/feature-system-breadth RequiredByLoader removed symbolValues from 25 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/free-fluctuating-allomorph-pair RequiredByLoader removed symbolValues from 8 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... pol ok::ALT|pol LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/loader-default-symbol RequiredByLoader removed symbolValues from 14 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... bat ok::|bat LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/loader-isactive RequiredByLoader removed symbolValues from 9 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/metathesis-comparison-crash RequiredByLoader removed symbolValues from 2 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/morphotactic-attribute-breadth RequiredByLoader removed symbolValues from 4 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/mpr-gated-exception RequiredByLoader removed symbolValues from 110 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... tulik ok::TULIK|tulik LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/process-morphology-in-place-mutation RequiredByLoader removed symbolValues from 6 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... i ok::ROOT|i LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/right-to-left-anchor-environment RequiredByLoader removed symbolValues from 2 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... aae ok::ROOT1|aae LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/simultaneous-epenthesis-cascade RequiredByLoader removed symbolValues from 23 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... bubu threw::InfiniteLoopException LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/stem-name-restricted-root-allomorph RequiredByLoader removed symbolValues from 3 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/subrule-morphosyntactic-gating RequiredByLoader removed symbolValues from 16 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... pat ok::ROOT1|pat LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues edge-cases/truncate-morphotactic RequiredByLoader removed symbolValues from 19 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... sag ok::|sag LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues languages/fusional-realizational-morphology RequiredByLoader removed symbolValues from 43 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues languages/metathesis-phase-isolation RequiredByLoader removed symbolValues from 140 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues languages/polysynthetic-stratal-derivation-chain RequiredByLoader removed symbolValues from 121 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... nuna ok::NUNA|nuna LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues languages/suffixing-extension-slot-ordering RequiredByLoader removed symbolValues from 131 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues languages/suffixing-vowel-harmony RequiredByLoader removed symbolValues from 116 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +FeatureValue symbolValues languages/templatic-root-modification RequiredByLoader removed symbolValues from 127 element(s) InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.InvalidCastException: Unable to cast object of type 'SIL.Machine.... +HeadMorphologicalInput excludedMPRFeatures languages/fusional-realizational-morphology Unobservable removed excludedMPRFeatures from 1 element(s) all 63 word(s) unchanged - - None - +HeadMorphologicalInput requiredMPRFeatures languages/fusional-realizational-morphology Unobservable removed requiredMPRFeatures from 1 element(s) all 63 word(s) unchanged - - None - +LexicalEntry family edge-cases/loader-isactive-breadth Unobservable removed family from 2 element(s) all 18 word(s) unchanged - - None - +LexicalEntry family edge-cases/morphotactic-attribute-breadth Unobservable removed family from 4 element(s) all 33 word(s) unchanged - - None - +LexicalEntry family languages/fusional-realizational-morphology Evidenced removed family from 6 element(s) 'ducit': ok::- -> ok::DUC+PAST2|ducit ducit ok::- Word ok::DUC+PAST2|ducit +LexicalEntry family languages/suffixing-extension-slot-ordering Evidenced removed family from 2 element(s) 'zamed': ok::- -> ok::ZAM+RREALTEST|zamed zamed ok::- Word ok::ZAM+RREALTEST|zamed +LexicalEntry partOfSpeech edge-cases/alpha-variable-name-collision Unobservable removed partOfSpeech from 1 element(s) all 2 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/compounding-breadth Unobservable removed partOfSpeech from 6 element(s) all 11 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/deep-optional-affix-nesting Unobservable removed partOfSpeech from 1 element(s) all 3 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/diacritic-segments Unobservable removed partOfSpeech from 4 element(s) all 13 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/disjunctive-recheck Unobservable removed partOfSpeech from 4 element(s) all 12 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/feature-gating-breadth Unobservable removed partOfSpeech from 4 element(s) all 15 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/feature-system-breadth Unobservable removed partOfSpeech from 10 element(s) all 18 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/free-fluctuating-allomorph-pair Unobservable removed partOfSpeech from 2 element(s) all 6 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/loader-default-symbol Unobservable removed partOfSpeech from 2 element(s) all 2 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/loader-isactive Unobservable removed partOfSpeech from 2 element(s) all 2 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/loader-isactive-breadth Unobservable removed partOfSpeech from 6 element(s) all 18 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/loader-pattern-shapes Unobservable removed partOfSpeech from 2 element(s) all 4 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/metathesis-comparison-crash Unobservable removed partOfSpeech from 1 element(s) all 1 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/morphotactic-attribute-breadth Unobservable removed partOfSpeech from 9 element(s) all 33 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/mpr-gated-exception Unobservable removed partOfSpeech from 5 element(s) all 12 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/mpr-group-overwrite-without-realizational Unobservable removed partOfSpeech from 1 element(s) all 5 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/mpr-overwrite-order-dependence Unobservable removed partOfSpeech from 2 element(s) all 10 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/process-morphology-in-place-mutation Unobservable removed partOfSpeech from 3 element(s) all 3 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/simultaneous-epenthesis-cascade Unobservable removed partOfSpeech from 1 element(s) all 1 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/stem-name-restricted-root-allomorph Unobservable removed partOfSpeech from 1 element(s) all 6 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/strrep-identity Unobservable removed partOfSpeech from 3 element(s) all 12 word(s) unchanged - - None - +LexicalEntry partOfSpeech edge-cases/subrule-morphosyntactic-gating Evidenced removed partOfSpeech from 1 element(s) 'pat': ok::ROOT1|pat -> ok::- pat ok::ROOT1|pat Word ok::- +LexicalEntry partOfSpeech edge-cases/truncate-morphotactic Unobservable removed partOfSpeech from 3 element(s) all 9 word(s) unchanged - - None - +LexicalEntry partOfSpeech languages/fusional-realizational-morphology Evidenced removed partOfSpeech from 27 element(s) 'mint': ok::STEM+P3|mint -> ok::MIT+PRESSTEM|mint;STEM+P3|mint mint ok::STEM+P3|mint Word ok::MIT+PRESSTEM|mint;STEM+P3|mint +LexicalEntry partOfSpeech languages/metathesis-phase-isolation Evidenced removed partOfSpeech from 9 element(s) 'idil': ok::- -> ok::ADIL|idil idil ok::- Word ok::ADIL|idil +LexicalEntry partOfSpeech languages/polysynthetic-stratal-derivation-chain Evidenced removed partOfSpeech from 15 element(s) 'nunavuq': ok::- -> ok::NUNA+INFL|nunavuq nunavuq ok::- Word ok::NUNA+INFL|nunavuq +LexicalEntry partOfSpeech languages/prefixal-discontinuous-slot-dependency Unobservable removed partOfSpeech from 2 element(s) all 10 word(s) unchanged - - None - +LexicalEntry partOfSpeech languages/suffixing-evidential-adjacency-chain Unobservable removed partOfSpeech from 5 element(s) all 28 word(s) unchanged - - None - +LexicalEntry partOfSpeech languages/suffixing-extension-slot-ordering Evidenced removed partOfSpeech from 19 element(s) 'mpe': ok::PPE|mpe -> ok::- mpe ok::PPE|mpe Word ok::- +LexicalEntry partOfSpeech languages/suffixing-vowel-harmony Evidenced removed partOfSpeech from 11 element(s) 'gan': ok::GAN|gan -> ok::- gan ok::GAN|gan Word ok::- +LexicalEntry partOfSpeech languages/templatic-root-modification Evidenced removed partOfSpeech from 9 element(s) 'kataba': ok::KTB+P3SG|kataba -> ok::KTB+JUSS|kataba;KTB+P3SG|kataba kataba ok::KTB+P3SG|kataba Word ok::KTB+JUSS|kataba;KTB+P3SG|kataba +LexicalEntry ruleFeatures edge-cases/loader-isactive-breadth Unobservable removed ruleFeatures from 2 element(s) all 18 word(s) unchanged - - None - +LexicalEntry ruleFeatures edge-cases/morphotactic-attribute-breadth Unobservable removed ruleFeatures from 1 element(s) all 33 word(s) unchanged - - None - +LexicalEntry ruleFeatures edge-cases/mpr-gated-exception Evidenced removed ruleFeatures from 1 element(s) 'vokadan': ok::- -> ok::VOKAD+SUF|vokadan vokadan ok::- Word ok::VOKAD+SUF|vokadan +LexicalEntry ruleFeatures languages/fusional-realizational-morphology Evidenced removed ruleFeatures from 6 element(s) 'gofz': ok::GOF+ENDZ|gofz -> ok::- gofz ok::GOF+ENDZ|gofz Word ok::- +LexicalEntry ruleFeatures languages/prefixal-discontinuous-slot-dependency Evidenced removed ruleFeatures from 2 element(s) 'shiyidkal': ok::SBJ+PRF+CLF+KAL|shiyidkal -> ok::- shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal Word ok::- +LexicalEntry ruleFeatures languages/suffixing-extension-slot-ordering Evidenced removed ruleFeatures from 7 element(s) 'mbe': ok::- -> ok::PPE|mbe mbe ok::- Word ok::PPE|mbe +MetathesisRule leftSwitch edge-cases/feature-system-breadth RequiredByDtd removed leftSwitch from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'leftSwitch... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'leftSwitch... +MetathesisRule leftSwitch edge-cases/metathesis-comparison-crash RequiredByDtd removed leftSwitch from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'leftSwitch... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'leftSwitch... +MetathesisRule leftSwitch languages/metathesis-phase-isolation RequiredByDtd removed leftSwitch from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'leftSwitch... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'leftSwitch... +MetathesisRule rightSwitch edge-cases/feature-system-breadth RequiredByDtd removed rightSwitch from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'rightSwitc... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'rightSwitc... +MetathesisRule rightSwitch edge-cases/metathesis-comparison-crash RequiredByDtd removed rightSwitch from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'rightSwitc... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'rightSwitc... +MetathesisRule rightSwitch languages/metathesis-phase-isolation RequiredByDtd removed rightSwitch from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'rightSwitc... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'rightSwitc... +ModifyFromInput index edge-cases/process-morphology-in-place-mutation RequiredByDtd removed index from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... i ok::ROOT|i LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +ModifyFromInput index languages/fusional-realizational-morphology RequiredByDtd removed index from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +ModifyFromInput index languages/templatic-root-modification RequiredByDtd removed index from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'index' is ... +MorphemeCoOccurrenceRule otherMorphemes edge-cases/morphotactic-attribute-breadth RequiredByDtd removed otherMorphemes from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherMorph... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherMorph... +MorphemeCoOccurrenceRule otherMorphemes languages/suffixing-evidential-adjacency-chain RequiredByDtd removed otherMorphemes from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherMorph... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherMorph... +MorphemeCoOccurrenceRule otherMorphemes languages/templatic-root-modification RequiredByDtd removed otherMorphemes from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherMorph... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'otherMorph... +MorphemeCoOccurrenceRule primaryMorpheme edge-cases/morphotactic-attribute-breadth RequiredByDtd removed primaryMorpheme from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryMor... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryMor... +MorphemeCoOccurrenceRule primaryMorpheme languages/suffixing-evidential-adjacency-chain RequiredByDtd removed primaryMorpheme from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryMor... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryMor... +MorphemeCoOccurrenceRule primaryMorpheme languages/templatic-root-modification RequiredByDtd removed primaryMorpheme from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryMor... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'primaryMor... +MorphologicalInput excludedMPRFeatures edge-cases/morphotactic-attribute-breadth Evidenced removed excludedMPRFeatures from 1 element(s) 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori topdori ok::- Word ok::TOP+CONFEREXCL+EXCLREADER|topdori +MorphologicalInput excludedMPRFeatures edge-cases/mpr-gated-exception Evidenced removed excludedMPRFeatures from 1 element(s) 'vokadan': ok::- -> ok::VOKAD+SUF|vokadan vokadan ok::- Word ok::VOKAD+SUF|vokadan +MorphologicalInput requiredMPRFeatures edge-cases/morphotactic-attribute-breadth Unobservable removed requiredMPRFeatures from 1 element(s) all 33 word(s) unchanged - - None - +MorphologicalInput requiredMPRFeatures edge-cases/mpr-group-overwrite-without-realizational Evidenced removed requiredMPRFeatures from 1 element(s) 'wudofq': ok::- -> ok::THEMEB+THEMEA+DOF+ENDC|wudofq wudofq ok::- Word ok::THEMEB+THEMEA+DOF+ENDC|wudofq +MorphologicalInput requiredMPRFeatures edge-cases/mpr-overwrite-order-dependence Evidenced removed requiredMPRFeatures from 2 element(s) 'daboxayuzi': ok::- -> ok::DABO+SETX+SETY+GATEX|daboxayuzi daboxayuzi ok::- Word ok::DABO+SETX+SETY+GATEX|daboxayuzi +MorphologicalInput requiredMPRFeatures languages/fusional-realizational-morphology Evidenced removed requiredMPRFeatures from 3 element(s) 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz ygofz ok::- Word ok::THEMEY+GOF+ENDZ|ygofz +MorphologicalInput requiredMPRFeatures languages/prefixal-discontinuous-slot-dependency Evidenced removed requiredMPRFeatures from 3 element(s) 'bishiwodkal': ok::- -> ok::OBJ+SBJ+IMPF+CLF+KAL|bishiwodkal bishiwodkal ok::- Word ok::OBJ+SBJ+IMPF+CLF+KAL|bishiwodkal +MorphologicalInput requiredMPRFeatures languages/suffixing-extension-slot-ordering RequiredByLoader removed requiredMPRFeatures from 4 element(s) InvalidOperationException: Stack overflow. at SIL.Machine.Morphology.HermitCrab.Word.MarkMorph(System.Collections.Gen... mbe ok::- LoadFailure InvalidOperationException: Stack overflow. at SIL.Machine.Morphology.HermitCrab.Word.MarkMorph(System.Collections.Gen... +MorphologicalOutput MPRFeatures edge-cases/morphotactic-attribute-breadth Evidenced removed MPRFeatures from 4 element(s) 'topdori': ok::- -> ok::TOP+CONFEREXCL+EXCLREADER|topdori topdori ok::- Word ok::TOP+CONFEREXCL+EXCLREADER|topdori +MorphologicalOutput MPRFeatures edge-cases/mpr-gated-exception Evidenced removed MPRFeatures from 1 element(s) 'menanukam': ok::- -> ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam menanukam ok::- Word ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam +MorphologicalOutput MPRFeatures edge-cases/mpr-group-overwrite-without-realizational Evidenced removed MPRFeatures from 2 element(s) 'udofq': ok::THEMEA+DOF+ENDC|udofq -> ok::- udofq ok::THEMEA+DOF+ENDC|udofq Word ok::- +MorphologicalOutput MPRFeatures edge-cases/mpr-overwrite-order-dependence Evidenced removed MPRFeatures from 4 element(s) 'daboyuxazi': ok::DABO+SETY+SETX+GATEX|daboyuxazi -> ok::- daboyuxazi ok::DABO+SETY+SETX+GATEX|daboyuxazi Word ok::- +MorphologicalOutput MPRFeatures languages/fusional-realizational-morphology Evidenced removed MPRFeatures from 5 element(s) 'ygofz': ok::- -> ok::THEMEY+GOF+ENDZ|ygofz ygofz ok::- Word ok::THEMEY+GOF+ENDZ|ygofz +MorphologicalOutput MPRFeatures languages/prefixal-discontinuous-slot-dependency Evidenced removed MPRFeatures from 1 element(s) 'bishiyidkal': ok::OBJ+SBJ+PRF+CLF+KAL|bishiyidkal -> ok::- bishiyidkal ok::OBJ+SBJ+PRF+CLF+KAL|bishiyidkal Word ok::- +MorphologicalOutput MPRFeatures languages/suffixing-extension-slot-ordering Evidenced removed MPRFeatures from 4 element(s) 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael nbael ok::- Word ok::PPO+PHDESTROY|nbael +MorphologicalPhonologicalRuleFeatureGroup features edge-cases/morphotactic-attribute-breadth RequiredByDtd removed features from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... +MorphologicalPhonologicalRuleFeatureGroup features edge-cases/mpr-group-overwrite-without-realizational RequiredByDtd removed features from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... dof ok::DOF|dof LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... +MorphologicalPhonologicalRuleFeatureGroup features edge-cases/mpr-overwrite-order-dependence RequiredByDtd removed features from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... dabo ok::DABO|dabo LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... +MorphologicalPhonologicalRuleFeatureGroup features languages/fusional-realizational-morphology RequiredByDtd removed features from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... +MorphologicalPhonologicalRuleFeatureGroup features languages/suffixing-extension-slot-ordering RequiredByDtd removed features from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'features' ... +MorphologicalRule outputObligatoryFeatures languages/suffixing-extension-slot-ordering Unobservable removed outputObligatoryFeatures from 1 element(s) all 53 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/compounding-breadth Unobservable removed outputPartOfSpeech from 1 element(s) all 11 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/deep-optional-affix-nesting Unobservable removed outputPartOfSpeech from 12 element(s) all 3 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/diacritic-segments Unobservable removed outputPartOfSpeech from 2 element(s) all 13 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/disjunctive-recheck Unobservable removed outputPartOfSpeech from 2 element(s) all 12 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/feature-gating-breadth Unobservable removed outputPartOfSpeech from 3 element(s) all 15 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/feature-system-breadth Unobservable removed outputPartOfSpeech from 1 element(s) all 18 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/free-fluctuating-allomorph-pair Unobservable removed outputPartOfSpeech from 1 element(s) all 6 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/loader-isactive-breadth Unobservable removed outputPartOfSpeech from 6 element(s) all 18 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/morphotactic-attribute-breadth Unobservable removed outputPartOfSpeech from 16 element(s) all 33 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/mpr-gated-exception Unobservable removed outputPartOfSpeech from 4 element(s) all 12 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/mpr-group-overwrite-without-realizational Unobservable removed outputPartOfSpeech from 3 element(s) all 5 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/mpr-overwrite-order-dependence Unobservable removed outputPartOfSpeech from 6 element(s) all 10 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/process-morphology-in-place-mutation Unobservable removed outputPartOfSpeech from 1 element(s) all 3 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/stem-name-restricted-root-allomorph Unobservable removed outputPartOfSpeech from 2 element(s) all 6 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/strrep-identity Unobservable removed outputPartOfSpeech from 2 element(s) all 12 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech edge-cases/subrule-morphosyntactic-gating Evidenced removed outputPartOfSpeech from 1 element(s) 'pat': ok::ROOT1|pat -> ok::ROOT1+DERIVE|pat;ROOT1|pat pat ok::ROOT1|pat Word ok::ROOT1+DERIVE|pat;ROOT1|pat +MorphologicalRule outputPartOfSpeech languages/fusional-realizational-morphology Unobservable removed outputPartOfSpeech from 17 element(s) all 63 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech languages/metathesis-phase-isolation Unobservable removed outputPartOfSpeech from 9 element(s) all 20 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech languages/polysynthetic-stratal-derivation-chain Evidenced removed outputPartOfSpeech from 4 element(s) 'nunaliqvuq': ok::NUNA+DERIV+INFL|nunaliqvuq -> ok::- nunaliqvuq ok::NUNA+DERIV+INFL|nunaliqvuq Word ok::- +MorphologicalRule outputPartOfSpeech languages/prefixal-discontinuous-slot-dependency Unobservable removed outputPartOfSpeech from 7 element(s) all 10 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech languages/suffixing-evidential-adjacency-chain Unobservable removed outputPartOfSpeech from 11 element(s) all 28 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech languages/suffixing-extension-slot-ordering Unobservable removed outputPartOfSpeech from 16 element(s) all 53 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech languages/suffixing-vowel-harmony Unobservable removed outputPartOfSpeech from 6 element(s) all 27 word(s) unchanged - - None - +MorphologicalRule outputPartOfSpeech languages/templatic-root-modification Unobservable removed outputPartOfSpeech from 7 element(s) all 25 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/compounding-breadth Evidenced removed requiredPartsOfSpeech from 1 element(s) 'katumi': ok::- -> ok::KA+TU+TPLSUF|katumi katumi ok::- Word ok::KA+TU+TPLSUF|katumi +MorphologicalRule requiredPartsOfSpeech edge-cases/deep-optional-affix-nesting Unobservable removed requiredPartsOfSpeech from 12 element(s) all 3 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/diacritic-segments Unobservable removed requiredPartsOfSpeech from 2 element(s) all 13 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/disjunctive-recheck Unobservable removed requiredPartsOfSpeech from 2 element(s) all 12 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/feature-gating-breadth Unobservable removed requiredPartsOfSpeech from 3 element(s) all 15 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/feature-system-breadth Unobservable removed requiredPartsOfSpeech from 1 element(s) all 18 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/free-fluctuating-allomorph-pair Unobservable removed requiredPartsOfSpeech from 1 element(s) all 6 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/loader-isactive-breadth Unobservable removed requiredPartsOfSpeech from 6 element(s) all 18 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/morphotactic-attribute-breadth Unobservable removed requiredPartsOfSpeech from 16 element(s) all 33 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/mpr-gated-exception Unobservable removed requiredPartsOfSpeech from 4 element(s) all 12 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/mpr-group-overwrite-without-realizational Unobservable removed requiredPartsOfSpeech from 3 element(s) all 5 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/mpr-overwrite-order-dependence Unobservable removed requiredPartsOfSpeech from 6 element(s) all 10 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/process-morphology-in-place-mutation Unobservable removed requiredPartsOfSpeech from 1 element(s) all 3 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/stem-name-restricted-root-allomorph Unobservable removed requiredPartsOfSpeech from 2 element(s) all 6 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/strrep-identity Unobservable removed requiredPartsOfSpeech from 2 element(s) all 12 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech edge-cases/truncate-morphotactic Unobservable removed requiredPartsOfSpeech from 3 element(s) all 9 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech languages/fusional-realizational-morphology Evidenced removed requiredPartsOfSpeech from 17 element(s) 'mano': ok::STEM+P1|mano -> ok::STEM+ABLAUT+P1|mano;STEM+P1|mano mano ok::STEM+P1|mano Word ok::STEM+ABLAUT+P1|mano;STEM+P1|mano +MorphologicalRule requiredPartsOfSpeech languages/metathesis-phase-isolation Unobservable removed requiredPartsOfSpeech from 9 element(s) all 20 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech languages/polysynthetic-stratal-derivation-chain Evidenced removed requiredPartsOfSpeech from 4 element(s) 'nunavuq': ok::- -> ok::NUNA+INFL|nunavuq nunavuq ok::- Word ok::NUNA+INFL|nunavuq +MorphologicalRule requiredPartsOfSpeech languages/prefixal-discontinuous-slot-dependency Unobservable removed requiredPartsOfSpeech from 7 element(s) all 10 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech languages/suffixing-evidential-adjacency-chain Unobservable removed requiredPartsOfSpeech from 11 element(s) all 28 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech languages/suffixing-extension-slot-ordering Evidenced removed requiredPartsOfSpeech from 16 element(s) 'lisez': ok::PHXROOT+PHXSRC|lisez -> ok::PHXROOT+AGR|lisez;PHXROOT+PHXSRC|lisez lisez ok::PHXROOT+PHXSRC|lisez Word ok::PHXROOT+AGR|lisez;PHXROOT+PHXSRC|lisez +MorphologicalRule requiredPartsOfSpeech languages/suffixing-vowel-harmony Unobservable removed requiredPartsOfSpeech from 6 element(s) all 27 word(s) unchanged - - None - +MorphologicalRule requiredPartsOfSpeech languages/templatic-root-modification Evidenced removed requiredPartsOfSpeech from 7 element(s) 'katabit': ok::KTB+P1SG|katabit -> ok::KTB+JUSS+PASS+P1SG|katabit;KTB+JUSS+PASS+P1SG|katabit;KTB+P1SG|katabit;KTB+P3SG+PASS+P1SG|katabit;KTB+P3SG+PASS+P1SG|katabit;KTB+PERF+P1SG|katabit katabit ok::KTB+P1SG|katabit Word ok::KTB+JUSS+PASS+P1SG|katabit;KTB+JUSS+PASS+P1SG|katabit;KTB+P1SG|katabit;KTB+P3SG+PASS+P1SG|katabit;KTB+P3SG+PASS+P1SG|katabit;KTB+PERF+P1SG|katabit +MorphologicalRule requiredStemName languages/suffixing-extension-slot-ordering Evidenced removed requiredStemName from 1 element(s) 'daheh': ok::- -> ok::DAH+STEMREQ|daheh daheh ok::- Word ok::DAH+STEMREQ|daheh +PhonologicalSubrule excludedMPRFeatures edge-cases/mpr-gated-exception Evidenced removed excludedMPRFeatures from 1 element(s) 'menanukam': ok::- -> ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam menanukam ok::- Word ok::NPFX+TANUK+DELEXCLSRC|menanukam;NPFX+TANUK+DELEXCLSRC|menanukam +PhonologicalSubrule excludedMPRFeatures languages/suffixing-extension-slot-ordering Evidenced removed excludedMPRFeatures from 1 element(s) 'mbe': ok::- -> ok::PPE|mbe mbe ok::- Word ok::PPE|mbe +PhonologicalSubrule requiredMPRFeatures languages/suffixing-extension-slot-ordering Evidenced removed requiredMPRFeatures from 1 element(s) 'nbael': ok::- -> ok::PPO+PHDESTROY|nbael nbael ok::- Word ok::PPO+PHDESTROY|nbael +PhonologicalSubrule requiredPartsOfSpeech edge-cases/mpr-gated-exception Unobservable removed requiredPartsOfSpeech from 3 element(s) all 12 word(s) unchanged - - None - +PhonologicalSubrule requiredPartsOfSpeech edge-cases/subrule-morphosyntactic-gating Evidenced removed requiredPartsOfSpeech from 1 element(s) 'pat': ok::ROOT1|pat -> ok::- pat ok::ROOT1|pat Word ok::- +PhonologicalSubrule requiredPartsOfSpeech languages/metathesis-phase-isolation Evidenced removed requiredPartsOfSpeech from 1 element(s) 'idil': ok::- -> ok::ADIL|idil idil ok::- Word ok::ADIL|idil +PhonologicalSubrule requiredPartsOfSpeech languages/polysynthetic-stratal-derivation-chain Evidenced removed requiredPartsOfSpeech from 4 element(s) 'kuuukuuu': ok::MS|kuuukuuu -> ok::- kuuukuuu ok::MS|kuuukuuu Word ok::- +PhonologicalSubrule requiredPartsOfSpeech languages/suffixing-extension-slot-ordering Evidenced removed requiredPartsOfSpeech from 3 element(s) 'mbe': ok::- -> ok::PPE|mbe mbe ok::- Word ok::PPE|mbe +PhonologicalSubrule requiredPartsOfSpeech languages/suffixing-vowel-harmony Evidenced removed requiredPartsOfSpeech from 1 element(s) 'kutagida': ok::KUTAK+PAST|kutagida -> ok::- kutagida ok::KUTAK+PAST|kutagida Word ok::- +PhonologicalSubrule requiredPartsOfSpeech languages/templatic-root-modification Evidenced removed requiredPartsOfSpeech from 5 element(s) 'spr': ok::SPR|spr -> ok::- spr ok::SPR|spr Word ok::- +Segment segment edge-cases/alpha-variable-name-collision RequiredByDtd removed segment from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/diacritic-segments RequiredByDtd removed segment from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/disjunctive-recheck RequiredByDtd removed segment from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... wak ok::|wak LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/feature-system-breadth RequiredByDtd removed segment from 20 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/free-fluctuating-allomorph-pair RequiredByDtd removed segment from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... pol ok::ALT|pol LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/loader-pattern-shapes RequiredByDtd removed segment from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... bat ok::|b[ae]t LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/metathesis-comparison-crash RequiredByDtd removed segment from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/mpr-gated-exception RequiredByDtd removed segment from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... tulik ok::TULIK|tulik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/right-to-left-anchor-environment RequiredByDtd removed segment from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... aae ok::ROOT1|aae LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/strrep-identity RequiredByDtd removed segment from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... pat ok::+|[(^0)∅]?+?pat;|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/subrule-morphosyntactic-gating RequiredByDtd removed segment from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... pat ok::ROOT1|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment edge-cases/truncate-morphotactic RequiredByDtd removed segment from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... sag ok::|sag LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment languages/metathesis-phase-isolation RequiredByDtd removed segment from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment languages/polysynthetic-stratal-derivation-chain RequiredByDtd removed segment from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... nuna ok::NUNA|nuna LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment languages/suffixing-evidential-adjacency-chain RequiredByDtd removed segment from 14 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment languages/suffixing-vowel-harmony RequiredByDtd removed segment from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +Segment segment languages/templatic-root-modification RequiredByDtd removed segment from 5 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'segment' i... +SimpleContext naturalClass edge-cases/alpha-variable-name-collision RequiredByDtd removed naturalClass from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/compounding-breadth RequiredByDtd removed naturalClass from 13 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/deep-optional-affix-nesting RequiredByDtd removed naturalClass from 12 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... k ok::K|k LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/diacritic-segments RequiredByDtd removed naturalClass from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/disjunctive-recheck RequiredByDtd removed naturalClass from 5 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... wak ok::|wak LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/feature-gating-breadth RequiredByDtd removed naturalClass from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/feature-system-breadth RequiredByDtd removed naturalClass from 20 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/free-fluctuating-allomorph-pair RequiredByDtd removed naturalClass from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... pol ok::ALT|pol LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/loader-default-symbol RequiredByDtd removed naturalClass from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... bat ok::|bat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/loader-isactive-breadth RequiredByDtd removed naturalClass from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/metathesis-comparison-crash RequiredByDtd removed naturalClass from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/morphotactic-attribute-breadth RequiredByDtd removed naturalClass from 18 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/mpr-gated-exception RequiredByDtd removed naturalClass from 10 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... tulik ok::TULIK|tulik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/mpr-group-overwrite-without-realizational RequiredByDtd removed naturalClass from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... dof ok::DOF|dof LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/mpr-overwrite-order-dependence RequiredByDtd removed naturalClass from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... dabo ok::DABO|dabo LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/process-morphology-in-place-mutation RequiredByDtd removed naturalClass from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... i ok::ROOT|i LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/right-to-left-anchor-environment RequiredByDtd removed naturalClass from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... aae ok::ROOT1|aae LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/simultaneous-epenthesis-cascade RequiredByDtd removed naturalClass from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... bubu threw::InfiniteLoopException LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/stem-name-restricted-root-allomorph RequiredByDtd removed naturalClass from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/strrep-identity RequiredByDtd removed naturalClass from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... pat ok::+|[(^0)∅]?+?pat;|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/subrule-morphosyntactic-gating RequiredByDtd removed naturalClass from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... pat ok::ROOT1|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass edge-cases/truncate-morphotactic RequiredByDtd removed naturalClass from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... sag ok::|sag LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/fusional-realizational-morphology RequiredByDtd removed naturalClass from 31 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/metathesis-phase-isolation RequiredByDtd removed naturalClass from 21 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/polysynthetic-stratal-derivation-chain RequiredByDtd removed naturalClass from 22 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... nuna ok::NUNA|nuna LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/prefixal-discontinuous-slot-dependency RequiredByDtd removed naturalClass from 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/suffixing-evidential-adjacency-chain RequiredByDtd removed naturalClass from 15 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/suffixing-extension-slot-ordering RequiredByDtd removed naturalClass from 27 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/suffixing-vowel-harmony RequiredByDtd removed naturalClass from 29 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +SimpleContext naturalClass languages/templatic-root-modification RequiredByDtd removed naturalClass from 25 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'naturalCla... +Slot morphologicalRules edge-cases/deep-optional-affix-nesting RequiredByDtd removed morphologicalRules from 12 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... k ok::K|k LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules edge-cases/diacritic-segments RequiredByDtd removed morphologicalRules from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules edge-cases/loader-isactive-breadth RequiredByDtd removed morphologicalRules from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules edge-cases/morphotactic-attribute-breadth RequiredByDtd removed morphologicalRules from 13 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules languages/prefixal-discontinuous-slot-dependency RequiredByDtd removed morphologicalRules from 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules languages/suffixing-evidential-adjacency-chain RequiredByDtd removed morphologicalRules from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules languages/suffixing-extension-slot-ordering RequiredByDtd removed morphologicalRules from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +Slot morphologicalRules languages/suffixing-vowel-harmony RequiredByDtd removed morphologicalRules from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'morphologi... +StemName partsOfSpeech edge-cases/stem-name-restricted-root-allomorph RequiredByDtd removed partsOfSpeech from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... +StemName partsOfSpeech languages/fusional-realizational-morphology RequiredByDtd removed partsOfSpeech from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... +StemName partsOfSpeech languages/suffixing-extension-slot-ordering RequiredByDtd removed partsOfSpeech from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... +StemName partsOfSpeech languages/templatic-root-modification RequiredByDtd removed partsOfSpeech from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'partsOfSpe... +Stratum characterDefinitionTable edge-cases/alpha-variable-name-collision RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/bistratal-overlapping-segment-representation RequiredByDtd removed characterDefinitionTable from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... des ok::ROOT3|des LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/compounding-breadth RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/deep-optional-affix-nesting RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... k ok::K|k LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/diacritic-segments RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/disjunctive-recheck RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... wak ok::|wak LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/feature-gating-breadth RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/feature-system-breadth RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/free-fluctuating-allomorph-pair RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... pol ok::ALT|pol LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/loader-default-symbol RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... bat ok::|bat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/loader-isactive RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/loader-isactive-breadth RequiredByDtd removed characterDefinitionTable from 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/loader-pattern-shapes RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... bat ok::|b[ae]t LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/metathesis-comparison-crash RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... ti ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/morphotactic-attribute-breadth RequiredByDtd removed characterDefinitionTable from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... topdori ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/mpr-gated-exception RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... tulik ok::TULIK|tulik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/mpr-group-overwrite-without-realizational RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... dof ok::DOF|dof LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/mpr-overwrite-order-dependence RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... dabo ok::DABO|dabo LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/process-morphology-in-place-mutation RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... i ok::ROOT|i LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/right-to-left-anchor-environment RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... aae ok::ROOT1|aae LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/simultaneous-epenthesis-cascade RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... bubu threw::InfiniteLoopException LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/stem-name-restricted-root-allomorph RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/strrep-identity RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... pat ok::+|[(^0)∅]?+?pat;|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/subrule-morphosyntactic-gating RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... pat ok::ROOT1|pat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable edge-cases/truncate-morphotactic RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... sag ok::|sag LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/fusional-realizational-morphology RequiredByDtd removed characterDefinitionTable from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... mun ok::STEM|mun LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/metathesis-phase-isolation RequiredByDtd removed characterDefinitionTable from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... idil ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/polysynthetic-stratal-derivation-chain RequiredByDtd removed characterDefinitionTable from 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... nuna ok::NUNA|nuna LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/prefixal-discontinuous-slot-dependency RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/suffixing-evidential-adjacency-chain RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... tupay ok::TUPA+1SG|tupay;TUPA2+1SG|tupay LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/suffixing-extension-slot-ordering RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... mbe ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/suffixing-vowel-harmony RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum characterDefinitionTable languages/templatic-root-modification RequiredByDtd removed characterDefinitionTable from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... katab ok::KTB|katab LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'characterD... +Stratum morphologicalRules edge-cases/compounding-breadth Evidenced removed morphologicalRules from 1 element(s) 'katu': ok::KA+TU|katu -> ok::- katu ok::KA+TU|katu Word ok::- +Stratum morphologicalRules edge-cases/diacritic-segments Unobservable removed morphologicalRules from 1 element(s) all 13 word(s) unchanged - - None - +Stratum morphologicalRules edge-cases/disjunctive-recheck Evidenced removed morphologicalRules from 1 element(s) 'wokta': ok::+|wokta -> ok::- wokta ok::+|wokta Word ok::- +Stratum morphologicalRules edge-cases/feature-gating-breadth Evidenced removed morphologicalRules from 1 element(s) 'kalka': ok::KAL+AGR|kalka -> ok::- kalka ok::KAL+AGR|kalka Word ok::- +Stratum morphologicalRules edge-cases/feature-system-breadth Evidenced removed morphologicalRules from 1 element(s) 'ikt': ok::TI+SUF|ikt;TIK|ikt -> ok::TIK|ikt ikt ok::TI+SUF|ikt;TIK|ikt Word ok::TIK|ikt +Stratum morphologicalRules edge-cases/free-fluctuating-allomorph-pair Evidenced removed morphologicalRules from 1 element(s) 'kits': ok::ORD+SSFX|kits -> ok::- kits ok::ORD+SSFX|kits Word ok::- +Stratum morphologicalRules edge-cases/morphotactic-attribute-breadth Evidenced removed morphologicalRules from 2 element(s) 'topdo': ok::TOP+CONFEREXCL|topdo -> ok::- topdo ok::TOP+CONFEREXCL|topdo Word ok::- +Stratum morphologicalRules edge-cases/mpr-gated-exception Evidenced removed morphologicalRules from 1 element(s) 'menulik': ok::NPFX+TULIK|menulik -> ok::- menulik ok::NPFX+TULIK|menulik Word ok::- +Stratum morphologicalRules edge-cases/mpr-group-overwrite-without-realizational Evidenced removed morphologicalRules from 1 element(s) 'udof': ok::THEMEA+DOF|udof -> ok::- udof ok::THEMEA+DOF|udof Word ok::- +Stratum morphologicalRules edge-cases/mpr-overwrite-order-dependence Evidenced removed morphologicalRules from 1 element(s) 'daboxayu': ok::DABO+SETX+SETY|daboxayu -> ok::- daboxayu ok::DABO+SETX+SETY|daboxayu Word ok::- +Stratum morphologicalRules edge-cases/process-morphology-in-place-mutation Evidenced removed morphologicalRules from 1 element(s) 'a': ok::AROOT|a;ROOT+ABLAUT|a -> ok::AROOT|a a ok::AROOT|a;ROOT+ABLAUT|a Word ok::AROOT|a +Stratum morphologicalRules edge-cases/stem-name-restricted-root-allomorph Evidenced removed morphologicalRules from 1 element(s) 'kapom': ok::ROOT+PERS1|kapom -> ok::- kapom ok::ROOT+PERS1|kapom Word ok::- +Stratum morphologicalRules edge-cases/strrep-identity Evidenced removed morphologicalRules from 1 element(s) 'pat': ok::+|[(^0)∅]?+?pat;|pat -> ok::|pat pat ok::+|[(^0)∅]?+?pat;|pat Word ok::|pat +Stratum morphologicalRules edge-cases/subrule-morphosyntactic-gating Evidenced removed morphologicalRules from 1 element(s) 'bat': ok::ROOT1+DERIVE|bat -> ok::- bat ok::ROOT1+DERIVE|bat Word ok::- +Stratum morphologicalRules edge-cases/truncate-morphotactic Evidenced removed morphologicalRules from 1 element(s) 'sa': ok::+|sa -> ok::- sa ok::+|sa Word ok::- +Stratum morphologicalRules languages/fusional-realizational-morphology Evidenced removed morphologicalRules from 2 element(s) 'mano': ok::STEM+P1|mano -> ok::- mano ok::STEM+P1|mano Word ok::- +Stratum morphologicalRules languages/metathesis-phase-isolation Evidenced removed morphologicalRules from 3 element(s) 'mu+i': ok::MI+3SGU|mu+?i -> ok::- mu+i ok::MI+3SGU|mu+?i Word ok::- +Stratum morphologicalRules languages/polysynthetic-stratal-derivation-chain Evidenced removed morphologicalRules from 2 element(s) 'nunaliq': ok::NUNA+DERIV|nunaliq -> ok::- nunaliq ok::NUNA+DERIV|nunaliq Word ok::- +Stratum morphologicalRules languages/suffixing-evidential-adjacency-chain Unobservable removed morphologicalRules from 1 element(s) all 28 word(s) unchanged - - None - +Stratum morphologicalRules languages/suffixing-extension-slot-ordering Evidenced removed morphologicalRules from 1 element(s) 'npael': ok::PPO+PHDESTROY|npael -> ok::- npael ok::PPO+PHDESTROY|npael Word ok::- +Stratum morphologicalRules languages/suffixing-vowel-harmony Evidenced removed morphologicalRules from 1 element(s) 'guan': ok::GAN+INTS|guan -> ok::- guan ok::GAN+INTS|guan Word ok::- +Stratum morphologicalRules languages/templatic-root-modification Evidenced removed morphologicalRules from 1 element(s) 'katabit': ok::KTB+P1SG|katabit -> ok::- katabit ok::KTB+P1SG|katabit Word ok::- +Stratum phonologicalRules edge-cases/alpha-variable-name-collision Evidenced removed phonologicalRules from 1 element(s) 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au +Stratum phonologicalRules edge-cases/feature-system-breadth Evidenced removed phonologicalRules from 1 element(s) 'ik': ok::AK|ik -> ok::- ik ok::AK|ik Word ok::- +Stratum phonologicalRules edge-cases/loader-default-symbol Evidenced removed phonologicalRules from 1 element(s) 'bdt': ok::- -> ok::|bdt bdt ok::- Word ok::|bdt +Stratum phonologicalRules edge-cases/metathesis-comparison-crash Evidenced removed phonologicalRules from 1 element(s) 'ti': ok::- -> ok::TI|ti ti ok::- Word ok::TI|ti +Stratum phonologicalRules edge-cases/mpr-gated-exception Evidenced removed phonologicalRules from 1 element(s) 'menulik': ok::NPFX+TULIK|menulik -> ok::- menulik ok::NPFX+TULIK|menulik Word ok::- +Stratum phonologicalRules edge-cases/right-to-left-anchor-environment Evidenced removed phonologicalRules from 1 element(s) 'aae': ok::ROOT1|aae -> ok::- aae ok::ROOT1|aae Word ok::- +Stratum phonologicalRules edge-cases/simultaneous-epenthesis-cascade Evidenced removed phonologicalRules from 1 element(s) 'bubu': threw::InfiniteLoopException -> ok::|bubu bubu threw::InfiniteLoopException Word ok::|bubu +Stratum phonologicalRules edge-cases/subrule-morphosyntactic-gating Evidenced removed phonologicalRules from 1 element(s) 'pat': ok::ROOT1|pat -> ok::ROOT1+DERIVE|pat;ROOT1|pat pat ok::ROOT1|pat Word ok::ROOT1+DERIVE|pat;ROOT1|pat +Stratum phonologicalRules languages/metathesis-phase-isolation Evidenced removed phonologicalRules from 3 element(s) 'nui': ok::NIU|nui -> ok::- nui ok::NIU|nui Word ok::- +Stratum phonologicalRules languages/polysynthetic-stratal-derivation-chain Evidenced removed phonologicalRules from 1 element(s) 'bubu': ok::DR1|bubu;DR2|bubu;DR3|bubu -> ok::- bubu ok::DR1|bubu;DR2|bubu;DR3|bubu Word ok::- +Stratum phonologicalRules languages/suffixing-extension-slot-ordering Evidenced removed phonologicalRules from 1 element(s) 'nba': ok::PPO|nba -> ok::- nba ok::PPO|nba Word ok::- +Stratum phonologicalRules languages/suffixing-vowel-harmony Evidenced removed phonologicalRules from 1 element(s) 'semitide': ok::SEMIT+PAST|semitide -> ok::- semitide ok::SEMIT+PAST|semitide Word ok::- +Stratum phonologicalRules languages/templatic-root-modification Evidenced removed phonologicalRules from 1 element(s) 'katabit': ok::KTB+P1SG|katabit -> ok::- katabit ok::KTB+P1SG|katabit Word ok::- +SymbolicFeature defaultSymbol edge-cases/loader-default-symbol Unobservable removed defaultSymbol from 1 element(s) all 2 word(s) unchanged - - None - +VariableFeature phonologicalFeature edge-cases/alpha-variable-name-collision RequiredByDtd removed phonologicalFeature from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'phonologic... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'phonologic... +VariableFeature phonologicalFeature edge-cases/feature-system-breadth RequiredByDtd removed phonologicalFeature from 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'phonologic... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'phonologic... +VariableFeature phonologicalFeature languages/suffixing-vowel-harmony RequiredByDtd removed phonologicalFeature from 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'phonologic... semitide ok::SEMIT+PAST|semitide LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: The required attribute 'phonologic... diff --git a/conformance/languages/fusional-realizational-morphology/grammar.xml b/conformance/languages/fusional-realizational-morphology/grammar.xml new file mode 100644 index 000000000..aac1171ed --- /dev/null +++ b/conformance/languages/fusional-realizational-morphology/grammar.xml @@ -0,0 +1,679 @@ + + + + + FusionalRealizationalMorphology + + v + n + + vAblaut + + n1 + v1 + n2 + v2 + + compH + compNH + + + + + id + + abcd + efgh + iklm + nopr + stuv + wxyz + + + + + tenseprespast + pers123 + numsgpl + + + + PedA + PedB + ConjA + ConjB + ConjC + ConjD + + CompReq + CompSubA + ThemeGroup + AllGroup + AnyGroup + + + + + PrincipalPartA + + + + + + + PrincipalPartB + + + + + + + + Main + + a + b + c + d + e + f + g + h + i + k + l + m + n + o + p + r + s + t + u + v + w + x + y + z + + + + + + + + + + Any + + AblautI + AblautA + + + + FamCarry + + FamCompBlock + + FamHNBlock + + + + + Main + + + + pers1 + + + + o + + + + P1 + + + pers2 + + + + s + + + + P2 + + + pers3 + + + + t + + + + P3 + + + + tense + + + + es + + + + TENSE + + + + realizPast + + + + id + + + + RPAST + + + + past2 + + + + it + + + + PAST2 + + + plural2 + + + + unt + + + + PL2 + + + + gePartT + + + + + ge + + t + + + + GET + + + + suffixS3 + + + + h + + + S3 + + + + nasalInfix + + + + + + + + + n + + + + + PRESSTEM + + + + compoundHeadNonHead + + + + + + + + + + + prefixBe1 + + + + be + + + + BEPFX1 + + + compoundNonHeadHead + + + + + + + + + + + prefixBe2 + + + + be + + + + BEPFX2 + + + + ablautPast + + + + + + + + + + + + + + + + ABLAUT + + + + compoundConstrained + + + + + + + + + + + + + + + + + + + + + + mun + man + min + + STEM + bring + + + + fer + FER + carry + + + + duc + DUC + lead + + + tul + + TUL + carry.PST.SUPPL + + + + lob + LOB + praise + + + + vic + VIC + conquer + + + + pan + PAN + bread + + + nox + NOXN + night + + + nox + NOXV + harm + + + + cor + BLOCKHEAD + heart + + + + zon + BLOCKSIB + zone + + + riv + BLOCKNON + river + + + + lex + LEX + law + + + dom + DOMN + house + + + dom + DOMV + tame + + + + sing + SING + sing + + + gen + GEN + kind + + + + nov + + NOV + new + + + mit + MIT + send + + + fic + FIC + make + + + + sec + SEC + cut + + + lav + LAV + wash + + + + + + MprGroups + + + + themeX + + + + x + + + THEMEX + + + themeY + + + + y + + + THEMEY + + + endZ + + + + z + + + ENDZ + + + + endW + + + + w + + + ENDW + + + endH + + + + h + + + ENDH + + + + + + ped + PED + foot + + + + kat + KAT + cat + + + sod + SOD + salt + + + lim + LIM + threshold + + + + gof + GOF + gof + + + + + + diff --git a/conformance/languages/fusional-realizational-morphology/words.yaml b/conformance/languages/fusional-realizational-morphology/words.yaml new file mode 100644 index 000000000..3b65e6b24 --- /dev/null +++ b/conformance/languages/fusional-realizational-morphology/words.yaml @@ -0,0 +1,753 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). This grammar has no phonological rules and no +# AffixTemplate at all (every MorphologicalRule/RealizationalRule/CompoundingRule applies freely, +# unordered) -- so a bare root is a valid word whenever nothing else (a StemName region, a Family +# collision, an IsBlocked check) specifically forbids it. +# +# 1. mun -> STEM's default (unrestricted) allomorph, bare, no person feature assigned at all. The +# default allomorph carries no stemName, so it has no region to fail to satisfy. +# -> STEM|mun, rules: [] +# 2. muno -> STEM's default allomorph + P1 ("-o"). Once a person feature IS assigned, snP1P2 and +# snP1P3's regions jointly exhaust the whole person space {1,2,3} -- so the default allomorph, +# valid only in the absence of any person-governed region, can never combine with ANY person +# suffix. Zero parses. +# -> expect_fail +# 3. mano -> STEM's snP1P2-restricted allomorph "man" + P1. P1 is in snP1P2's region {1,2} -> valid. +# -> STEM+P1|mano, rules: [mrPers1] +# 4. mant -> STEM's snP1P2-restricted allomorph "man" + P3 ("-t"). P3 is NOT in snP1P2's region +# {1,2} -> zero parses. +# -> expect_fail +# 5. fer -> FER, bare, no lexical head features at all, no rule touches it -> trivially valid. +# -> FER|fer, rules: [] +# +# The remaining words either reuse these same mechanisms on independent lexical material (the +# realizational-rule/family-blocking/circumfix/infix/compounding/MPR-group/ablaut sections) or are +# expect_fail words whose signature is the empty set. +# +# Reconciliation against the oracle (self-check): the 5 words above matched on the first run with no +# disagreement. The remaining 44 words needed several real fixes before matching -- none were hand- +# derivation errors in the sense of "wrong linguistic reasoning"; all were genuine grammar-authoring/ +# engine-interaction discoveries, reported here in full rather than silently smoothed over: +# +# 1. Morph-chain order for a PREFIX is LEFT-TO-RIGHT SURFACE POSITION (prefix morpheme first), not +# "root first, affixes after" the way every suffix-only example in this suite (and suffixing- +# quechua) reads -- none of the ledger's source v1 fixtures used a real MorphemeId on a +# prefixing rule (they tested the mechanism only, MorphemeId left unset), so there was no +# precedent to crib from. Resolved empirically via --propose: confirmed on gelobt (GET+LOB, not +# LOB+GET) and xped (THEMEX+PED). +# 2. The compounding seam's boundary marker "+" must be declared as a BoundaryDefinition (DTD +# element under CharacterDefinitionTable), not a plain SegmentDefinition -- declaring it as a +# segment made every compound word find ZERO parses (confirmed by isolated probing against v1 +# compounding/nonhead-not-root's own grammar.xml, which uses BoundaryDefinition). It renders as +# "+?" in the signature (matching v1's own "(pʰ)ut+?dat"), never as a literal character in the +# surface word text. +# 3. mrSuffixS3's literal suffix was originally "-s", identical to mrPers1's own "-s" ending on +# any posV root sharing no AffixTemplate -- every "-s"-suffixed word (muns, lobs) spuriously +# double-analyzed as both. Renamed S3's suffix to "-h" (mrSuffixS3 requiredPartsOfSpeech=posV; +# mrEndH is a DIFFERENT rule, gated posN, so the two "-h" suffixes never collide). +# 4. mrAblaut, gated on the shared "posV", let ANY posV word containing "a" get a spurious extra +# analysis where the "a" was hypothesized as an ablaut-changed "i" reverting to some OTHER posV +# root -- concretely, "mano" (STEM+P1) ALSO analyzed as STEM(reverting "man"'s "a" back to "i", +# landing on the real "min" allomorph)+ABLAUT+P1, a genuine cross-construct collision between +# two unrelated grammar sections that happened to share both a POS gate and a coincidental +# vowel-alternation pattern. Fixed by giving SING (mrAblaut's only intended target) its own POS, +# posAblautV, confining the reversal search to exactly the one root it describes. +# 5. The two CompoundingRules (mrCompoundHN, mrCompoundNH) both had unrestricted wildcard head/ +# nonhead patterns and no POS gating, so mrCompoundNH ALSO matched "pannox" (reading it as +# nonhead="pan"+head="nox", producing the identical signature mrCompoundHN already derives) -- +# every compound word double-counted. Fixed by giving each CompoundingRule's Set its own disjoint +# POS pair (posN1/posV1 for Set 1, posN2/posV2 for Set 2) via headPartsOfSpeech/ +# nonHeadPartsOfSpeech, confining each rule to its own lexical material. +# 6. Set 2 (prefix-commute) originally put the homophone-ambiguity pair on the NON-head (mirroring +# Set 1) with mrPrefixBe2 (posV-gated) attaching to the HEAD (a plain noun, "dom") -- but a +# posV-gated rule can never apply to a noun, so lexbedom always found zero parses. Fixed by +# moving the homophone pair (DOMN/DOMV) onto the HEAD instead, so mrPrefixBe2 has a posV2 +# reading to attach to; the non-head (LEX) is a plain, unambiguous noun in this set instead. +# 7. Even after fix 6, lexbedom still found zero parses: mpr-groups/output-overwrite and +# compounding/prefix-commute have genuinely CONFLICTING requirements on morphologicalRuleOrder +# within one stratum. output-overwrite needs "linear" order to be observable at all (a v1 +# fixture requirement); prefix-commute's head-recursion (the prefix unapplying from the +# compounding HEAD span before the compound itself unapplies) only succeeds under "unordered" -- +# confirmed by toggling the setting and watching lexbedom and yxpedz trade places. Resolved by +# splitting the grammar into two Strata sharing the same CharacterDefinitionTable: "Main" +# (unordered, everything else) and "MprGroups" (linear, only the two mpr-groups constructs). +# +# Findings 2-7 are documented at their point of relevance in grammar.xml as well. None required a +# harness change; all were resolved within the grammar itself once understood. + +language: FusionalRealizationalMorphology +inspired_by: ["fusional inflectional-class morphology with stem suppletion, realizational rules, and ablaut-as-sole-exponent (typological pattern, not any specific language)"] +sources: + - "WALS - Fusion, Exponence, Inflectional Synthesis in Inflectional Morphology chapters" + - "typological literature on suppletion - inflectional classes, syncretism, principal parts" +requires: [] +words: + - word: mun + note: STEM's default (unrestricted) allomorph, bare -- no person feature assigned, so there is no StemName region to fail. + parses: + - signature: "STEM|mun" + gloss: bring + rules: [] + exercises: + - "Stem names" + + - word: muno + note: STEM default allomorph + P1 -- once ANY person feature is assigned, snP1P2/snP1P3's regions jointly exhaust {1,2,3}, so the region-less default allomorph can never combine with a person suffix at all. + expect_fail: true + exercises: + - "Stem names" + + - word: muns + note: STEM default allomorph + P2 -- same reasoning as muno. + expect_fail: true + exercises: + - "Stem names" + + - word: munt + note: STEM default allomorph + P3 -- same reasoning as muno. + expect_fail: true + exercises: + - "Stem names" + + - word: mano + note: STEM's snP1P2-restricted allomorph "man" + P1 ("-o") -- P1 is in snP1P2's region {1,2}. + parses: + - signature: "STEM+P1|mano" + gloss: bring-1SG + rules: [mrPers1] + exercises: + - "Stem names" + + - word: mans + note: STEM's snP1P2-restricted allomorph "man" + P2 ("-s") -- P2 is in snP1P2's region {1,2}. + parses: + - signature: "STEM+P2|mans" + gloss: bring-2SG + rules: [mrPers2] + exercises: + - "Stem names" + + - word: mant + note: STEM's snP1P2-restricted allomorph "man" + P3 -- P3 is NOT in snP1P2's region {1,2} -- zero parses. + expect_fail: true + exercises: + - "Stem names" + + - word: man + note: STEM's snP1P2-restricted allomorph, bare -- no person feature assigned means no region is satisfied, so this stemName-governed allomorph fails standalone (unlike the default allomorph's "mun"). + expect_fail: true + exercises: + - "Stem names" + + - word: mino + note: >- + STEM's snP1P3-restricted allomorph "min" + P1 -- P1 is in snP1P3's region {1,3}, AND also in + snP1P2's region {1,2}: the shared-region row, proving 1st-person overlap between the two stem + names doesn't spuriously block either one. + provenance: "W5, StemName selection + default-stem fallback" + parses: + - signature: "STEM+P1|mino" + gloss: bring-1SG + rules: [mrPers1] + exercises: + - "Stem names" + + - word: mins + note: STEM's snP1P3-restricted allomorph "min" + P2 -- P2 is NOT in snP1P3's region {1,3} -- zero parses. + expect_fail: true + exercises: + - "Stem names" + + - word: mint + note: STEM's snP1P3-restricted allomorph "min" + P3 -- P3 is in snP1P3's region {1,3}. + parses: + - signature: "STEM+P3|mint" + gloss: bring-3SG + rules: [mrPers3] + exercises: + - "Stem names" + + - word: min + note: STEM's snP1P3-restricted allomorph, bare -- fails standalone for the same reason "man" does. + expect_fail: true + exercises: + - "Stem names" + + - word: fer + note: FER ("carry"), bare, no lexical head features at all -- trivially valid, no rule touches it. + parses: + - signature: "FER|fer" + gloss: carry + rules: [] + exercises: [] + + - word: ferid + note: FER + RPAST (a RealizationalRule, no AffixTemplate/Slot wrapper needed) -- the root's own FS has no tense value at all, so RPAST's IsBlocked presence check finds nothing to collide with. + provenance: "W5, RealizationalAffixProcessRule core mechanics + IsBlocked" + parses: + - signature: "FER+RPAST|ferid" + gloss: carry-PST.REALIZ + rules: [rrPast] + exercises: + - "RealizationalAffixProcessRule" + + - word: feres + note: FER + TENSE ("-es", ordinary affix, sets tense=pres) -- pre-loads a tense value so the realizational rule's blocking check below has something to trip on. + parses: + - signature: "FER+TENSE|feres" + gloss: carry-PRES + rules: [mrTense] + exercises: + - "RealizationalAffixProcessRule" + + - word: feresid + note: >- + FER + TENSE + RPAST attempted together -- mrTense sets tense=pres first, then RPAST's IsBlocked + check sees tense is ALREADY present (even though it's pres, not past) and blocks -- a + value-equality mis-implementation would wrongly accept this; presence alone is what matters. + expect_fail: true + blocked_by: [rrPast] + exercises: + - "RealizationalAffixProcessRule" + + - word: duc + note: DUC ("lead"), bare, regular member of famCarry -- no collision, trivially valid. + parses: + - signature: "DUC|duc" + gloss: lead + rules: [] + exercises: [] + + - word: tul + note: TUL ("carry.PST.SUPPL"), bare, irregular suppletive member of famCarry with tense lexically fixed to past -- direct lexical lookup never reaches CheckBlocking. + parses: + - signature: "TUL|tul" + gloss: carry.PST.SUPPL + rules: [] + exercises: + - "RealizationalAffixProcessRule" + + - word: ducit + note: >- + DUC + PAST2 ("-it", sets tense=past) attempted -- the synthesized candidate's tense=past FS + subsumes TUL's own lexically-fixed FS (family collision), so Word.CheckBlocking fires and + substitutes in TUL's own shape; since that substituted shape ("tul") does not match the surface + "ducit", the candidate is discarded. Zero parses. + expect_fail: true + blocked_by: [mrPast2] + provenance: "W5, LexFamily blocks a more-general family member (Word.CheckBlocking)" + exercises: + - "RealizationalAffixProcessRule" + + - word: ducunt + note: DUC + PL2 ("-unt", sets num=pl only, never touches tense) -- never collides with TUL's tense-only lexical fixing, so not blocked. + parses: + - signature: "DUC+PL2|ducunt" + gloss: lead-PL + rules: [mrPl2] + exercises: + - "RealizationalAffixProcessRule" + + - word: lob + note: LOB ("praise"), bare. + parses: + - signature: "LOB|lob" + gloss: praise + rules: [] + exercises: [] + + - word: gelobt + note: LOB circumfixed "ge-...-t" (ge-...-t past-participle-plausible) -- simultaneous prefix+suffix wrapped around one copied stem span, both pieces contributed by the SAME rule/morpheme id. + provenance: "W9.1 probe, AffixProcessRuleTests.CircumfixRules" + parses: + - signature: "GET+LOB|gelobt" + gloss: PTCP-praise + rules: [mrCircumfixGeT] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: lobh + note: >- + LOB + S3 ("-h", ordinary suffix, independent of the circumfix rule). S3's suffix is "-h", not + "-s": isolated probing found that "-s" collided with mrPers2's own literal "-s" suffix (both + apply freely to any posV root), spuriously double-analyzing every "-s"-suffixed posV word as + both S3 and P2 -- see grammar.xml's mrSuffixS3 comment. + parses: + - signature: "LOB+S3|lobh" + gloss: praise-3SG + rules: [mrSuffixS3] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: gelobth + note: LOB circumfixed AND suffixed with S3 in the same word -- proves the circumfix composes with an independent ordinary suffix rule. + parses: + - signature: "GET+LOB+S3|gelobth" + gloss: PTCP-praise-3SG + rules: [mrCircumfixGeT, mrSuffixS3] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: gelobthh + note: A doubled S3 suffix -- no rule combination produces two trailing "h"s. Negative control, mirroring v1 affix-shapes/circumfix's own doubled-suffix negative row. + expect_fail: true + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: vic + note: VIC ("conquer"), bare -- the perfect-stem shape (vici-plausible), no infix. + parses: + - signature: "VIC|vic" + gloss: conquer + rules: [] + exercises: [] + + - word: vinc + note: VIC's present stem, nasal-infixed ("vi" + "n" + "c") -- vincere-plausible; two MorphologicalInput parts (first 2 segments, then the remainder), "n" inserted between them. + provenance: "W9.1 probe, AffixProcessRuleTests.InfixRules" + parses: + - signature: "VIC+PRESSTEM|vinc" + gloss: conquer-PRES.STEM + rules: [mrNasalInfix] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: pannox + note: >- + PAN (head, "bread") + NOX (nonhead, bare root) compounded head+nonhead -- NOX is homophonous + across posN ("night") and posV ("harm"), so both are independently valid non-head roots for the + same surface string: two genuinely distinct analyses. The compounding seam's boundary marker + "+" is a BoundaryDefinition (not a plain segment, see grammar.xml's CharacterDefinitionTable + comment); it renders as "+?" in the signature's shape half, matching v1 compounding's own + "(pʰ)ut+?dat"-style rendering -- it is never part of the literal surface word text itself. + parses: + - signature: "PAN+NOXN|pan+?nox" + gloss: bread-night + rules: [mrCompoundHN] + exercises: + - "CompoundingRule" + - signature: "PAN+NOXV|pan+?nox" + gloss: bread-harm + rules: [mrCompoundHN] + exercises: + - "CompoundingRule" + + - word: benox + note: >- + NOXV, be-prefixed, standalone (no compounding involved) -- proves mrPrefixBe1 itself works + correctly in isolation, so panbenox's rejection below is specifically about the compounding + non-head-must-be-a-root constraint, not some defect in the prefix rule itself. + parses: + - signature: "BEPFX1+NOXV|benox" + gloss: PST-harm + rules: [mrPrefixBe1] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: panbenox + note: >- + PAN + be-prefixed NOX compounded head+nonhead -- the non-head span "benox" is prefix+root, NOT + a bare root, and CompoundingRule's analysis-side search requires the non-head to be a bare root + (computational-complexity reasons, per AnalysisCompoundingRule.cs) -- the prefix is discarded as + an invalid analysis rather than recursively re-applied. Zero parses. + expect_fail: true + blocked_by: [mrCompoundHN] + provenance: "P3, CompoundingRuleTests.SimpleRules reconfiguration 3 (non-head-not-root variant)" + exercises: + - "CompoundingRule" + + - word: pandex + note: PAN + "dex" -- "dex" is neither a root nor any rule's output, so no compound analysis exists at all. + expect_fail: true + exercises: + - "CompoundingRule" + + - word: lexdom + note: >- + LEX (nonhead, "law", posN2 only) + DOM (head, bare) compounded nonhead+head -- DOM is + homophonous across posN2 ("house") and posV2 ("tame"), so both are independently valid head + roots for the same surface string (the mirror image of Set 1's ambiguity, which sat on the + non-head instead). + parses: + - signature: "LEX+DOMN|lex+?dom" + gloss: law-house + rules: [mrCompoundNH] + exercises: + - "CompoundingRule" + - signature: "LEX+DOMV|lex+?dom" + gloss: law-tame + rules: [mrCompoundNH] + exercises: + - "CompoundingRule" + + - word: lexbedom + note: >- + LEX (nonhead) + be-prefixed DOM (head) compounded nonhead+head -- here the PREFIX attaches to + the HEAD, not the non-head, and CompoundingRule's non-head-must-be-a-root requirement never + constrains the head span at all, so this succeeds where panbenox failed: the prefix unapplies + cleanly from the head span "bedom" -- but mrPrefixBe2 requires posV2, so only DOM's VERB reading + (DOMV, "tame") is prefix-eligible; the noun reading (DOMN) can never combine with the prefix at + all, so unlike lexdom's bare-head ambiguity, this word has exactly one analysis, not two. The + prefix commutes with compounding rule ordering exactly as v1's own prefix-commute fixture pins. + provenance: "P3, CompoundingRuleTests.SimpleRules reconfiguration 3 (prefix-commute variant)" + parses: + - signature: "LEX+BEPFX2+DOMV|lex+?bedom" + gloss: law-PST-tame + rules: [mrCompoundNH, mrPrefixBe2] + exercises: + - "CompoundingRule" + + - word: lexbex + note: LEX + "bex" -- "bex" is neither DOM nor any valid prefixed-head shape, so no compound analysis exists. + expect_fail: true + exercises: + - "CompoundingRule" + + - word: ped + note: PED ("foot"), bare -- no MPR feature preset on this lexical entry, trivially valid. + parses: + - signature: "PED|ped" + gloss: foot + rules: [] + exercises: [] + + - word: gofz + note: >- + GOF ("gof", introduced in full below with its ruleFeatures preset) + mrEndZ directly, with + NEITHER mrThemeX NOR mrThemeY intervening -- GOF's own lexically-preset mprPedA reaches + mrEndZ's requiredMPRFeatures="mprPedA" gate untouched, so this succeeds. The control for + "ygofz" below: same root, same final suffix, the only difference is whether a + ThemeGroup-overwriting rule sits in between. Placed here, ahead of GOF's own narrative + introduction, because the paired severance witness on "ygofz" requires it to be the FIRST + word in this file whose outcome differs under either of two specific severances -- see + "ygofz"'s own note. + parses: + - signature: "GOF+ENDZ|gofz" + gloss: gof-END + rules: [mrEndZ] + exercises: + - "MPR features/groups" + + - word: ygofz + note: >- + GOF + mrThemeY + mrEndZ -- mrThemeY's own MorphologicalOutput MPRFeatures="mprPedB" write puts + mprPedB into ThemeGroup's newly-written set, and MprFeatureSet.AddOutput's overwrite step drops + every OTHER ThemeGroup member not in that set -- including GOF's own lexically-preset mprPedA, + even though GOF never lost it by declaration, only by a later rule's write. mrEndZ's + requiredMPRFeatures="mprPedA" then fails: zero parses, despite GOF genuinely carrying mprPedA + at the lexical entry. This is the AbsentGatedForm witness for BOTH MPR writers onto this same + reader: severing mrThemeY's own MorphologicalOutput.MPRFeatures (so the write, and the + overwrite it triggers, never happens at all) leaves GOF's preset mprPedA untouched and this + parses exactly as "gofz" does; severing mrEndZ's own requiredMPRFeatures (so the gate no longer + needs mprPedA at all) unblocks it independently, to the identical result -- the same word, + the same successful parse, from two unrelated severances. This word is placed immediately + after "gofz" and before "xped"/"yxpedz" (the mpr-groups section's own earlier, unrelated + Overwrite/required-MPR demonstrations) deliberately: FindPairedWitness's severance ledger + reports the FIRST word in file order whose outcome differs under a given mutation, and + "xpedz"/"yxpedz" already differ under these same two severances (in the OPPOSITE, non-paired + direction and the un-paired reader-only direction respectively) -- if "ygofz" sat after them, + its own paired flip would never surface as either interface's recorded example. + expect_fail: true + blocked_by: [mrEndZ] + exercises: + - "MPR features/groups" + # Claims the McDc:AbsentGatedForm cell of conformance/dataflow-obligations.tsv's obligation matrix. + # DataflowClaimGate checks this against conformance/dataflow-obligations.tsv, never trusts it, + # and recomputes severing/before/after by re-severing the writer and reader named in the ledger + # row -- the inline values below are what it recomputed against, not what it trusts blindly. + claimed_cells: + - cell: "MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm" + severing: >- + MPRFeatures across every MorphologicalOutput (the one that matters here is mrThemeY's own + "mprPedB" write), as the writer, or mrEndZ's MorphologicalInput.requiredMPRFeatures="mprPedA" + gate, as the reader -- severing either alone unblocks this word + before: "ok::-" + after: "ok::THEMEY+GOF+ENDZ|ygofz" + distinct_from: gofz + proof: >- + ygofz is GOF (lexically preset with mprPedA) run through mrThemeY then mrEndZ; with both + constructs intact, mrThemeY's own write triggers ThemeGroup's overwrite semantics + (MprFeatureSet.AddOutput) and drops GOF's preset mprPedA before mrEndZ's gate is ever + checked, so this has zero parses (ok::-). Removing either the writer (mrThemeY's own + MorphologicalOutput.MPRFeatures, so the overwrite-triggering write never happens) or the + reader (mrEndZ's requiredMPRFeatures, so the gate no longer needs mprPedA) lets mrEndZ + apply anyway, producing THEMEY+GOF+ENDZ|ygofz -- the AbsentGatedForm arm: the required + feature is ABSENT (from the derivation's accumulated state, though never from GOF's own + declaration) and the rule's requirement GATES on it. gofz (GOF+ENDZ with no mrThemeY at + all) is the control that shows mrEndZ applies normally once mprPedA actually survives to + the gate, so ygofz's block is attributable to mrThemeY's overwrite, not to mrEndZ never + applying at all. + + - word: xped + note: PED prefixed by mrThemeX ("x-", sets MPR feature mprPedA). + provenance: "W3.1, MprFeatureGroupOutput.Overwrite in MPR output accumulation" + parses: + - signature: "THEMEX+PED|xped" + gloss: THEME.A-foot + rules: [mrThemeX] + exercises: + - "MPR features/groups" + + - word: yxped + note: PED prefixed by mrThemeX then mrThemeY ("y-", sets mprPedB) -- ThemeGroup's outputType="overwrite" means mrThemeY's own output DROPS mprPedA rather than accumulating it alongside mprPedB. + parses: + - signature: "THEMEY+THEMEX+PED|yxped" + gloss: THEME.B-THEME.A-foot + rules: [mrThemeX, mrThemeY] + exercises: + - "MPR features/groups" + + - word: xpedz + note: PED prefixed by mrThemeX then suffixed by mrEndZ (requiredMPRFeatures="mprPedA") -- mprPedA is still present (only mrThemeX applied), so mrEndZ's requirement is satisfied. + parses: + - signature: "THEMEX+PED+ENDZ|xpedz" + gloss: THEME.A-foot-END + rules: [mrThemeX, mrEndZ] + exercises: + - "MPR features/groups" + + - word: yxpedz + note: >- + PED prefixed by mrThemeX then mrThemeY then suffixed by mrEndZ -- the DISTINGUISHING row: after + mrThemeY, ThemeGroup's Overwrite semantics have already dropped mprPedA, so mrEndZ's + requiredMPRFeatures="mprPedA" fails. Zero parses. A pre-fix "flat union" mis-implementation + would wrongly accept this. + expect_fail: true + blocked_by: [mrEndZ] + exercises: + - "MPR features/groups" + + - word: kat + note: KAT ("cat"), bare -- ruleFeatures preset both AllGroup members (mprConjA, mprConjB) directly on the lexical entry. + parses: + - signature: "KAT|kat" + gloss: cat + rules: [] + exercises: [] + + - word: sod + note: SOD ("salt"), bare -- ruleFeatures preset mprConjA (half of AllGroup) and mprConjC (half of AnyGroup). + parses: + - signature: "SOD|sod" + gloss: salt + rules: [] + exercises: [] + + - word: lim + note: LIM ("threshold"), bare -- no ruleFeatures preset at all. + parses: + - signature: "LIM|lim" + gloss: threshold + rules: [] + exercises: [] + + - word: katw + note: KAT + mrEndW (requiredMPRFeatures="mprConjA mprConjB", matchType="all") -- KAT has both AllGroup members, so the ALL requirement is satisfied. + provenance: "W3.1, MprFeatureGroupMatchType.All/Any in required-MPR gating" + parses: + - signature: "KAT+ENDW|katw" + gloss: cat-ALL.END + rules: [mrEndW] + exercises: + - "MPR features/groups" + + - word: sodw + note: SOD + mrEndW -- SOD has only mprConjA, not mprConjB, so the ALL requirement (both members) is NOT satisfied. Zero parses -- the pre-fix flat-overlap bug would have wrongly accepted this. + expect_fail: true + blocked_by: [mrEndW] + exercises: + - "MPR features/groups" + + - word: limw + note: LIM + mrEndW -- LIM has neither AllGroup member, so the ALL requirement fails outright. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: kath + note: KAT + mrEndH (requiredMPRFeatures="mprConjC mprConjD", matchType="any") -- KAT has NEITHER AnyGroup member, so the ANY requirement fails. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: sodh + note: SOD + mrEndH -- SOD has mprConjC (one AnyGroup member), so the ANY requirement (at least one) is satisfied. + parses: + - signature: "SOD+ENDH|sodh" + gloss: salt-ANY.END + rules: [mrEndH] + exercises: + - "MPR features/groups" + + - word: limh + note: LIM + mrEndH -- LIM has neither AnyGroup member, so the ANY requirement fails. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: gof + note: >- + GOF, bare -- ruleFeatures preset every group member mrEndZ/mrEndW/mrEndH gate on (mprPedA plus + both AllGroup and one AnyGroup member), so this one root can chain all three suffixes and expose + the Stratum "MprGroups" list-order dependency between them (none of the three produces an MPR + feature the others consume, so without a shared root no word could ever request more than one). + parses: + - signature: "GOF|gof" + gloss: gof + rules: [] + exercises: [] + + - word: gofzw + note: >- + GOF + mrEndZ + mrEndW, in that list order (mrEndZ before mrEndW on Stratum "MprGroups"). The + ordering discriminator for the mrEndZ~mrEndW adjacent pair: "gofwz" below is the same two + suffixes reversed, which only parses when the list order is swapped. + parses: + - signature: "GOF+ENDZ+ENDW|gofzw" + gloss: gof-END-ALL.END + rules: [mrEndZ, mrEndW] + exercises: + - "MPR features/groups" + + - word: gofwz + note: >- + GOF + mrEndW + mrEndZ, the reverse of "gofzw". Zero parses under the shipped list order + (mrEndZ mrEndW): this exact surface is only reachable when mrEndW is transposed ahead of + mrEndZ, which is the mrEndZ~mrEndW ordering item's own counterfactual. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: gofwh + note: >- + GOF + mrEndW + mrEndH, in that list order (mrEndW before mrEndH). The ordering discriminator + for the mrEndW~mrEndH adjacent pair: "gofhw" below is the same two suffixes reversed, which + only parses when the list order is swapped. + parses: + - signature: "GOF+ENDW+ENDH|gofwh" + gloss: gof-ALL.END-ANY.END + rules: [mrEndW, mrEndH] + exercises: + - "MPR features/groups" + + - word: gofhw + note: >- + GOF + mrEndH + mrEndW, the reverse of "gofwh". Zero parses under the shipped list order + (mrEndW mrEndH): this exact surface is only reachable when mrEndH is transposed ahead of + mrEndW, which is the mrEndW~mrEndH ordering item's own counterfactual. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: sing + note: SING ("sing", singen-plausible), bare -- no lexical head features, present-stem citation form. + parses: + - signature: "SING|sing" + gloss: sing + rules: [] + exercises: [] + + - word: sang + note: >- + SING's past-tense form, realized ENTIRELY by changing the root's own vowel ("i"->"a") via + ModifyFromInput -- no affix at all. Ablaut as the sole exponent of the tense category + (singen/sang-plausible). + parses: + - signature: "SING+ABLAUT|sang" + gloss: sing-PST.ABLAUT + rules: [mrAblaut] + exercises: + - "MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext" + + - word: mitlav + note: >- + MIT (head, mprCompReq+mprSubA) + LAV (nonhead) -- mrCompoundConstrained's subrule 0 + (requiredMPRFeatures="mprSubA" on HeadMorphologicalInput) matches since MIT carries mprSubA. + G5 (code-coverage-driven): previously zero coverage for a CompoundingSubrule's own per-subrule + requiredMPRFeatures/excludedMPRFeatures gating (distinct from the ordinary-MorphologicalRule + MPR-groups material elsewhere in this file). + provenance: "G5 coverage sweep, SynthesisCompoundingRule requiredMPRFeatures/excludedMPRFeatures" + parses: + - signature: "MIT+LAV|mit+?lav" + gloss: send-wash + rules: [mrCompoundConstrained] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: ficlav + note: >- + FIC (head, mprCompReq only, no mprSubA) + LAV (nonhead) -- subrule 0 fails (FIC lacks + mprSubA), so subrule 1 (excludedMPRFeatures="mprSubA") is tried instead and matches, since FIC + genuinely excludes mprSubA. Proves the per-subrule MPR gate actually discriminates between the + two subrules, not just falls through by pattern order. + provenance: "G5 coverage sweep, SynthesisCompoundingRule requiredMPRFeatures/excludedMPRFeatures" + parses: + - signature: "FIC+LAV|fic+?lav" + gloss: make-wash + rules: [mrCompoundConstrained] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: seclav + note: >- + SEC (head, no ruleFeatures at all) + LAV (nonhead) -- mrCompoundConstrained's own + headProdRestrictionsMprFeatures="mprCompReq" requires the head to carry mprCompReq, which SEC + does not, so the rule never applies at all (both subrules unreachable). G5 (code-coverage- + driven): previously zero coverage for CompoundingRule.headProdRestrictionsMprFeatures. + provenance: "G5 coverage sweep, SynthesisCompoundingRule.headProdRestrictionsMprFeatures" + expect_fail: true + blocked_by: [mrCompoundConstrained] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: genlav + note: >- + GEN (head, mprCompReq, family famCompBlock) + LAV (nonhead) -- the compounding rule itself + applies successfully, but GEN's family also contains the suppletive NOV, and CheckBlocking + substitutes NOV's own entry in wherever GEN's compound output would surface; the resulting + resynthesis ("nov") no longer matches this word's own input shape ("gen+lav"), so the overall + analysis has zero parses. G5 (code-coverage-driven): previously zero coverage for + CompoundingRule's own Blockable/CheckBlocking path (only ever exercised through an ordinary + MorphologicalRule elsewhere in this file, via famCarry). + provenance: "G5 coverage sweep, SynthesisCompoundingRule Blockable/CheckBlocking" + expect_fail: true + blocked_by: [mrCompoundConstrained] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: mitlavlav + note: >- + MIT+LAV (mitlav, above) attempted as the HEAD of a further application of the same + compounding rule, with LAV again as the nonhead. Hand-derived to hit MaxApplicationCount (the + DTD's own default multipleApplication="1" caps one application per derivation), but a + dotnet-coverage check after this word was added showed SynthesisCompoundingRule's + MaxApplicationCount lines still unreached -- the zero-parse result is real (confirmed by + self-check) but its cause is not confirmed to be MaxApplicationCount specifically; most likely + analysis-direction compound-splitting does not recurse into a derived (non-lexical) head span + at all, rejecting this candidate before MaxApplicationCount is ever checked. Left in as a + correct expect_fail pin, but MaxApplicationCount itself remains a documented residual gap. + provenance: "G5 coverage sweep, SynthesisCompoundingRule (MaxApplicationCount attempt, gap remains)" + expect_fail: true + blocked_by: [mrCompoundConstrained] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" + + - word: corriv + note: >- + CompoundingRule@blockable="false" probe for mrCompoundHN (mrCompoundConstrained's own + blockable="true" is already pinned by genlav above, but neither of the OTHER two + CompoundingRules -- mrCompoundHN, mrCompoundNH -- had a family sibling to make their own + declared "false" value observable; rewriting it to "true" changed nothing until now). + BLOCKHEAD (head, family famHNBlock) + BLOCKNON (nonhead) compound normally. BLOCKHEAD's family + also contains the sibling BLOCKSIB, which declares no AssignedHeadFeatures at all -- an empty + SyntacticFeatureStruct trivially subsumes an empty one, so were mrCompoundHN blockable, + CheckBlocking would fire on family membership alone and substitute BLOCKSIB's own bare entry + wherever this compound's output would surface, and the resulting resynthesis ("zon") would not + match this word's own input shape ("cor+riv"). Because mrCompoundHN declares blockable="false", + that substitution never happens and the ordinary compound analysis stands. + parses: + - signature: "BLOCKHEAD+BLOCKNON|cor+?riv" + gloss: heart-river + rules: [mrCompoundHN] + exercises: + - "CompoundingRule constraints (MaxApplicationCount/Blockable/head-nonhead syntactic features)" diff --git a/conformance/languages/metathesis-phase-isolation/grammar.xml b/conformance/languages/metathesis-phase-isolation/grammar.xml new file mode 100644 index 000000000..c8d0262a6 --- /dev/null +++ b/conformance/languages/metathesis-phase-isolation/grammar.xml @@ -0,0 +1,467 @@ + + + + + MetathesisPhaseIsolation + + + nComplexMeta + nSimpleMeta + nNotUnapplied + vInfix + vCircum + vRedup + vTrunc + nLnk + vNonContig + + + + cons+- + voc+- + high+- + low+- + back+- + round+- + voice+- + + place + + bilabial + alveolar + velar + glottal + sibilant + lateral + rhotic + nasalLab + nasalAlv + vocalic + + + + + + Main + + + a + + + + + + e + + + + + + i + + + + + + u + + + + + + ɯ + + + + + + + p + + + + + + b + + + + + + m + + + + + + t + + + + + + d + + + + + + n + + + + + + s + + + + + + l + + + + + + r + + + + + + k + + + + + + h + + + + + + + + + + + + + + Any + Consonant + + + Vowel + + + + LowVowel + + + VowelI + + + + + VoicedCons + + + + I + U + + + + + nonContigRaising + + + + + + + + + + + + + metathesisSimple + + + + + + + + + + + + metathesisComplex + + + + + + + + + + + + + + + ComplexMeta + + + uSuffix + + + + +u + + + 3SGU + + + + + mi + MI + come + + + + + + SimpleMeta + + + iSuffix + + + + i + + + 3SGI + + + + + + niu + NIU + coconut + + + pu + PU + fire + + + + + + Morphology + + + + infixUm + + + + + + + + + um + + + + + AV + + + + circumKeAn + + + + + ke + + an + + + + NMLZ + + + + redupCV + + + + + + + + + + + + + + RDP + + + + redupFull + + + + + + + + + + RDPL + + + + truncateFinalE + + + + + + + + + + INCP + + + + linker + + + + in + + + LNK + + + + perfNonContig + + + + + + + + + + a + + a + + ɯd + + + + PERF + + + + + sulat + SULAT + write + + + adil + ADIL + just + + + tula + TULA + help + + + pure + PURE + finish + + + baha + BAHA + flood + + + ktb + KTB + arrange + + + + + + diff --git a/conformance/languages/metathesis-phase-isolation/words.yaml b/conformance/languages/metathesis-phase-isolation/words.yaml new file mode 100644 index 000000000..59c3325f2 --- /dev/null +++ b/conformance/languages/metathesis-phase-isolation/words.yaml @@ -0,0 +1,274 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). +# +# 1. nui -> NIU ("coconut", posSimpleMeta) underlying "niu": mrSimpleMeta (adjacent i-then-u -> +# u-then-i swap) fires obligatorily -> "nui". The underlying "niu" can never itself surface. +# -> NIU|nui, rules: [mrSimpleMeta] +# 2. niu -> the raw, un-metathesized underlying shape -- mrSimpleMeta is obligatory wherever an +# i-then-u adjacency holds, so "niu" can never be a valid surface (mirrors v1 simple_rule row 1). +# -> expect_fail, blocked_by: [mrSimpleMeta] +# 3. mu+i -> MI ("come", posComplexMeta) + 3SGU ("+u"): underlying "mi"+"+u" = "mi+u", then +# mrComplexMeta (i +BND u -> u +BND i, final-anchored) swaps across the boundary -> "mu+i", +# rendered with the visible boundary as "mu+?i". +# -> MI+3SGU|mu+?i, rules: [mrUSuffix, mrComplexMeta] +# 4. pui -> PU ("fire", posNotUnapplied) + 3SGI ("i"): underlying "pu"+"i" = "pui". The surface is +# u-then-i, NOT the i-then-u adjacency mrSimpleMeta requires, so metathesis correctly never fires +# (the non-unapplication pin) -- rules lists only the suffix. +# -> PU+3SGI|pui, rules: [mrISuffix] +# 5. sumulat -> SULAT ("write", posInfix) + AV (-um- infixed after the first consonant): "s"+"um"+ +# "ulat" = "sumulat". +# -> SULAT+AV|sumulat, rules: [mrInfixUm] +# +# The remaining words reuse these mechanisms on independent lexical material -- circumfix ke-...-an, +# CV- and full reduplication (ReduplicationHint), literal-final truncation, the isolated +# CopyFromInput/InsertSegments linker, and the noncontiguous perf + allophonic a->i raising -- or are +# expect_fail words whose signature is the empty set. See PROTOCOL.md section 3 for the `-`/empty- +# signature convention and the multi-character-segment rendering note. +# +# Reconciliation against the oracle (self-check): documented per word where the oracle disagreed with +# the hand derivation; the trace is authoritative per the task discipline. + +language: MetathesisPhaseIsolation +inspired_by: ["infix/circumfix/reduplication/metathesis/subtractive-truncation typology (typological pattern, not any specific language)"] +sources: + - "WALS - infixation, reduplication, and metathesis typology chapters" + - "WALS - infix, circumfix, and CV-reduplication morphological typology" + - "typological literature on consonant metathesis and the phase distinction; subtractive perfective typology" +requires: [phonology] +words: + - word: idil + note: >- + ADIL's own bare shape ("adil": posCircum, see below) already has "a" immediately before a + voiced consonant ("d") -- exactly prNonContig's trigger environment (see katibɯd, the KTB + perf word that raises the same way). prNonContig is scoped to posNonContig only, a + DIFFERENT part of speech than ADIL's own posCircum, so it never gets a chance to raise + ADIL's "a" even though the phonological environment is genuinely present. "idil" (the + raised form) is therefore unreachable under the grammar as declared. + Kept first in this list deliberately: severing LexicalEntry.partOfSpeech is a fixture-wide + mutation that ALSO breaks "adil"'s own bare-identity reading (forcing the same raising on + ADIL's own control word once the gate is gone fixture-wide) -- the paired witness this + claims needs THIS word, not "adil", to be the first one either severance changes. + expect_fail: true + blocked_by: [prNonContig] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + # Claims the McDc:AbsentGatedForm cell of conformance/dataflow-obligations.tsv's obligation matrix. + # DataflowClaimGate checks this against conformance/dataflow-obligations.tsv, never trusts it, + # and recomputes severing/before/after by re-severing the writer and reader named in the ledger + # row -- the inline values below are what it recomputed against, not what it trusts blindly. + claimed_cells: + - cell: "PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech::McDc:AbsentGatedForm" + severing: >- + ADIL's own partOfSpeech="posCircum" (the writer), or prNonContig's PhonologicalSubrule + requiredPartsOfSpeech="posNonContig" (the reader) -- severing either alone lets + prNonContig apply to ADIL too + before: "ok::-" + after: "ok::ADIL|idil" + distinct_from: adil + proof: >- + "idil" needs prNonContig (a -> i before a voiced consonant, gated to a DIFFERENT part + of speech, posNonContig) to fire on ADIL's own root; with both constructs intact this + word has zero parses (ok::-). Removing either the writer (LexicalEntry's partOfSpeech) + or the reader (prNonContig's requiredPartsOfSpeech) lets prNonContig apply to ADIL as + well, producing ok::ADIL|idil -- the AbsentGatedForm arm: the required part of speech + is ABSENT from ADIL and the phonological subrule's requirement GATES on it. adil + (ADIL's own bare, un-raised surface) is the control that shows the root is otherwise + ordinary and fully valid, so idil's block is attributable specifically to prNonContig's + gate, not to ADIL failing to parse at all. + + - word: nui + note: >- + NIU ("coconut", posSimpleMeta) underlying "niu" -- mrSimpleMeta swaps the adjacent i-then-u to + u-then-i (leftSwitch=u, rightSwitch=i), the metathesis/simple_rule mechanism. Obligatory, so + the underlying "niu" never itself surfaces (see next word). + provenance: "MetathesisRuleTests.SimpleRule" + parses: + - signature: "NIU|nui" + gloss: coconut + rules: [mrSimpleMeta] + exercises: + - "MetathesisRule" + + - word: niu + note: The raw, un-metathesized underlying shape -- mrSimpleMeta is obligatory wherever an i-then-u adjacency holds, so this surface form can never be a valid analysis (mirrors v1 simple_rule's own negative row). + expect_fail: true + blocked_by: [mrSimpleMeta] + exercises: + - "MetathesisRule" + + - word: mu+i + note: >- + MI ("come", posComplexMeta) + 3SGU ("+u") -- underlying "mi"+"+u" = "mi+u", then mrComplexMeta + (i +BND u -> u +BND i, final-anchored, with a non-switch BoundaryMarker between the switch + roles) swaps across the boundary. The visible "+" boundary renders as "+?" in the signature + shape (metathesis/complex_rule mechanism). + provenance: "MetathesisRuleTests.ComplexRule" + parses: + - signature: "MI+3SGU|mu+?i" + gloss: come-3SG + rules: [mrUSuffix, mrComplexMeta] + exercises: + - "MetathesisRule" + - "Boundary markers (CharacterDefinitionTable)" + + - word: mi + note: MI ("come", posComplexMeta) bare root, no suffix -- mrComplexMeta has no i +BND u site, so nothing fires. + parses: + - signature: "MI|mi" + gloss: come + rules: [] + exercises: [] + + - word: pui + note: >- + PU ("fire", posNotUnapplied) + 3SGI ("i") -- underlying "pu"+"i" = "pui". The surface is + u-then-i, NOT the i-then-u adjacency mrSimpleMeta requires, so the shared metathesis rule + correctly never fires (metathesis/not_unapplied's non-unapplication pin); rules names only the + suffix. + provenance: "MetathesisRuleTests.SimpleRuleNotUnapplied" + parses: + - signature: "PU+3SGI|pui" + gloss: fire-3SG + rules: [mrISuffix] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: sumulat + note: SULAT ("write", posInfix) + AV -- actor-voice -um- infixed after the first consonant, "s"+"um"+"ulat" = "sumulat". + provenance: "W9.1 probe, AffixProcessRuleTests.InfixRules" + parses: + - signature: "SULAT+AV|sumulat" + gloss: write-AV + rules: [mrInfixUm] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + + - word: sulat + note: SULAT bare root, no infix -- a plain control. + parses: + - signature: "SULAT|sulat" + gloss: write + rules: [] + exercises: [] + + - word: keadilan + note: ADIL ("just", posCircum) + NMLZ -- ke-...-an nominalizer wraps the stem, "ke"+"adil"+"an" = "keadilan". + provenance: "W9.1 probe, AffixProcessRuleTests.CircumfixRules" + parses: + - signature: "NMLZ+ADIL|keadilan" + gloss: NMLZ-just + rules: [mrCircum] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + + - word: adil + note: ADIL bare root, no circumfix -- a plain control. + parses: + - signature: "ADIL|adil" + gloss: just + rules: [] + exercises: [] + + - word: tutula + note: >- + TULA ("help", posRedup) with CV- reduplication (ReduplicationHint prefix): the first C-V ("tu") + is copied as the reduplicant prefix, then the whole stem -- "tu"+"tula" = "tutula". + parses: + - signature: "RDP+TULA|tutula" + gloss: RED-help + rules: [mrRedupCV] + exercises: + - "AffixProcessRule: reduplication (ReduplicationHint)" + + - word: tulatula + note: >- + TULA with full reduplication (ReduplicationHint prefix): the whole stem is copied twice, + "tula"+"tula" = "tulatula". + parses: + - signature: "RDPL+TULA|tulatula" + gloss: RED.FULL-help + rules: [mrRedupFull] + exercises: + - "AffixProcessRule: reduplication (ReduplicationHint)" + + - word: tula + note: TULA bare root, no reduplication -- a plain control. + parses: + - signature: "TULA|tula" + gloss: help + rules: [] + exercises: [] + + - word: pur + note: >- + PURE ("finish", posTrunc) + INCP -- subtractive truncation deletes the literal final "e" + (a subtractive incomplete-phase / subtractive-perfective typological pattern, cited in + provenance), "pure" -> "pur". + provenance: "W9.1 probe, AffixProcessRuleTests.TruncateRules" + parses: + - signature: "PURE+INCP|pur" + gloss: finish-INCP + rules: [mrTrunc] + exercises: + - "AffixProcessRule: subtraction/truncation" + + - word: pure + note: PURE bare root, no truncation -- a plain control. + parses: + - signature: "PURE|pure" + gloss: finish + rules: [] + exercises: [] + + - word: bahain + note: >- + BAHA ("flood", posLnk) + LNK -- the isolated CopyFromInput/InsertSegments demo: a plain linker + suffix "-in" with no phonology and no infixation, so the two output actions are exercised on + their own, "baha"+"in" = "bahain". + parses: + - signature: "BAHA+LNK|bahain" + gloss: flood-LNK + rules: [mrLnk] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + + - word: baha + note: BAHA bare root, no linker -- a plain control. + parses: + - signature: "BAHA|baha" + gloss: flood + rules: [] + exercises: [] + + - word: katibɯd + note: >- + KTB ("arrange", posNonContig) + PERF -- the triconsonantal root gets an "a" inserted after C1 + and C2 plus a trailing "ɯd" (k+a+t+a+b+ɯd = katabɯd), then prNonContig raises the "a" before the + voiced "b" to "i" -> "katibɯd" (the first "a", before voiceless "t", is left unchanged). The + noncontiguous affix + allophonic-rewrite interplay. + provenance: "W9.1 probe, AffixProcessRuleTests.NonContiguousRules" + parses: + - signature: "KTB+PERF|katibɯd" + gloss: arrange-PERF + rules: [mrPerf, prNonContig] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: katabɯd + note: The raw, un-raised underlying shape of the perf form -- prNonContig obligatorily raises the "a" before a voiced consonant, so this surface form can never itself be a valid analysis (see katibɯd). + expect_fail: true + blocked_by: [prNonContig] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: ktb + note: KTB bare triconsonantal root, no perf affix -- a plain control. + parses: + - signature: "KTB|ktb" + gloss: arrange + rules: [] + exercises: [] diff --git a/conformance/languages/polysynthetic-stratal-derivation-chain/grammar.xml b/conformance/languages/polysynthetic-stratal-derivation-chain/grammar.xml new file mode 100644 index 000000000..901f7b91a --- /dev/null +++ b/conformance/languages/polysynthetic-stratal-derivation-chain/grammar.xml @@ -0,0 +1,439 @@ + + + + + PolysyntheticStratalDerivationChain + + + n + v + n1 + v1 + n2 + v2 + nDelR + nMultiSeg + nMDC + + + + cons+- + voc+- + high+- + low+- + back+- + round+- + voice+- + + place + + bilabial + labiodental + alveolar + sibilant + lateral + velar + uvular + nasalLab + nasalAlv + vocalic + + + + + + Main + + + a + + + + + + i + + + + + + u + + + + + + + p + + + + + + b + + + + + + m + + + + + + v + + + + + + t + + + + + + s + + + + + + l + + + + + + n + + + + + + k + + + + + + q + + + + + + + + + + + + + + Any + + HighVowel + + + + HFUVowel + + + + + VowelU + + + + + BackRndVowel + + + + + TSeg + + + + + iDeletion + + + + + + + + + + + + + multiSegRaising + + + + + + + + + + + + + mdcRaising + + + + + + + + + + + + mdcTDeletion + + + + + + + + + + + + + + + Phonology + + + + bubui + DR1 + probe.bubui + + + buibu + DR2 + probe.buibu + + + buibui + DR3 + probe.buibui + + + + kuiikuii + MS + probe.multiseg + + + + buiibuii + MDC + probe.mdc + + + + matu + MDC2 + probe.mdc2 + + + + utui + MDC3 + probe.mdc3 + + + + + + Derivation + + + + verbalize + + + + liq + + + DERIV + + + + compoundHeadNonHead + + + + + + + + + + + prefixPi1 + + + + pi + + + PIPFX1 + + + + compoundNonHeadHead + + + + + + + + + + + prefixMa2 + + + + ma + + + MAPFX2 + + + + + + [Any]* + + + nuna + NUNA + land + + + + aku + AKU + meat + + + tat + TATN + shadow + + + tat + TATV + tie + + + + sila + SILA + weather + + + nuk + NUKN + horn + + + nuk + NUKV + pull + + + + + + Inflection + + + + indic3sg + + + + vuq + + + INFL + + + + + + diff --git a/conformance/languages/polysynthetic-stratal-derivation-chain/words.yaml b/conformance/languages/polysynthetic-stratal-derivation-chain/words.yaml new file mode 100644 index 000000000..0e015c3c8 --- /dev/null +++ b/conformance/languages/polysynthetic-stratal-derivation-chain/words.yaml @@ -0,0 +1,372 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). +# +# 1. nuna -> NUNA ("land", posN) bare noun root, no rule -> trivially valid. +# -> NUNA|nuna, rules: [] +# 2. nunaliq -> NUNA + DERIV ("-liq", posN->posV verbalizer, in the deep Derivation stratum): the +# root is verbalized, no inflection yet. +# -> NUNA+DERIV|nunaliq, rules: [mrDeriv] +# 3. nunaliqvuq -> NUNA + DERIV + INFL ("-vuq", posV->posV, in the shallower Inflection stratum): +# the derived posV stem built in stratum 0 feeds inflection in stratum 1 -- recursion across +# strata, the stratum-ordering headline. +# -> NUNA+DERIV+INFL|nunaliqvuq, rules: [mrDeriv, mrInfl] +# 4. nunavuq -> INFL attempted directly on the bare noun "nuna": mrInfl requires posV, but "nuna" +# is posN and nothing verbalized it, so inflection can never attach -> zero parses. +# -> expect_fail, blocked_by: [mrInfl] +# 5. akutat -> AKU ("meat", posN1 head) + TAT (posN1/posV1 nonhead, homophonous) compounded +# head+nonHead via mrCompoundHN: the nonhead "tat" resolves as BOTH its noun (TATN) and verb +# (TATV) reading, so two analyses. The "+" seam renders as "+?". +# -> AKU+TATN|aku+?tat ; AKU+TATV|aku+?tat, rules: [mrCompoundHN] each +# +# The remaining words reuse these mechanisms on independent lexical/rule material -- the prefix- +# commute compounding Set 2, the Guesser/LexicalGuess pattern, and the three seam-phonology probes +# (i-deletion multi-site unapplication, multi-segment raising, and the P6 deletion-composition) -- or +# are expect_fail words whose signature is the empty set. +# +# Reconciliation against the oracle (self-check): documented per word where the oracle disagreed with +# the hand derivation; the trace is authoritative per the task discipline. In particular, the +# multi-parse "bubu" word carries prDelReins on every parse because TraceRuleAttributor unions the +# phonological rules fired across all of a word's analyses (its own documented ambiguous-word +# limitation, the same one templatic-root-modification's gigugu note records) -- here that union is honest +# anyway, since every "bubu" analysis genuinely deletes an "i". +# +# Coverage addendum (bucket-1 obligation sweep): silaaku adds a word only, no grammar change -- the +# construct it exercises (mrCompoundHN's headPartsOfSpeech) was already declared. +# silaaku -> mrCompoundHN attempted with SILA (posN2) as HEAD, mismatching headPartsOfSpeech="posN1" +# -> zero parses (HeadRequiredSyntacticFeatureStruct, conformance/gate-obligations.tsv). + +language: PolysyntheticStratalDerivationChain +inspired_by: ["polysynthetic derivation-then-inflection across strata, with noun-incorporation-style compounding and recursive postbase-style suffixation (typological pattern, not any specific language)"] +sources: + - "WALS - polysynthesis, noun incorporation, and derivation chapters" + - "typological literature on derivation strata and noun incorporation" + - "typological literature on recursive derivational suffixation and postbase ordering" +requires: [phonology] +words: + - word: nuna + note: NUNA ("land", posN) bare noun root -- no rule touches it, trivially valid. + parses: + - signature: "NUNA|nuna" + gloss: land + rules: [] + exercises: [] + + - word: nunaliq + note: NUNA + DERIV ("-liq", posN->posV verbalizer) in the deep Derivation stratum -- verbalized, not yet inflected. + parses: + - signature: "NUNA+DERIV|nunaliq" + gloss: land-VBLZ + rules: [mrDeriv] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: nunaliqvuq + note: >- + NUNA + DERIV + INFL -- the derivational "-liq" applies in the deep Derivation stratum (posN-> + posV), then the derived verb stem feeds the inflectional "-vuq" (3sg indicative) in the + shallower Inflection stratum: recursion across strata, the stratum-ordering headline construct. + parses: + - signature: "NUNA+DERIV+INFL|nunaliqvuq" + gloss: land-VBLZ-3SG.IND + rules: [mrDeriv, mrInfl] + exercises: + - "Stratum (Linear/Unordered rule order)" + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: nunavuq + note: INFL attempted directly on the bare noun "nuna" -- mrInfl requires a posV stem, but nothing verbalized "nuna" (posN), so inflection can never attach. Zero parses (inflection presupposes the derivation stratum ran). + expect_fail: true + blocked_by: [mrInfl] + exercises: + - "Stratum (Linear/Unordered rule order)" + # Claims the McDc:AbsentGatedForm cell of conformance/dataflow-obligations.tsv's obligation matrix. + # DataflowClaimGate checks this against conformance/dataflow-obligations.tsv, never trusts it, + # and recomputes severing/before/after by re-severing the writer and reader named in the ledger + # row -- the inline values below are what it recomputed against, not what it trusts blindly. + claimed_cells: + - cell: "PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm" + severing: >- + partOfSpeech across every LexicalEntry (the one that matters here is NUNA's posN), as the + writer, or mrInfl's MorphologicalRule.requiredPartsOfSpeech="posV" gate, as the reader -- + severing either alone unblocks this word + before: "ok::-" + after: "ok::NUNA+INFL|nunavuq" + distinct_from: nunaliqvuq + proof: >- + nunavuq is mrInfl attempted directly on the bare noun NUNA (posN); with both constructs + intact, inflection cannot attach (ok::-). Removing either the writer (LexicalEntry's + partOfSpeech) or the reader (mrInfl's requiredPartsOfSpeech) lets inflection attach + anyway, producing NUNA+INFL|nunavuq -- the AbsentGatedForm arm: the required feature is + ABSENT and the rule's requirement GATES on it. nunaliqvuq (NUNA+DERIV+INFL, where mrDeriv + verbalizes the root to posV first) is the control that shows mrInfl applies normally once + the required POS is actually present, so nunavuq's block is attributable to the gate, not + to mrInfl never applying at all. + + - word: akutat + note: >- + AKU ("meat", posN1 head) + TAT (nonhead) compounded head+nonHead via mrCompoundHN -- "tat" is + homophonous between its noun (TATN) and verb (TATV) reading and both resolve as the non-head + root, so two analyses sharing the surface "aku+tat" (rendered "aku+?tat" with the "+" boundary). + parses: + - signature: "AKU+TATN|aku+?tat" + gloss: meat-shadow + rules: [mrCompoundHN] + exercises: + - "CompoundingRule" + - "Boundary markers (CharacterDefinitionTable)" + - signature: "AKU+TATV|aku+?tat" + gloss: meat-tie + rules: [mrCompoundHN] + exercises: + - "CompoundingRule" + - "Boundary markers (CharacterDefinitionTable)" + + - word: pitat + note: TAT's verb reading (TATV, posV1) with the pi- prefix, standalone (no compounding) -- proves mrPrefixPi1 works in isolation, so akupitat's rejection below is specifically the non-head-must-be-a-root constraint. + parses: + - signature: "PIPFX1+TATV|pitat" + gloss: PFX-tie + rules: [mrPrefixPi1] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: akupitat + note: >- + AKU (head) + pi-prefixed TAT compounded head+nonHead -- the non-head span "pitat" is prefix+root, + NOT a bare root, and mrCompoundHN's analysis-side search requires the non-head to already be a + bare root (AnalysisCompoundingRule discards a non-root non-head), so this has zero parses -- the + distinguishing non-head-not-root pin. + expect_fail: true + blocked_by: [mrCompoundHN] + provenance: "P3, CompoundingRuleTests.SimpleRules reconfiguration 3 (non-head-not-root variant)" + exercises: + - "CompoundingRule" + + - word: akutas + note: AKU + "tas" -- "tas" is neither a root nor any rule's output, so no compound analysis exists at all. + expect_fail: true + exercises: + - "CompoundingRule" + + - word: silaaku + note: >- + SILA ("weather", posN2) attempted as the HEAD of mrCompoundHN, with AKU ("meat", posN1) as + nonhead -- mrCompoundHN's own headPartsOfSpeech="posN1" never matches SILA's declared posN2. + Unlike a nonhead-POS mismatch (checked, unrecorded, during the analysis-direction root search -- + AnalysisCompoundingRule.cs:65-73 silently discards a non-conforming nonhead candidate before it + is ever passed on for confirmation), a head-POS mismatch survives to the synthesis-direction + confirm step and is traced there (SynthesisCompoundingRule.cs:100-114). mrCompoundNH's own + attempt at "silaaku" (nonhead=SILA, head=AKU) also fails, on ITS OWN head-side gate + (headPartsOfSpeech="posN2 posV2" never matches AKU's posN1). Zero parses. + expect_fail: true + blocked_by: [mrCompoundHN] + exercises: + - "CompoundingRule" + # Claims the Blocked arm of conformance/gate-obligations.tsv's HeadRequiredSyntacticFeatureStruct + # gate. Unlike kutu/patu in edge-cases/compounding-breadth (which fail via HeadRequired + # HeadFeatures/HeadRequiredFootFeatures, leaving CompoundingRule.headPartsOfSpeech itself + # unaffected by severing), this word's failure is a genuine HEAD PART-OF-SPEECH mismatch, so + # severing headPartsOfSpeech -- the gate's own hardcoded severance target + # (EngineGateInventoryLedger.DtdAttributes) -- actually flips it. + + - word: silanuk + note: >- + SILA ("weather", posN2 nonhead) + NUK (head) compounded nonHead+head via mrCompoundNH -- "nuk" + is homophonous between its noun (NUKN) and verb (NUKV) reading on the HEAD, so two analyses + sharing "sila+nuk" (rendered "sila+?nuk"). + parses: + - signature: "SILA+NUKN|sila+?nuk" + gloss: weather-horn + rules: [mrCompoundNH] + exercises: + - "CompoundingRule" + - "Boundary markers (CharacterDefinitionTable)" + - signature: "SILA+NUKV|sila+?nuk" + gloss: weather-pull + rules: [mrCompoundNH] + exercises: + - "CompoundingRule" + - "Boundary markers (CharacterDefinitionTable)" + + - word: silamanuk + note: >- + SILA (nonhead) + ma-prefixed NUK (head) compounded nonHead+head -- here the prefix attaches to + the HEAD span, which mrCompoundNH's non-head-root requirement never constrains, so it succeeds + where akupitat failed. mrPrefixMa2 requires posV2, so only NUK's verb reading (NUKV) is + prefix-eligible: exactly one analysis, not two. The prefix commutes with compounding. + provenance: "P3, CompoundingRuleTests.SimpleRules reconfiguration 3 (prefix-commute variant)" + parses: + - signature: "SILA+MAPFX2+NUKV|sila+?manuk" + gloss: weather-PFX-pull + rules: [mrCompoundNH, mrPrefixMa2] + exercises: + - "CompoundingRule" + + - word: silamak + note: SILA + "mak" -- "mak" is neither NUK nor any valid prefixed-head shape, so no compound analysis exists. + expect_fail: true + exercises: + - "CompoundingRule" + + - word: takuvuq + note: >- + Guesser/LexicalGuess: "taku" (see) is deliberately absent from the lexicon, so a normal parse + finds nothing; with root-guessing on, the "[Any]*" lexical pattern guesses a posV root, which + the inflection "-vuq" then attaches to. Two distinct guesses per PROTOCOL.md's pinned rendering + ("taku"+INFL, and the whole surface as a bare unaffixed root); a guessed root's morph-chain + component is the literal guessed substring itself, with no distinguishing marker. Each distinct + guess appears TWICE because this three-stratum grammar's analysis reaches the same guessable + shape at more than one stratum level (the guesser runs per analysis candidate, and the signature + multiset does not dedupe -- PROTOCOL.md section 3), so the honest multiset is 2x2. Self-check + only -- BatchCommand cannot guess, see PROTOCOL.md; the harness omits this word from adapter-mode + materialization. + parses: + - signature: "taku+INFL|takuvuq" + gloss: see-3SG.IND + guess: true + rules: [mrInfl] + exercises: + - "Guesser/LexicalGuess" + - signature: "taku+INFL|takuvuq" + guess: true + rules: [mrInfl] + exercises: + - "Guesser/LexicalGuess" + - signature: "takuvuq|takuvuq" + gloss: see.3SG.IND + guess: true + rules: [] + exercises: + - "Guesser/LexicalGuess" + - signature: "takuvuq|takuvuq" + guess: true + rules: [] + exercises: + - "Guesser/LexicalGuess" + + - word: bubu + note: >- + rewrite/deletion-reinsertion (P2 multi-site deletion unapplication): "i" is obligatorily deleted + after a high vowel, so the one surface "bubu" has THREE distinct underlying analyses -- DR1 + ("bubui", final i deleted), DR2 ("buibu", medial i deleted), DR3 ("buibui", both deleted). Every + analysis genuinely fired prDelReins, so the trace-union (see file header) is honest on every + parse. + provenance: "P2, RewriteRuleTests.DeletionRules first reconfiguration (multi-site deletion unapplication)" + parses: + - signature: "DR1|bubu" + gloss: probe.bubui + rules: [prDelReins] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + - signature: "DR2|bubu" + gloss: probe.buibu + rules: [prDelReins] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + - signature: "DR3|bubu" + gloss: probe.buibui + rules: [prDelReins] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: buibu + note: The raw underlying shape with an undeleted "i" after a high vowel -- prDelReins is obligatory, so this surface form can never itself be a valid analysis. + expect_fail: true + blocked_by: [prDelReins] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: kuuukuuu + note: >- + rewrite/multiplesegment (W9.2): MS ("kuiikuii") surfaces with each "ii" raised to "uu" after a + back-round vowel -- a 2-segment target rewrite, "kuiikuii" -> "kuuukuuu". + provenance: "W9.2 probe, RewriteRuleTests.MultipleSegmentRules" + parses: + - signature: "MS|kuuukuuu" + gloss: probe.multiseg + rules: [prMultiSeg] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: kuiikuii + note: The raw underlying shape with un-raised "ii" -- prMultiSeg is obligatory wherever an "ii" follows a back-round vowel, so this surface form can never itself be a valid analysis. + expect_fail: true + blocked_by: [prMultiSeg] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: buuubuuu + note: >- + rewrite/multiplesegment-deletion-composition (P6 group-capture fix): MDC ("buiibuii") surfaces + as "buuubuuu" via the same 2-segment raising (prMDC1), composed in the same stratum with a + pure-deletion rule (prMDC2, t -> nothing) that never fires here (no "t") but whose reverse- + analysis interposes an optional "t" between the raising rule's target pair -- the exact + composition the P6 fix addressed. Only prMDC1 fires in synthesis, so rules names just it. + provenance: "P6, RewriteRuleTests.MultipleSegmentRules second reconfiguration (group-capture fix)" + parses: + - signature: "MDC|buuubuuu" + gloss: probe.mdc + rules: [prMDC1] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: buiibuii + note: The raw underlying shape with un-raised "ii" -- prMDC1 is obligatory, so this surface form can never itself be a valid analysis. + expect_fail: true + blocked_by: [prMDC1] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: mau + note: >- + MDC2 ("matu") exercises the P6 grammar's SECOND rule (prMDC2, t -> nothing before a back-round + vowel) on its own: "matu" has a "t" before "u", so it surfaces as "mau". This rule is inert on + the buuubuuu composition above (no "t"), where only its analysis-direction reversal matters; here + it actually fires. + parses: + - signature: "MDC2|mau" + gloss: probe.mdc2 + rules: [prMDC2] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: matu + note: The raw underlying shape with an undeleted "t" before "u" -- prMDC2 is obligatory, so this surface form can never itself be a valid analysis (see mau). + expect_fail: true + blocked_by: [prMDC2] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: uui + note: >- + Ordering probe for prMDC1~prMDC2 (MDC3, "utui"): the trigger-u is directly before a "t", which + sits between it and the HighVowel pair "u i" -- prMDC1's LeftEnvironment needs the trigger + IMMEDIATELY before its target pair, so the intervening "t" blocks prMDC1 from ever firing here. + prMDC2 then deletes that "t" (its right neighbor "u" is back-round): "utui" -> "uui". This is + the fixture's DECLARED order (prMDC1 listed before prMDC2); see uuu below for what the swapped + order produces on the same root instead. + parses: + - signature: "MDC3|uui" + gloss: probe.mdc3 + rules: [prMDC2] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: uuu + note: >- + What prMDC1~prMDC2 SWAPPED would produce from the same MDC3 root ("utui"): prMDC2 running + first deletes the "t" (right neighbor "u" is back-round), which brings the trigger-u directly + against the HighVowel pair "u i" -- prMDC1's LeftEnvironment is now satisfied where it was not + before, so prMDC1 also fires, raising the "i" to "u" too. Not a valid surface form under this + fixture's declared order; the negative control that shows the order actually matters. + expect_fail: true + blocked_by: [prMDC1] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: utui + note: The raw underlying shape of MDC3, with neither the "t" deleted nor the vowel pair raised -- prMDC2 is obligatory wherever a "t" precedes a back-round vowel, so this surface form can never itself be a valid analysis (see uui). + expect_fail: true + blocked_by: [prMDC2] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" diff --git a/conformance/languages/prefixal-discontinuous-slot-dependency/grammar.xml b/conformance/languages/prefixal-discontinuous-slot-dependency/grammar.xml new file mode 100644 index 000000000..1072eb4bf --- /dev/null +++ b/conformance/languages/prefixal-discontinuous-slot-dependency/grammar.xml @@ -0,0 +1,198 @@ + + + + + PrefixalDiscontinuousSlotDependency + + v + + + + ClassA + ClassB + HighTrans + + + Main + + a + i + o + b + d + g + h + k + l + n + s + t + w + y + + + + + Any + + + + Main + + + + classifier + + + + d + + + CLF + CLF + + + + modeTransitivePerfective + + + + yi + + + PRF + TRANS.PRF + + + modeIntransitive + + + + wo + + + IMPF + INTR + + + + subject + + + + shi + + + + ni + + + SBJ + SBJ + + + + object + + + + bi + + + OBJ + 3OBJ + + + + disjunctA + + + + ga + + + ADVA + ITER + + + disjunctB + + + + ho + + + ADVB + AREAL + + + + + + verbPrefixTemplate + classifier + mode + subject + object + advA + advB + + + + + kal + KAL + carry + + + tan + TAN + speak + + + + + + diff --git a/conformance/languages/prefixal-discontinuous-slot-dependency/words.yaml b/conformance/languages/prefixal-discontinuous-slot-dependency/words.yaml new file mode 100644 index 000000000..93dff528d --- /dev/null +++ b/conformance/languages/prefixal-discontinuous-slot-dependency/words.yaml @@ -0,0 +1,219 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). This grammar is a pure STRESS grammar (spec Sec3 +# row 7): it embeds no v1 fixture and carries no provenance -- its job is exercising AffixTemplate +# morphology from the LEFT edge (a prefixal position-class template), which every other roster +# grammar (all suffix-dominant) leaves untested. +# +# The template (innermost -> outermost, i.e. application order for a prefixing rule -- see +# grammar.xml's AffixTemplate comment): classifier(1, obligatory) - mode(2, obligatory 2-way +# disjunctive slot) - subject(3, obligatory, adjacent-dependency disjunctive allomorphy) - +# object(4, optional, DISCONTINUOUS-dependency gate) - advA(5, optional, unconstrained) - +# advB(6, optional, unconstrained, outermost). +# +# 1. shiyidkal -> KAL ("carry", ruleFeatures="mprClassA") + the three OBLIGATORY slots only: +# mrClass ("d-") applies first (innermost) -> "dkal"; mrModeTrans ("yi-", ALSO sets +# mprHighTrans -- the FUSED portmanteau: one exponent realizing both the aspectual value and +# the transitivity-class marking a later slot depends on) applies next -> "yidkal"; mrSubj's +# subrule A (gated by mprClassA, "shi-") applies last (outermost of the three) -> "shiyidkal". +# Morph chain reads outermost-first (the deep-optional-affix-nesting P12..P1 convention): +# -> SBJ+PRF+CLF+KAL|shiyidkal, rules: [mrClass, mrModeTrans, mrSubj] +# 2. niyidtan -> TAN ("speak", ruleFeatures="mprClassB"), the SAME obligatory chain but mrSubj's +# OTHER subrule fires (gated by mprClassB, "ni-" instead of "shi-") -- proves the ADJACENT +# lexically-preset-class dependency picks the correct allomorph per root. +# -> SBJ+PRF+CLF+TAN|niyidtan, rules: [mrClass, mrModeTrans, mrSubj] +# 3. bishiyidkal -> KAL's obligatory chain (as in 1) PLUS mrObj ("bi-"): mrObj requires +# mprHighTrans, set two slots inward by mrModeTrans (slot 2) -- slot 3 (subject) sits in +# between and never touches this feature at all, so this is the DISCONTINUOUS dependency +# firing successfully across a skipped, irrelevant obligatory slot. +# -> OBJ+SBJ+PRF+CLF+KAL|bishiyidkal, rules: [mrClass, mrModeTrans, mrSubj, mrObj] +# 4. bishiwodkal -> the DISCONTINUOUS dependency's NEGATIVE control: KAL + mrClass + mrModeIntrans +# ("wo-", which does NOT set mprHighTrans -- a genuinely contrastive mode choice, not a free +# variant of mrModeTrans) + mrSubj, with mrObj ("bi-") attempted on top. mrObj's +# requiredMPRFeatures="mprHighTrans" is unsatisfied (only mrModeTrans sets it), so the object +# prefix cannot apply here at all -- zero parses, even though every other slot's own +# requirement is individually satisfied. +# -> expect_fail, blocked_by: [mrObj] +# 5. yidkal -> KAL + mrClass + mrModeTrans, but slot 3 (subject) is OBLIGATORY and omitted +# entirely -- the template cannot synthesize (or analyze) a completion missing an obligatory +# slot (mirrors suffixing-extension-slot-ordering's andik / suffixing-evidential-adjacency-chain's walakchik precedent, mirrored here +# from the LEFT edge instead of the right). +# -> expect_fail, blocked_by: [mrSubj] +# +# The remaining words reuse these same mechanisms on independent combinations (mrModeIntrans alone +# with no object attempted; the two-optional-slot stack advA+advB; a bare-root omitting ALL THREE +# obligatory slots) or exercise the LEFT-edge mirror of suffixing-extension-slot-ordering's own G2c-flagged finding: +# +# Reconciliation against the oracle (self-check): words 1-5 above, and every other word except one, +# matched the hand derivation on the first self-check run, including both expect_fail words' +# zero-parse status. ONE deliberate prediction was wrong, and the correction is itself the most +# useful finding in this file: "gahobishiyidkal" (the textual reverse of the flagship +# "hogabishiyidkal" -- advA's "ga-" and advB's "ho-" swapped in linear position). Having read +# suffixing-extension-slot-ordering's own andikilisha finding (G2c: an AffixTemplate's slot order is a hard SYNTHESIS +# constraint, but with two OPTIONAL, generically-shaped ["any segment, 1+"] slots, ANALYSIS can +# retry to a fixpoint and peel the two affixes off in either linear order), this word was +# hand-predicted to be ACCEPTED by the same mechanism -- mrAdvA/mrAdvB are just as optional and +# unconstrained as suffixing-extension-slot-ordering's causative/applicative pair. THE ORACLE REJECTS IT (zero parses), +# contradicting the prediction. Corrected in place below (expect_fail), and the reason why bantu- +# verbal's trick does NOT generalize here is itself instructive enough to trace all the way to +# engine source: `AnalysisAffixTemplateRule.ApplySlots` (src/SIL.Machine.Morphology.HermitCrab/ +# AnalysisAffixTemplateRule.cs) walks a template's slots from OUTERMOST to INNERMOST in ONE pass; at +# each slot index i it tries THAT slot's own rule at the word's CURRENT outer edge, and only if slot +# i is optional does it fall through to try slot i-1 at the SAME (unstripped) edge -- an obligatory +# slot's failure to match terminates the whole branch immediately, with no way back to a +# higher-indexed (already-passed) slot. suffixing-extension-slot-ordering's extensionTemplate has its ONE obligatory slot +# (finalVowel) at the OUTERMOST position, stripped first and unconditionally, so BOTH of its optional +# slots (causative, applicative) sit together, unobstructed, all the way to the root -- any +# out-of-turn match among them can fall through past the other via the optional-skip branch with +# nothing obligatory in the way. This grammar's swappable pair (advA, advB) is also outermost, but +# its three obligatory slots (subject, mode, classifier) sit BETWEEN that pair and the root: once +# advA is stripped out of its canonical (innermost-of-the-pair) turn, the very next slot the +# algorithm reaches inward is the OBLIGATORY subject slot -- and the actual next characters at the +# edge are advB's still-unstripped "ho-", not subject's "shi-"/"ni-", so subject's match fails and +# the whole branch dies with advB never given a chance to be tried (recursion only moves inward, it +# never revisits a slot index once passed). The complementary "skip advA first, try advB" branch +# dies exactly the same way one slot later. So the finding, honestly reconciled: an AffixTemplate's +# fixpoint analysis retry rescues an out-of-canonical-order pair of optional/unconstrained slots +# ONLY when every slot between that pair and the rest of the successful decomposition is ALSO +# optional -- an obligatory slot standing between the swappable pair and the root (as this prefixal +# template's obligatory-innermost design produces, the mirror image of suffixing-extension-slot-ordering's +# obligatory-outermost design) is a hard analysis-side order-enforcement mechanism after all, for +# THAT specific slot arrangement. G2c's finding is real but not universal; this grammar's structure +# is the counter-example that shows what condition it actually depends on. + +language: PrefixalDiscontinuousSlotDependency +inspired_by: ["prefixal left-edge position-class templates with fused/discontinuous slot dependencies (typological pattern, not any specific language)"] +sources: + - "WALS - Prefixing vs. suffixing morphology chapter; verb-template surveys" + - "typological literature on verb prefix position classes" + - "typological literature on morpheme order and semantic scope: discontinuous/fused prefix dependencies" +requires: [] +words: + - word: shiyidkal + note: >- + KAL ("carry") + the three OBLIGATORY slots only (classifier "d-", mode mrModeTrans "yi-", + subject mrSubj subrule A "shi-", gated by the root's own preset mprClassA). No optional slot + fires. Establishes the minimal well-formed word under this template. + parses: + - signature: "SBJ+PRF+CLF+KAL|shiyidkal" + gloss: carry-CLF-TRANS.PRF-SBJ + rules: [mrClass, mrModeTrans, mrSubj] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: niyidtan + note: >- + TAN ("speak") + the same obligatory chain as shiyidkal, but mrSubj's OTHER subrule fires + ("ni-", gated by the root's preset mprClassB instead of mprClassA) -- proves the + lexically-preset agreement class correctly conditions which subject allomorph a given root + takes (suffixing-extension-slot-ordering's kib/bel/nal precedent, applied to prefix-shape selection here). + parses: + - signature: "SBJ+PRF+CLF+TAN|niyidtan" + gloss: speak-CLF-TRANS.PRF-SBJ + rules: [mrClass, mrModeTrans, mrSubj] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: bishiyidkal + note: >- + KAL's obligatory chain (as in shiyidkal) plus mrObj ("bi-"): mrObj requires mprHighTrans, set + TWO slots inward by mrModeTrans (slot 2) -- slot 3 (subject) sits in between and never + touches this feature at all. This is the DISCONTINUOUS slot dependency the roster names: an + outer prefix's admissibility hinges on a non-adjacent inner prefix's own choice, skipping an + intervening (obligatory but irrelevant-to-this-gate) slot. + parses: + - signature: "OBJ+SBJ+PRF+CLF+KAL|bishiyidkal" + gloss: carry-CLF-TRANS.PRF-SBJ-3OBJ + rules: [mrClass, mrModeTrans, mrSubj, mrObj] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: bishiwodkal + note: >- + The discontinuous dependency's NEGATIVE control: KAL + mrClass + mrModeIntrans ("wo-", a + genuinely contrastive mode choice that does NOT set mprHighTrans) + mrSubj, with mrObj + ("bi-") attempted on top. mrObj's gate is unsatisfied (only mrModeTrans sets mprHighTrans), + so the object prefix cannot apply here even though every other slot's own requirement holds + individually. Zero parses -- proves the discontinuous dependency is a genuine gate, not a + trivially-always-true one (mrClass/mrModeTrans/mrModeIntrans/mrSubj are all obligatory-slot + or always-available material, so without this gate "bishiwodkal" would otherwise parse fine). + expect_fail: true + blocked_by: [mrObj] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: yidkal + note: >- + KAL + mrClass + mrModeTrans, but slot 3 (subject) is OBLIGATORY in the AffixTemplate and + omitted entirely -- the template cannot synthesize (or analyze) a completion missing an + obligatory slot, mirroring suffixing-extension-slot-ordering's andik / suffixing-evidential-adjacency-chain's walakchik precedent + from the LEFT edge instead of the right. + expect_fail: true + blocked_by: [mrSubj] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: kal + note: >- + KAL entirely bare -- all three obligatory slots (classifier, mode, subject) are omitted at + once, the simplest possible negative control for an obligatory-slot-heavy template. + expect_fail: true + blocked_by: [mrClass] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: shiwodkal + note: >- + KAL + mrClass + mrModeIntrans ("wo-") + mrSubj, with NO object slot attempted -- proves + mrModeIntrans is independently well-formed on its own (the discontinuous gate above rejects + it only in combination with mrObj, not on its own terms). + parses: + - signature: "SBJ+IMPF+CLF+KAL|shiwodkal" + gloss: carry-CLF-INTR-SBJ + rules: [mrClass, mrModeIntrans, mrSubj] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: gabishiyidkal + note: bishiyidkal's chain plus mrAdvA ("ga-"), the first of the two outermost optional, unconstrained slots. + parses: + - signature: "ADVA+OBJ+SBJ+PRF+CLF+KAL|gabishiyidkal" + gloss: carry-CLF-TRANS.PRF-SBJ-3OBJ-ITER + rules: [mrClass, mrModeTrans, mrSubj, mrObj, mrAdvA] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: hogabishiyidkal + note: >- + The flagship, fully-loaded word: ALL SIX slots fire (classifier, mode, subject, object, advA, + advB), in the template's own canonical linear order -- advB ("ho-") outermost, advA ("ga-") + just inside it. Exercises 6 of this grammar's 7 rule ids in a single word. + parses: + - signature: "ADVB+ADVA+OBJ+SBJ+PRF+CLF+KAL|hogabishiyidkal" + gloss: carry-CLF-TRANS.PRF-SBJ-3OBJ-ITER-AREAL + rules: [mrClass, mrModeTrans, mrSubj, mrObj, mrAdvA, mrAdvB] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: gahobishiyidkal + note: >- + THE order-swap reconciliation word (see header): the textual reverse of hogabishiyidkal's two + outermost prefixes (advA's "ga-" now outermost, advB's "ho-" now just inside it). Hand-predicted + ACCEPTED on the strength of suffixing-extension-slot-ordering's own andikilisha finding (G2c) -- WRONG: the oracle + REJECTS it (zero parses). Reconciled by tracing AnalysisAffixTemplateRule.ApplySlots: bantu- + verbal's swappable pair had nothing but optional slots between it and the root (its one + obligatory slot, finalVowel, sits outermost and is stripped first, unconditionally); this + grammar's swappable pair (advA/advB) has THREE OBLIGATORY slots (subject, mode, classifier) + between it and the root. Once advA is stripped out of its canonical turn, the very next slot + the single-pass, outer-to-inner analysis walk reaches is the obligatory subject slot -- but the + actual next characters are advB's still-unstripped "ho-", not a subject prefix, so subject's + match fails and the whole branch dies immediately (the algorithm only moves inward, it can + never revisit advB once passed). The symmetric "skip advA, try advB out of turn" branch dies + the same way one slot later. So: a fixpoint-retry rescue for an out-of-order optional pair + requires EVERY slot between that pair and the root to ALSO be optional -- an obligatory slot in + the way (this template's obligatory-innermost design, the mirror of suffixing-extension-slot-ordering's + obligatory-outermost one) is a real, working order-enforcement mechanism for analysis too, not + just synthesis. G2c's finding does not generalize to every template shape; this is the + counter-example that shows the actual condition it depends on. + expect_fail: true + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" diff --git a/conformance/languages/suffixing-evidential-adjacency-chain/grammar.xml b/conformance/languages/suffixing-evidential-adjacency-chain/grammar.xml new file mode 100644 index 000000000..617968eaa --- /dev/null +++ b/conformance/languages/suffixing-evidential-adjacency-chain/grammar.xml @@ -0,0 +1,334 @@ + + + + + SuffixingEvidentialAdjacencyChain + + v + + + Main + + + a + i + u + + k + l + m + n + p + s + sh + t + w + y + ch + + + + + Any + + Vowel + + + Consonant + + + + + + + + Main + + + + person1sg + + + + + + + + ni + + + + + + + + + + + + y + + + + + + + 1SG + + + + person2sg + + + + nki + + + 2SG + + + + person3sg + + + + n + + + 3SG + + + + person1plIncl + + + + tuku + + + 1PL.INCL + + + + person2pl + + + + lupa + + + 2PL + + + + plural + + + + chik + + + PL + + + + evidDirect + + + + mi + + + DIR + + + + evidReportative + + + + si + + + + shi + + + REP + + + + evidConjectural + + + + cha + + + CONJ + + + + evidAssumptive + + + + tan + + + ASSUM + + + + evidMirative + + + + was + + + MIR + + + + + verbTemplate + + person + + number + + evidential + + + + + walak + WALAK + carry.about + + + sipu + SIPU + weave + + + + tupa + TUPA + gather + + + tupa + TUPA2 + arrive + + + + + taki + kanta + + SING + sing + + + + + + + + + + + + + + + + + + + + + diff --git a/conformance/languages/suffixing-evidential-adjacency-chain/words.yaml b/conformance/languages/suffixing-evidential-adjacency-chain/words.yaml new file mode 100644 index 000000000..c63abd317 --- /dev/null +++ b/conformance/languages/suffixing-evidential-adjacency-chain/words.yaml @@ -0,0 +1,412 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from): +# +# 1. tupay = TUPA-or-TUPA2 (root, homophonous pair) + 1SG. Root ends in vowel "a" -> mrPerson1's +# post-vowel allomorph "-y" fires -> "tupa"+"y" = "tupay". Both eTupa and eTupa2 share the exact +# shape "tupa", so BOTH are valid roots for this surface word: two distinct analyses. +# -> TUPA+1SG|tupay ; TUPA2+1SG|tupay (ambiguous, 2 parses) +# 2. walakni = WALAK + 1SG. Root ends in consonant "k" -> post-consonant allomorph "-ni" fires. +# -> WALAK+1SG|walakni +# 3. walaknichik = WALAK + 1SG("-ni") + PL("-chik"): obligatory slot 1 + optional slot 2. +# -> WALAK+1SG+PL|walaknichik [see reconciliation note below: the oracle disagreed here] +# 4. walaknkicha = WALAK + 2SG("-nki") + CONJ("-cha"): the MorphemeCoOccurrenceRule excludes +# mrEvidConjectural from co-occurring with mrPerson2 (anywhere) -> zero parses. +# -> expect_fail, blocked_by: [mrEvidConjectural] +# 5. walakchik = WALAK + PL("-chik") only, no person suffix at all: slot 1 (person) is obligatory +# and unfilled, so the AffixTemplate can never produce this output (same mechanism as +# conformance/negative/obligatory-tense-slot's "tunz") -> zero parses. +# -> expect_fail +# +# Reconciliation against the oracle (self-check): 4 of 5 matched on the first run. #3 +# (walaknichik) did NOT: the oracle produced "walakni(ch)ik", not the plain-concatenation +# "walaknichik" this hand derivation assumed. The oracle is right and the hand derivation was +# naive: HermitCrabExtensions.ToRegexString unconditionally wraps any character-definition segment +# whose string representation is more than one character (here, the "ch"/"sh" digraph segments this +# grammar defines for the plural/reportative suffixes) in its own parentheses, regardless of +# ambiguity -- see conformance/PROTOCOL.md section 3's addendum. This affected every word in the +# fixture containing a "ch" or "sh" digraph (walaknichik, walaknkishi, sipuncha, walaknkichikmi), +# corrected below to match the oracle once this was understood; every other signature in this file +# matched the hand derivation (or the same pattern, once recognized) with no further disagreement. +# +# G2e ADDENDUM (coverage-parity fix, W6): this grammar was authored in the G1 pilot before the +# provenance-carrying discipline was enforced, and its one MorphemeCoOccurrenceRule (mrEvidConjectural +# excludes mrPerson2) did not faithfully embed 3 v1 cooccurrence/* fixtures the ledger assigns to it. +# grammar.xml gained: (1) a new eTaki/SING morpheme with two free-variation allomorphs (aTaki/aKanta), +# one (aKanta) carrying an AllomorphCoOccurrenceRule excluding CONJ -- cooccurrence/allomorph-basic; +# (2) 4 new slot-1/slot-3 members (mrPerson1PlIncl/mrPerson2Pl/mrEvidAssum/mrEvidMir) each carrying one +# of the remaining 4 MorphemeCoOccurrenceRule adjacency kinds (mrEvidConjectural's rule already +# exercised "anywhere") -- cooccurrence/morpheme-adjacency; (3) a second exclude rule on +# mrEvidConjectural (excludes eTupa2, a root that never co-occurs with CONJ here, so trivially +# satisfied) -- cooccurrence/and-semantics-pin (LT-22156 AND-not-OR semantics). Hand derivations for +# the new words below, BEFORE the oracle: +# 6. takiy = SING(aTaki, "taki")+1SG. Root ends vowel "i" -> mrPerson1 post-vowel "-y". +# -> SING+1SG|takiy +# 7. kantay = SING(aKanta, "kanta")+1SG, same allomorph-selection rule, CONJ absent so aKanta's +# AllomorphCoOccurrenceRule (excludes subEvidConj) is vacuously satisfied. +# -> SING+1SG|kantay +# 8. takincha = SING(aTaki)+3SG("-n")+CONJ("-cha"): aTaki carries NO co-occurrence rule, so it +# combines with CONJ freely -- the distinguishing row proving the rule is scoped to aKanta only, +# not to the whole SING morpheme. "ch" digraph -> paren-wrapped, same as sipun(ch)a. +# -> SING+3SG+CONJ|takin(ch)a +# 9. kantancha = SING(aKanta)+3SG+CONJ: aKanta's AllomorphCoOccurrenceRule fires (subEvidConj +# present) -> zero parses. +# -> expect_fail, blocked_by: [aKanta] +# 10. walaknitan = WALAK+1SG("-ni")+ASSUM("-tan"), adjacent -> mrEvidAssum's "somewhereToLeft" +# requirement on mrPerson1 is satisfied (trivially, since adjacent is also "somewhere"). +# -> WALAK+1SG+ASSUM|walaknitan +# 11. walaknichiktan = WALAK+1SG+PL("-chik")+ASSUM: PL intervenes between PERSON and ASSUM, but +# "somewhereToLeft" only needs mrPerson1 present somewhere left, so it STILL passes. +# -> WALAK+1SG+PL+ASSUM|walakni(ch)iktan +# 12. walakniwas = WALAK+1SG+MIR("-was"), adjacent -> mrEvidMir's "adjacentToLeft" requirement on +# mrPerson1 is satisfied (immediately adjacent). +# -> WALAK+1SG+MIR|walakniwas +# 13. walaknichikwas = WALAK+1SG+PL+MIR: PL now sits directly between PERSON and MIR, so +# "adjacentToLeft" FAILS (the somewhereToLeft/adjacentToLeft distinguishing pair, vs #11) -> +# zero parses. +# -> expect_fail, blocked_by: [mrEvidMir] +# 13b. walakntan = WALAK+3SG("-n")+ASSUM: mrPerson1 (not just any person) is required, and 3SG is +# not mrPerson1, so "somewhereToLeft" fails even with no PL involved at all -- guards against +# a no-op "somewhereToLeft" that #10/#11 alone would not catch (both keep mrPerson1 present). +# -> expect_fail, blocked_by: [mrEvidAssum] +# 14. siputukumi = SIPU+1PL.INCL("-tuku")+DIR("-mi"), adjacent -> mrPerson1PlIncl's +# "somewhereToRight" requirement on mrEvidDirect is satisfied. +# -> SIPU+1PL.INCL+DIR|siputukumi +# 15. siputukuchikmi = SIPU+1PL.INCL+PL+DIR: PL intervenes between the person suffix and DIR, but +# "somewhereToRight" only needs mrEvidDirect present somewhere right, so it STILL passes. +# -> SIPU+1PL.INCL+PL+DIR|siputuku(ch)ikmi +# 15b. siputuku = SIPU+1PL.INCL alone, no evidential at all: mrEvidDirect is absent entirely, so +# "somewhereToRight" fails even with no PL involved -- guards against a no-op +# "somewhereToRight" that #14/#15 alone would not catch (both keep mrEvidDirect present). +# -> expect_fail, blocked_by: [mrPerson1PlIncl] +# 16. sipulupami = SIPU+2PL("-lupa")+DIR, adjacent -> mrPerson2Pl's "adjacentToRight" requirement +# on mrEvidDirect is satisfied (immediately adjacent). +# -> SIPU+2PL+DIR|sipulupami +# 17. sipulupachikmi = SIPU+2PL+PL+DIR: PL now sits directly between the person suffix and DIR, so +# "adjacentToRight" FAILS (distinguishing pair vs #15) -> zero parses. +# -> expect_fail, blocked_by: [mrPerson2Pl] + +language: SuffixingEvidentialAdjacencyChain +inspired_by: ["suffixing evidential-marking verbal morphology with morpheme-adjacency co-occurrence constraints (typological pattern, not any specific language)"] +sources: + - "WALS - Suffixing vs. Prefixing in Inflectional Morphology" + - "typological literature on verbal morphology and evidentiality" + - "Aikhenvald, Evidentiality (2004)" +requires: [] +words: + - word: tupay + note: >- + Homophonous-root ambiguity: eTupa and eTupa2 share the identical shape "tupa", so this + surface word has two genuinely distinct analyses. Root-final vowel "a" selects mrPerson1's + post-vowel allomorph "-y". + parses: + - signature: "TUPA+1SG|tupay" + gloss: gather-1SG + rules: [mrPerson1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + - signature: "TUPA2+1SG|tupay" + gloss: arrive-1SG + rules: [mrPerson1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: sipuy + note: Root SIPU ends in vowel "u"; mrPerson1's post-vowel allomorph "-y" fires, same as tupay but with a non-homophonous root (single unambiguous parse). + parses: + - signature: "SIPU+1SG|sipuy" + gloss: weave-1SG + rules: [mrPerson1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walakni + note: Root WALAK ends in consonant "k"; mrPerson1's post-consonant allomorph "-ni" fires -- the environment-conditioned allomorph selection pair with sipuy/tupay, done lexically (RequiredEnvironments), not via a phonological rule. + parses: + - signature: "WALAK+1SG|walakni" + gloss: carry.about-1SG + rules: [mrPerson1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walaky + note: >- + Root WALAK ends in consonant "k", so mrPerson1's post-VOWEL allomorph "-y" (subPerson1PostV, + gated by its own RequiredEnvironments requiring a preceding vowel) can never attach to it -- + only the post-consonant "-ni" allomorph (walakni above) is licensed for this root. Distinct + from walakni: that word shows the post-consonant environment being SATISFIED; this one shows + the post-vowel environment being VIOLATED, the negative half of the same lexical + allomorph-selection gate. + provenance: "fold-in: dtd:element/RequiredEnvironments, PresentInLanguageGrammarAlready per conformance/fold-in-candidates.tsv -- walakni/tupay/sipuy alone never flip when RequiredEnvironments is severed, since each already satisfies its own subrule's environment; this word is the one whose current failure the gate is solely responsible for" + expect_fail: true + blocked_by: [mrPerson1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walaknki + note: Root WALAK + 2SG ("-nki"), the unconstrained disjunctive-slot-1 sibling of mrPerson1/mrPerson3. + parses: + - signature: "WALAK+2SG|walaknki" + gloss: carry.about-2SG + rules: [mrPerson2] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: sipun + note: Root SIPU + 3SG ("-n"), the third disjunctive slot-1 choice. + parses: + - signature: "SIPU+3SG|sipun" + gloss: weave-3SG + rules: [mrPerson3] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walaknichik + note: Root WALAK + 1SG("-ni", obligatory slot 1) + PL("-chik", optional slot 2) -- proves an optional slot composes once the obligatory slot is satisfied. + parses: + - signature: "WALAK+1SG+PL|walakni(ch)ik" + gloss: carry.about-1SG-PL + rules: [mrPerson1, mrPlural] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: sipuymi + note: Root SIPU + 1SG("-y") + DIR evidential ("-mi", optional slot 3) -- the evidential chain's direct-evidence member, skipping the optional number slot entirely. + parses: + - signature: "SIPU+1SG+DIR|sipuymi" + gloss: weave-1SG-DIR + rules: [mrPerson1, mrEvidDirect] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walaknkisi + note: Root WALAK + 2SG + REP evidential, allomorph A ("-si"). Pairs with walaknkishi to demonstrate free-fluctuation -- neither allomorph is rejected in favor of the other (Allomorph.FreeFluctuatesWith), they are simply two independently valid surface realizations of REP. + parses: + - signature: "WALAK+2SG+REP|walaknkisi" + gloss: carry.about-2SG-REP + rules: [mrPerson2, mrEvidReportative] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: walaknkishi + note: Root WALAK + 2SG + REP evidential, allomorph B ("-shi") -- the free-fluctuation partner of walaknkisi (see that word's note). + parses: + - signature: "WALAK+2SG+REP|walaknki(sh)i" + gloss: carry.about-2SG-REP + rules: [mrPerson2, mrEvidReportative] + exercises: + - "Disjunctive allomorphs / free-fluctuation" + + - word: sipuncha + note: >- + Root SIPU + 3SG + CONJ evidential ("-cha") -- a positive exercise of mrEvidConjectural, + unblocked because BOTH of its MorphemeCoOccurrenceRules pass: rule1 (excludes mrPerson2) is + satisfied since person is 3SG, not 2SG; rule2 (excludes eTupa2, see walaknkicha's note) is + satisfied since the root here is SIPU, not eTupa2. + parses: + - signature: "SIPU+3SG+CONJ|sipun(ch)a" + gloss: weave-3SG-CONJ + rules: [mrPerson3, mrEvidConjectural] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: takiy + note: >- + SING(aTaki, "taki")+1SG: root-final vowel "i" selects mrPerson1's post-vowel allomorph "-y", + same mechanism as sipuy/tupay. eTaki is a new morpheme with two free-variation allomorphs + (aTaki/aKanta, a native/Spanish-contact-loan doublet); this word uses the allomorph that + carries NO AllomorphCoOccurrenceRule at all. + parses: + - signature: "SING+1SG|takiy" + gloss: sing-1SG + rules: [mrPerson1] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: kantay + note: >- + SING(aKanta, "kanta")+1SG, the free-variation partner of takiy: aKanta carries an + AllomorphCoOccurrenceRule excluding co-occurrence with CONJ's subrule (subEvidConj), but CONJ + is absent here, so the rule is vacuously satisfied and the word is valid. + parses: + - signature: "SING+1SG|kantay" + gloss: sing-1SG + rules: [mrPerson1] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: takincha + note: >- + SING(aTaki)+3SG("-n")+CONJ("-cha"): aTaki carries no co-occurrence rule at all, so it combines + with CONJ freely -- the distinguishing row proving aKanta's AllomorphCoOccurrenceRule (see + kantancha below) is scoped to that one allomorph, not to the whole SING morpheme (C#'s + Allomorph.AllomorphCoOccurrenceRules lives on RootAllomorph, not Morpheme). + parses: + - signature: "SING+3SG+CONJ|takin(ch)a" + gloss: sing-3SG-CONJ + rules: [mrPerson3, mrEvidConjectural] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: kantancha + note: >- + SING(aKanta)+3SG+CONJ: aKanta's AllomorphCoOccurrenceRule (excludes subEvidConj, anywhere) + fires because CONJ is present -- zero parses. Contrast with takincha above, which uses the + SAME morpheme's sibling allomorph and succeeds: the rule is allomorph-scoped, not + morpheme-scoped. + provenance: "W6, AllomorphCoOccurrenceRule granularity" + expect_fail: true + blocked_by: [aKanta] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: walaknitan + note: >- + WALAK+1SG("-ni")+ASSUM("-tan"), adjacent: mrEvidAssum (a new evidential slot-3 member) carries + a MorphemeCoOccurrenceRule requiring mrPerson1 "somewhereToLeft" -- satisfied here since + mrPerson1 is immediately to its left. + provenance: "W6, MorphemeCoOccurrenceRule + all 5 adjacency kinds" + parses: + - signature: "WALAK+1SG+ASSUM|walaknitan" + gloss: carry.about-1SG-ASSUM + rules: [mrPerson1, mrEvidAssum] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: walaknichiktan + note: >- + WALAK+1SG+PL("-chik")+ASSUM: PL now intervenes between mrPerson1 and mrEvidAssum, but + "somewhereToLeft" only requires mrPerson1 to be present somewhere to the left, not adjacent -- + still satisfied, unlike walaknichikwas below. + parses: + - signature: "WALAK+1SG+PL+ASSUM|walakni(ch)iktan" + gloss: carry.about-1SG-PL-ASSUM + rules: [mrPerson1, mrPlural, mrEvidAssum] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: walakntan + note: >- + WALAK+3SG("-n")+ASSUM("-tan"): mrEvidAssum's MorphemeCoOccurrenceRule requires mrPerson1 + SPECIFICALLY (not just any person) somewhereToLeft. Person here is 3SG, so mrPerson1 is + absent entirely, and the "somewhereToLeft" require fails regardless of adjacency -- unlike + walaknitan/walaknichiktan above, which both keep mrPerson1 present and only vary whether PL + intervenes. Without this word, a no-op "somewhereToLeft" implementation (always satisfied) + would go undetected, since every other word exercising mrEvidAssum already has mrPerson1 + present. Zero parses. + expect_fail: true + blocked_by: [mrEvidAssum] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: walakniwas + note: >- + WALAK+1SG+MIR("-was"), adjacent: mrEvidMir (the somewhereToLeft/adjacentToLeft distinguishing + partner of mrEvidAssum) carries a MorphemeCoOccurrenceRule requiring mrPerson1 + "adjacentToLeft" -- satisfied here since mrPerson1 is immediately adjacent. + parses: + - signature: "WALAK+1SG+MIR|walakniwas" + gloss: carry.about-1SG-MIR + rules: [mrPerson1, mrEvidMir] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: walaknichikwas + note: >- + WALAK+1SG+PL+MIR: PL now sits directly between mrPerson1 and mrEvidMir, so "adjacentToLeft" + fails even though mrPerson1 is present somewhere to the left -- the distinguishing row against + walaknichiktan above (same PL-intervening configuration, but "somewhereToLeft" tolerates it + and "adjacentToLeft" does not) -- zero parses. + expect_fail: true + blocked_by: [mrEvidMir] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: siputukumi + note: >- + SIPU+1PL.INCL("-tuku")+DIR("-mi"), adjacent: mrPerson1PlIncl (a new 4th disjunctive slot-1 + person member) carries a MorphemeCoOccurrenceRule requiring mrEvidDirect "somewhereToRight" -- + satisfied here since mrEvidDirect is immediately to its right. + parses: + - signature: "SIPU+1PL.INCL+DIR|siputukumi" + gloss: weave-1PL.INCL-DIR + rules: [mrPerson1PlIncl, mrEvidDirect] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: siputukuchikmi + note: >- + SIPU+1PL.INCL+PL("-chik")+DIR: PL now intervenes between mrPerson1PlIncl and mrEvidDirect, but + "somewhereToRight" only requires mrEvidDirect to be present somewhere to the right, not + adjacent -- still satisfied, unlike sipulupachikmi below. + parses: + - signature: "SIPU+1PL.INCL+PL+DIR|siputuku(ch)ikmi" + gloss: weave-1PL.INCL-PL-DIR + rules: [mrPerson1PlIncl, mrPlural, mrEvidDirect] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: siputuku + note: >- + SIPU+1PL.INCL("-tuku") alone, no evidential at all: mrPerson1PlIncl's + MorphemeCoOccurrenceRule requires mrEvidDirect somewhereToRight, but no evidential slot is + filled here, so mrEvidDirect is absent entirely and the "somewhereToRight" require fails + regardless of adjacency -- unlike siputukumi/siputukuchikmi above, which both keep + mrEvidDirect present and only vary whether PL intervenes. Without this word, a no-op + "somewhereToRight" implementation (always satisfied) would go undetected, since every other + word exercising mrPerson1PlIncl already has mrEvidDirect present. Zero parses. + expect_fail: true + blocked_by: [mrPerson1PlIncl] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: sipulupami + note: >- + SIPU+2PL("-lupa")+DIR, adjacent: mrPerson2Pl (the somewhereToRight/adjacentToRight + distinguishing partner of mrPerson1PlIncl) carries a MorphemeCoOccurrenceRule requiring + mrEvidDirect "adjacentToRight" -- satisfied here since mrEvidDirect is immediately adjacent. + parses: + - signature: "SIPU+2PL+DIR|sipulupami" + gloss: weave-2PL-DIR + rules: [mrPerson2Pl, mrEvidDirect] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: sipulupachikmi + note: >- + SIPU+2PL+PL+DIR: PL now sits directly between mrPerson2Pl and mrEvidDirect, so + "adjacentToRight" fails even though mrEvidDirect is present somewhere to the right -- the + distinguishing row against siputukuchikmi above (same PL-intervening configuration, but + "somewhereToRight" tolerates it and "adjacentToRight" does not) -- zero parses. + expect_fail: true + blocked_by: [mrPerson2Pl] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: walaknkichikmi + note: Root WALAK + 2SG(slot1, obligatory) + PL(slot2, optional) + DIR(slot3, optional) -- the full 3-slot evidential chain filled at once, showing all three slots compose together in one word. + parses: + - signature: "WALAK+2SG+PL+DIR|walaknki(ch)ikmi" + gloss: carry.about-2SG-PL-DIR + rules: [mrPerson2, mrPlural, mrEvidDirect] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walakchik + note: Root WALAK + PL only, no person suffix at all. Slot 1 (person) is obligatory and unfilled, so the AffixTemplate can never produce this output at all (mirrors conformance/negative/obligatory-tense-slot's "tunz" case) -- zero parses. + expect_fail: true + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: walaknkicha + note: >- + Root WALAK + 2SG + CONJ evidential. mrEvidConjectural carries TWO MorphemeCoOccurrenceRules: + rule1 excludes mrPerson2 (fails here, 2SG is present); rule2 excludes eTupa2 (trivially + satisfied, the root here is WALAK, not eTupa2). AND-not-OR semantics (history row 5, 90dcee64, + #311/LT-22156): the word is rejected because rule1 alone fails, regardless of rule2 passing -- + pre-90dcee64 C# used `.Any(IsWordValid)`, under which rule2's trivial pass would have wrongly + rescued this word. Zero parses under the correct post-fix semantics. + provenance: "history row 5 (90dcee64, #311/LT-22156): AND-not-OR co-occurrence semantics" + expect_fail: true + blocked_by: [mrEvidConjectural] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" diff --git a/conformance/languages/suffixing-extension-slot-ordering/grammar.xml b/conformance/languages/suffixing-extension-slot-ordering/grammar.xml new file mode 100644 index 000000000..9108921fa --- /dev/null +++ b/conformance/languages/suffixing-extension-slot-ordering/grammar.xml @@ -0,0 +1,736 @@ + + + + + SuffixingExtensionSlotOrdering + + + vNasalMutation + vRealizational + vMprGroups + vExtension + vReduplication + vAgreement + + vSecondSweep + + vPhonoReq + vPhonoExcl + + + + cons+- + voc+- + high+- + back+- + voice+- + nasal+- + + place + + bilabial + dental + sibilant + nasalM + nasalN + lateral + glottal + velar + labiovelar + palatal + uvular + vocalic + + + + + + + tense + + pres + past + + + + + num + + sg + pl + + + + + g5 + + g5a + g5b + + + + + + + stress + + stressed + unstressed + + + + + + ExtA + ExtB + ConcA + ConcB + ConcC + ConcD + + RRealTest + + PhX + PhY + PhExcl + PhonoGroup + ExtGroup + AllConc + AnyConc + + + + + G5Stem + + + + + + + Main + + + a + + + + + + e + + + + + + i + + + + + + + b + + + + + + p + + + + + + d + + + + + + s + + + + + + z + + + + + + m + + + + + + n + + + + + + l + + + + + + h + + + + + + k + + + + + + w + + + + + + y + + + + + + x + + + + + + + + + Any + + Nasal + + + + VoicelessBilabial + + + + VoicedBilabial + + + + + + + FamRRealBlock + + + + + nasalMutation + + + + + + + + + + + + + phonoReq + + + + + + + + + + + + + phonoExcl + + + + + + + + + + + + + + Main + + + + tense + + + + pe + + + + TENSE + + + realizPast + + + + ile + + + + RPAST + + + + extX + + + + x + + + EXTX + + + extY + + + + y + + + EXTY + + + endZ + + + + z + + + ENDZ + + + + endW + + + + w + + + ENDW + + + endH + + + + h + + + ENDH + + + + redup + + + + + + + RED + + + + causative + + + + ish + + + CAUS + + + applicative + + + + il + + + APPL + + + finalVowel + + + + a + + + FV + + + + numPl + + + + ep + + + + + NUMPL + + + agr + + + + ez + + + + + AGR + + + + recurSuf + + + + iz + + + RECURSUF + + + + stemReq + + + + eh + + + STEMREQ + + + + rRealTest + + + + ed + + + + RREALTEST + + + + phonoDestroy + + + + el + + + PHDESTROY + + + + phXSource + + + + ez + + + PHXSRC + + + + + extensionTemplate + causative + applicative + finalVowel + + + + + + mpa + PAV + hit + + + + lima + LIM + cultivate + + + + kib + KIB + root.kib + + + bel + BEL + root.bel + + + nal + NAL + root.nal + + + + + lis + PHXROOT + root.phxroot + + + npa + PPO + root.ppo + + + mpe + PPE + root.ppe + + + + sek + SEK + root.sek + + + + andik + AND + write + + + + kimbia + KIMB + run + + + + dab + DAB + cook + + + + kes + + + KES + sing + + + + sil + SIL + plant + + + + dal + DAL + dig + + + dah + DAH + climb + + + + zim + + ZIM + fly + + + zam + + ZAM + swim + + + wep + + WEP + dive + + + + + + diff --git a/conformance/languages/suffixing-extension-slot-ordering/words.yaml b/conformance/languages/suffixing-extension-slot-ordering/words.yaml new file mode 100644 index 000000000..bcbd7b54c --- /dev/null +++ b/conformance/languages/suffixing-extension-slot-ordering/words.yaml @@ -0,0 +1,691 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). +# +# 1. mba -> PAV ("hit", posV) bare root, underlying "mpa": prNasalMutation (posV-scoped subrule) +# obligatorily voices the "p" to "b" following the nasal "m" -> "mba". The raw "mpa" itself can +# never surface for this candidate (see mpa below). +# -> PAV|mba, rules: [prNasalMutation] +# 2. mpa -> the SAME underlying shape "mpa", but analyzed as the (nonexistent) posN-equivalent -- +# no such rule ever gates a posV-only subrule off, so instead this is eMpaV's own OWN candidate, +# analyzed as unmutated: impossible, since prNasalMutation is obligatory for posV. Zero parses +# would follow IF eMpaV were the only lexical entry sharing shape "mpa" -- but there is no +# second (posV-immune) lexical entry sharing "mpa" in this word list, so "mpa" is simply +# expect_fail on its own terms (prNasalMutation's obligatory synthesis-confirm never lets the +# raw "mpa" survive as PAV's own surface). +# -> expect_fail, blocked_by: [prNasalMutation] +# 3. lima -> LIM ("cultivate", posV2) bare root, no rule applied. +# -> LIM|lima, rules: [] +# 4. limaile -> LIM + RPAST (a RealizationalRule, no AffixTemplate needed): the root's own FS has +# no tense value at all, so IsBlocked's presence check finds nothing to collide with. +# -> LIM+RPAST|limaile, rules: [rrPast] +# 5. limapeile -> LIM + TENSE ("-pe", sets tense=pres) attempted together with RPAST: IsBlocked +# sees tense is ALREADY present (pres, not past) and blocks anyway (presence-only, not +# value-equality) -> zero parses. +# -> expect_fail, blocked_by: [rrPast] +# +# The remaining words reuse these same mechanisms on independent lexical/rule material -- MPR +# features/groups (Overwrite + All/Any gating, mirroring fusional-realizational-morphology's own proof exactly), +# verbal reduplication (ReduplicationHint, zero coverage today -- this grammar's home), and +# extension-slot ordering via AffixTemplate (Causative before Applicative, both before the +# obligatory Final Vowel) -- or are expect_fail words whose signature is the empty set. +# +# Reconciliation against the oracle (self-check): all 5 words above matched the hand derivation on +# the first self-check run. Two genuine reconciliations were needed elsewhere in the file: +# 1. Reduplication (mrRedup's redupMorphType="suffix"): the hand derivation assumed morph order +# ROOT+RED (the "existing"/first copy keeping the root's own morpheme identity, the "new"/ +# second copy carrying RED), verified correct by an isolated probe before this word was added +# to the file (see grammar.xml's mrRedup comment) -- no --propose correction was needed once +# that probe's finding was applied. redupMorphType does set this order: "suffix" (here) and +# "implicit" both give ROOT+RED (KIMB+RED|kimbiakimbia); "prefix" gives RED+ROOT +# (RED+KIMB|kimbiakimbia). +# 2. Extension-slot ordering ("andikilisha", the intended wrong-order negative control): hand- +# derived as expect_fail on the assumption that the AffixTemplate's declared slot sequence +# (causative before applicative) forbids the reverse surface order -- the oracle instead +# ACCEPTS it (AND+APPL+CAUS+FV). Confirmed by an isolated 2-slot probe (see that word's own +# note for the full mechanism): the template's slot order is a hard SYNTHESIS constraint and +# constrains a single analysis-side unwind the same way, but with two OPTIONAL, generically- +# shaped slots, the overall stratum analysis retries the rule set (including the template) to a +# fixpoint, so the two affixes can be peeled off across separate template applications in +# either order. Corrected in place rather than discarded, since it is a genuine and useful +# engine finding for any future template-heavy grammar (prefixal-discontinuous-slot-dependency especially). +# Every other word in the file matched on the first run. + +language: SuffixingExtensionSlotOrdering +inspired_by: ["noun-class-agreement and CARP-style verbal-extension-ordering typology, with post-nasal-mutation allomorphy (typological pattern, not any specific language)"] +sources: + - "WALS - Reduplication chapters; noun-class and verbal-template surveys" + - "typological literature on suffix ordering (CARP hierarchy: Causative-Applicative-Reciprocal-Passive)" + - "typological literature on post-nasal mutation / post-nasal hardening-voicing" +requires: [phonology] +words: + # Bucket-2 coverage (LexicalEntry.ruleFeatures/MorphologicalOutput.MPRFeatures -> + # PhonologicalSubrule.{required,excluded}MPRFeatures): placed FIRST in file order deliberately, AND + # the "distinguishing" (baseline-fail) word placed BEFORE its own bare-form control in each pair. + # InterfaceWitnessLedger's severance sweep reports the FIRST word (in this file's own order) whose + # outcome changes AT ALL when an (element, attribute) pair is stripped fixture-wide -- not the first + # FAVORABLE flip -- and DataflowObligationLedger.FindPairedWitness only credits a cell when the + # writer's and the reader's reported words are the SAME word. Severing requiredMPRFeatures/ + # excludedMPRFeatures affects BOTH members of a pair at once (the mutated word fail->pass, its own + # bare control pass->fail), so whichever sits earlier in file order wins the report; putting the + # fail->pass word first is what makes it (rather than its own control) the reported witness. + - word: mbe + note: >- + THE distinguishing row for LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures: + PPE ("root.ppe", posV3excl), mutated. PPE's own ruleFeatures="mprPhExcl" is exactly what + prPhonoExcl's excludedMPRFeatures="mprPhExcl" excludes, so the mutation can never fire for PPE -- + zero parses. Removing either PPE's own LexicalEntry.ruleFeatures (the writer, so the exclusion is + vacuously satisfied) or prPhonoExcl's own excludedMPRFeatures (the reader, so there is no + exclusion left to trip) unblocks it independently, to the identical successful parse. mpe + (below) is the control showing the root's bare form is otherwise unaffected. Placed ahead of + nba/npa (below): severing LexicalEntry.ruleFeatures ALSO flips nba (PPO's own bare form, + pass->fail), and the sweep reports whichever word differs FIRST in file order, so mbe has to + sit earlier than nba for its own fail->pass flip to be the one reported. + expect_fail: true + blocked_by: [prPhonoExcl] + exercises: + - "MPR features/groups" + claimed_cells: + - cell: "MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures::McDc:PresentGatedForm" + severing: >- + either PPE's own LexicalEntry.ruleFeatures="mprPhExcl" (the writer) or prPhonoExcl's own + PhonologicalSubrule.excludedMPRFeatures="mprPhExcl" gate (the reader) -- severing either + alone unblocks this word + before: "ok::-" + after: "ok::PPE|mbe" + distinct_from: mpe + proof: >- + mbe is PPE (carries mprPhExcl) attempting the post-nasal voicing minor rule; with both + constructs intact the mutation is blocked (zero parses). Removing either the writer (PPE's + ruleFeatures) or the reader (prPhonoExcl's excludedMPRFeatures) lets the same mutation + through, producing PPE|mbe -- the PresentGatedForm arm: the feature is PRESENT on the root + and the rule's exclusion GATES on it. + + - word: mpe + note: >- + PPE bare root, underlying "mpe" -- PPE's own LexicalEntry.ruleFeatures presets mprPhExcl, and + prPhonoExcl's excludedMPRFeatures="mprPhExcl" gate blocks the post-nasal voicing minor rule + outright (a lexical exception, the *spinity shape of trisyllabic laxing in miniature) -- the + raw "mpe" surfaces unmutated. The control for mbe (above). + parses: + - signature: "PPE|mpe" + gloss: root.ppe + rules: [] + exercises: [] + + - word: nbael + note: >- + THE distinguishing row for MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures: + PPO ("root.ppo", posV3req) + mrPhonoDestroy ("-el"), mutated. PPO's own LexicalEntry.ruleFeatures + presets mprPhX; mrPhonoDestroy's own MorphologicalOutput MPRFeatures="mprPhY" write shares + PhonoGroup (outputType="overwrite") with mprPhX, so MprFeatureSet.AddOutput drops PPO's preset + before prPhonoReq's requiredMPRFeatures="mprPhX" gate is ever checked -- the mutation cannot + fire, so this has zero parses despite PPO genuinely carrying mprPhX at the lexical entry -- the + exact ygofz/mrEndZ shape (fusional-realizational-morphology), here for a PhonologicalSubrule reader instead of a + MorphologicalInput one. Removing either mrPhonoDestroy's own MorphologicalOutput.MPRFeatures + write (so the overwrite-triggering write never happens, and PPO's preset survives) or + prPhonoReq's own requiredMPRFeatures (so the gate no longer needs mprPhX at all) unblocks it + independently, to the identical successful parse -- the same word, from two unrelated + severances. npael (below) is the control showing the affix attaches normally when the mutation + is not attempted. + expect_fail: true + blocked_by: [prPhonoReq] + exercises: + - "MPR features/groups" + claimed_cells: + - cell: "MorphologicalPhonologicalRuleFeature::MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures::McDc:AbsentGatedForm" + severing: >- + either mrPhonoDestroy's own MorphologicalOutput.MPRFeatures="mprPhY" write (the writer) or + prPhonoReq's own PhonologicalSubrule.requiredMPRFeatures="mprPhX" gate (the reader) -- + severing either alone unblocks this word + before: "ok::-" + after: "ok::PPO+PHDESTROY|nbael" + distinct_from: npael + proof: >- + nbael is PPO (lexically preset with mprPhX) run through mrPhonoDestroy then prPhonoReq's + phonological gate; with both constructs intact, mrPhonoDestroy's write triggers PhonoGroup's + overwrite semantics (MprFeatureSet.AddOutput) and drops PPO's preset mprPhX before + prPhonoReq's gate is ever checked, so this has zero parses. Removing either the writer + (mrPhonoDestroy's own MorphologicalOutput.MPRFeatures, so the overwrite-triggering write + never happens) or the reader (prPhonoReq's requiredMPRFeatures, so the gate no longer needs + mprPhX) lets the mutation fire anyway, producing PPO+PHDESTROY|nbael -- the AbsentGatedForm + arm: the required feature is ABSENT (from the derivation's accumulated state, though never + from PPO's own declaration) and the rule's requirement GATES on it. + + - word: npael + note: >- + PPO + mrPhonoDestroy ("-el"), unmutated -- the control for nbael (above): with the mutation + never firing (PPO's preset mprPhX destroyed by mrPhonoDestroy's own write before prPhonoReq's + gate is checked), the raw "npa" shape survives into "npael". + parses: + - signature: "PPO+PHDESTROY|npael" + gloss: root.ppo-PHDESTROY + rules: [mrPhonoDestroy] + exercises: + - "MPR features/groups" + + - word: nba + note: >- + PPO bare root, underlying "npa" -- PPO's own LexicalEntry.ruleFeatures presets mprPhX with no + destroyer intervening, so prPhonoReq's requiredMPRFeatures="mprPhX" gate is satisfied and the + post-nasal voicing minor rule (same construct as prNasalMutation, MPR-gated instead of + POS-gated) fires obligatorily, exactly mirroring mba/mpa below. + parses: + - signature: "PPO|nba" + gloss: root.ppo + rules: [prPhonoReq] + exercises: + - "RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level" + + - word: npa + note: The raw, un-mutated underlying shape -- prPhonoReq is obligatory once its MPR gate is satisfied (PPO's own preset mprPhX), so this surface can never be a valid analysis of PPO. + expect_fail: true + blocked_by: [prPhonoReq] + exercises: + - "RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level" + + - word: lisez + note: >- + PHXROOT ("lis") + mrPhXSource ("-ez"): mrPhXSource's own MorphologicalOutput MPRFeatures="mprPhX" + write is what makes InteractionChainLedger count MorphologicalOutput.MPRFeatures-> + PhonologicalSubrule.requiredMPRFeatures as exercised at all (the same id, mprPhX, appearing in + both a MorphologicalOutput and a PhonologicalSubrule attribute value somewhere in this fixture) + -- mirrors mrThemeX's own role for fusional-realizational-morphology's ygofz. "lis" has no + nasal+voiceless-bilabial sequence, so prPhonoReq's mutation never fires here even though its MPR + gate is satisfied; this word demonstrates the write, not the mutation. + parses: + - signature: "PHXROOT+PHXSRC|lisez" + gloss: root.phxroot-PHXSRC + rules: [mrPhXSource] + exercises: + - "MPR features/groups" + + - word: mba + note: >- + PAV ("hit", posV) bare root, underlying "mpa" -- prNasalMutation obligatorily voices the "p" + to "b" following the nasal "m", a genuine post-nasal-voicing effect (modeled here as + already fused into the root's own stored shape, mirroring v1 rewrite/required-pos-subrule's + own bare-shape minimalism). + parses: + - signature: "PAV|mba" + gloss: hit + rules: [prNasalMutation] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: mpa + note: The raw, un-mutated underlying shape -- prNasalMutation is obligatory for posV wherever its nasal-left-environment holds, so this surface form can never itself be a valid analysis of PAV. + expect_fail: true + blocked_by: [prNasalMutation] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: lima + note: LIM ("cultivate", posV2), bare root, no lexical head features at all -- trivially valid, no rule touches it. + parses: + - signature: "LIM|lima" + gloss: cultivate + rules: [] + exercises: [] + + - word: limaile + note: LIM + RPAST (a RealizationalRule, no AffixTemplate/Slot wrapper needed) -- the root's own FS has no tense value at all, so RPAST's IsBlocked presence check finds nothing to collide with. + provenance: "W5, RealizationalAffixProcessRule core mechanics + IsBlocked" + parses: + - signature: "LIM+RPAST|limaile" + gloss: cultivate-PST.REALIZ + rules: [rrPast] + exercises: + - "RealizationalAffixProcessRule" + + - word: limape + note: LIM + TENSE ("-pe", ordinary affix, sets tense=pres) -- pre-loads a tense value so the realizational rule's blocking check below has something to trip on. + parses: + - signature: "LIM+TENSE|limape" + gloss: cultivate-PRES + rules: [mrTense] + exercises: + - "RealizationalAffixProcessRule" + + - word: limapeile + note: >- + LIM + TENSE + RPAST attempted together -- mrTense sets tense=pres first, then RPAST's + IsBlocked check sees tense is ALREADY present (even though it's pres, not past) and blocks -- + a value-equality mis-implementation would wrongly accept this; presence alone is what matters. + expect_fail: true + blocked_by: [rrPast] + exercises: + - "RealizationalAffixProcessRule" + + - word: kib + note: KIB ("root.kib", posV3), bare -- ruleFeatures preset both AllConc members (mprConcA, mprConcB) directly on the lexical entry. + parses: + - signature: "KIB|kib" + gloss: root.kib + rules: [] + exercises: [] + + - word: bel + note: BEL ("root.bel", posV3), bare -- ruleFeatures preset mprConcA (half of AllConc) and mprConcC (half of AnyConc). + parses: + - signature: "BEL|bel" + gloss: root.bel + rules: [] + exercises: [] + + - word: nal + note: NAL ("root.nal", posV3), bare -- no ruleFeatures preset at all. + parses: + - signature: "NAL|nal" + gloss: root.nal + rules: [] + exercises: [] + + - word: xkib + note: KIB prefixed by mrExtX ("x-", sets MPR feature mprExtA). + provenance: "W3.1, MprFeatureGroupOutput.Overwrite in MPR output accumulation" + parses: + - signature: "EXTX+KIB|xkib" + gloss: EXT.A-root.kib + rules: [mrExtX] + exercises: + - "MPR features/groups" + + - word: yxkib + note: KIB prefixed by mrExtX then mrExtY ("y-", sets mprExtB) -- ExtGroup's outputType="overwrite" means mrExtY's own output DROPS mprExtA rather than accumulating it alongside mprExtB. + parses: + - signature: "EXTY+EXTX+KIB|yxkib" + gloss: EXT.B-EXT.A-root.kib + rules: [mrExtX, mrExtY] + exercises: + - "MPR features/groups" + + - word: xkibz + note: KIB prefixed by mrExtX then suffixed by mrEndZ (requiredMPRFeatures="mprExtA") -- mprExtA is still present (only mrExtX applied), so mrEndZ's requirement is satisfied. + parses: + - signature: "EXTX+KIB+ENDZ|xkibz" + gloss: EXT.A-root.kib-END + rules: [mrExtX, mrEndZ] + exercises: + - "MPR features/groups" + + - word: yxkibz + note: >- + KIB prefixed by mrExtX then mrExtY then suffixed by mrEndZ -- the DISTINGUISHING row: after + mrExtY, ExtGroup's Overwrite semantics have already dropped mprExtA, so mrEndZ's + requiredMPRFeatures="mprExtA" fails. Zero parses. A pre-fix "flat union" mis-implementation + would wrongly accept this. + expect_fail: true + blocked_by: [mrEndZ] + exercises: + - "MPR features/groups" + + - word: kibw + note: KIB + mrEndW (requiredMPRFeatures="mprConcA mprConcB", matchType="all") -- KIB has both AllConc members, so the ALL requirement is satisfied. + provenance: "W3.1, MprFeatureGroupMatchType.All/Any in required-MPR gating" + parses: + - signature: "KIB+ENDW|kibw" + gloss: root.kib-ALL.END + rules: [mrEndW] + exercises: + - "MPR features/groups" + + - word: belw + note: BEL + mrEndW -- BEL has only mprConcA, not mprConcB, so the ALL requirement is NOT satisfied. Zero parses -- the pre-fix flat-overlap bug would have wrongly accepted this. + expect_fail: true + blocked_by: [mrEndW] + exercises: + - "MPR features/groups" + + - word: nalw + note: NAL + mrEndW -- NAL has neither AllConc member, so the ALL requirement fails outright. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: kibh + note: KIB + mrEndH (requiredMPRFeatures="mprConcC mprConcD", matchType="any") -- KIB has NEITHER AnyConc member, so the ANY requirement fails. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: belh + note: BEL + mrEndH -- BEL has mprConcC (one AnyConc member), so the ANY requirement (at least one) is satisfied. + parses: + - signature: "BEL+ENDH|belh" + gloss: root.bel-ANY.END + rules: [mrEndH] + exercises: + - "MPR features/groups" + + - word: nalh + note: NAL + mrEndH -- NAL has neither AnyConc member, so the ANY requirement fails. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: sek + note: >- + SEK ("root.sek", posV3), bare -- ruleFeatures preset every group member mrEndZ/mrEndW/mrEndH + gate on (mprExtA, both AllConc members, one AnyConc member), so this one root can chain all + three suffixes and expose the Stratum "Main" list-order dependency between them. + parses: + - signature: "SEK|sek" + gloss: root.sek + rules: [] + exercises: [] + + - word: sekzw + note: >- + SEK + mrEndZ + mrEndW, in that list order. The ordering discriminator for the mrEndZ~mrEndW + adjacent pair: "sekwz" below is the same two suffixes reversed, which only parses when the + list order is swapped. + parses: + - signature: "SEK+ENDZ+ENDW|sekzw" + gloss: root.sek-END-ALL.END + rules: [mrEndZ, mrEndW] + exercises: + - "MPR features/groups" + + - word: sekwz + note: >- + SEK + mrEndW + mrEndZ, the reverse of "sekzw". Zero parses under the shipped list order + (mrEndZ mrEndW): only reachable when mrEndW is transposed ahead of mrEndZ. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: sekwh + note: >- + SEK + mrEndW + mrEndH, in that list order. The ordering discriminator for the mrEndW~mrEndH + adjacent pair: "sekhw" below is the same two suffixes reversed, which only parses when the + list order is swapped. + parses: + - signature: "SEK+ENDW+ENDH|sekwh" + gloss: root.sek-ALL.END-ANY.END + rules: [mrEndW, mrEndH] + exercises: + - "MPR features/groups" + + - word: sekhw + note: >- + SEK + mrEndH + mrEndW, the reverse of "sekwh". Zero parses under the shipped list order + (mrEndW mrEndH): only reachable when mrEndH is transposed ahead of mrEndW. + expect_fail: true + exercises: + - "MPR features/groups" + + - word: kimbia + note: KIMB ("run/flee", posV5), bare root, no reduplication applied -- a plain, unrestricted control. + parses: + - signature: "KIMB|kimbia" + gloss: run + rules: [] + exercises: [] + + - word: kimbiakimbia + note: >- + KIMB fully reduplicated (intensive/repetitive aspect, "run"/"run about repeatedly"- + plausible): mrRedup copies the whole stem twice. + redupMorphType="suffix" treats the FIRST copy as the root's own continuing morph and the + SECOND as the rule's own new morph, so the morph chain reads root-then-RED (confirmed by an + isolated probe before this word was authored -- see grammar.xml's mrRedup comment). This is + the zero-coverage-today construct's home: no other v2 grammar carries ReduplicationHint. + parses: + - signature: "KIMB+RED|kimbiakimbia" + gloss: run-RED + rules: [mrRedup] + exercises: + - "AffixProcessRule: reduplication (ReduplicationHint)" + + - word: andika + note: AND ("write", posV4) + FV only ("-a") -- the obligatory Final Vowel slot filled, both optional extension slots (causative, applicative) skipped entirely. + parses: + - signature: "AND+FV|andika" + gloss: write-FV + rules: [mrFV] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: andik + note: AND bare, no Final Vowel at all -- slot 3 (finalVowel) is obligatory and unfilled, so the AffixTemplate can never produce this output (mirrors suffixing-vowel-harmony's kutak / suffixing-evidential-adjacency-chain's walakchik). + expect_fail: true + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: andikisha + note: AND + CAUS (slot 1, "-ish") + FV (slot 3, "-a") -- the optional applicative slot (slot 2) skipped, proving slot 1 and slot 3 compose independently of slot 2. + provenance: "plan item 2 (wave-3), requiredPartsOfSpeech on a phonological subrule" + parses: + - signature: "AND+CAUS+FV|andikisha" + gloss: write-CAUS-FV + rules: [mrCaus, mrFV] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: andikila + note: AND + APPL (slot 2, "-il") + FV (slot 3, "-a") -- causative (slot 1) skipped, the mirror-image partial fill of andikisha. + parses: + - signature: "AND+APPL+FV|andikila" + gloss: write-APPL-FV + rules: [mrAppl, mrFV] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: andikishila + note: >- + AND + CAUS (slot 1) + APPL (slot 2) + FV (slot 3), ALL THREE slots filled in the template's + own fixed order -- the extension-slot-ordering construct's flagship word, CARP-style + (Causative before Applicative, both before the obligatory Final Vowel). + parses: + - signature: "AND+CAUS+APPL+FV|andikishila" + gloss: write-CAUS-APPL-FV + rules: [mrCaus, mrAppl, mrFV] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: andikilisha + note: >- + The textual mirror-image of andikishila (applicative-then-causative instead of causative- + then-applicative) -- hand-derived as expect_fail (assumed the template's declared slot + sequence would forbid this order structurally), but the ORACLE ACCEPTS it. Reconciliation + finding, confirmed by an isolated 2-slot probe before correcting this word: AffixTemplate's + own slot sequence governs SYNTHESIS strictly (generation always produces causative-then- + applicative) and constrains a SINGLE analysis-side unwind of the template the same way, but + Slot 1/2 are both optional and their MorphologicalInput stems are both unconstrained + ("any segment, 1+"), so the overall stratum analysis (which retries its rule set, including + this template, to a fixpoint) can peel the affixes off across TWO separate template + applications: first CAUS strips from the outside ("andikilish" -> "andikil", since + applicative's own "-il" pattern doesn't match at that point), then the template is retried on + the result and APPL strips from ITS outside ("andikil" -> "andik"). Neither slot's rule ever + violated its own pattern; the "wrong order" is simply a different, also-valid decomposition of + the same string once repeated application is accounted for. A grammar wanting true analysis- + side order enforcement would need an MPR-feature gate between the two slots (this grammar's + own mpr-groups section demonstrates that mechanism); this template alone does not provide it. + parses: + - signature: "AND+APPL+CAUS+FV|andikilisha" + gloss: write-APPL-CAUS-FV + rules: [mrAppl, mrCaus, mrFV] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: dabep + note: >- + DAB ("cook", posV6) + mrNumPl ("-op") -- assigns featNum=pl (OutputHeadFeatures) and + featStress=stressed (OutputFootFeatures) to the resulting word. G5 (code-coverage-driven): + no other grammar in the suite exercises RequiredHeadFeatures/OutputHeadFeatures/ + RequiredFootFeatures/OutputFootFeatures at all before this pair of words. + provenance: "G5 coverage sweep, SyntacticFeatureSystem/XmlLanguageLoader head+foot feature paths" + parses: + - signature: "DAB+NUMPL|dabep" + gloss: cook-PL + rules: [mrNumPl] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: dabepez + note: >- + DAB + mrNumPl + mrAgr ("-ez") -- mrAgr's RequiredHeadFeatures (featNum=pl) and + RequiredFootFeatures (featStress=stressed) are both satisfied because mrNumPl already + assigned them, so the agreement suffix can attach on top. + provenance: "G5 coverage sweep, SyntacticFeatureSystem/XmlLanguageLoader head+foot feature paths" + parses: + - signature: "DAB+NUMPL+AGR|dabepez" + gloss: cook-PL-AGR + rules: [mrNumPl, mrAgr] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: dabez + note: >- + DAB + mrAgr directly, WITHOUT the intervening mrNumPl -- reconciliation finding: a bare root + carries no featNum/featStress value at all, and an UNSET feature unifies freely against + mrAgr's RequiredHeadFeatures/RequiredFootFeatures (unification, not presence-checking), so + this analysis succeeds vacuously rather than failing. Contrast with kesez below, whose root + carries an explicit CONFLICTING value via AssignedHeadFeatures/AssignedFootFeatures -- that + is what actually trips the requirement. + provenance: "G5 coverage sweep, SyntacticFeatureSystem/XmlLanguageLoader head+foot feature paths" + parses: + - signature: "DAB+AGR|dabez" + gloss: cook-AGR + rules: [mrAgr] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kes + note: >- + KES ("sing", posV6) bare root -- carries AssignedHeadFeatures featNum=sg and + AssignedFootFeatures featStress=unstressed directly on the lexical entry (both previously at + zero coverage: AssignedFootFeatures had no user anywhere in the suite). A bare-root parse is + unaffected by either assignment. + provenance: "G5 coverage sweep, LexicalEntry.AssignedHeadFeatures/AssignedFootFeatures" + parses: + - signature: "KES|kes" + gloss: sing + rules: [] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kesez + note: >- + KES + mrAgr ("-ez") -- KES's own AssignedHeadFeatures (featNum=sg) genuinely CONFLICTS with + mrAgr's RequiredHeadFeatures (featNum=pl), and likewise AssignedFootFeatures (unstressed) + conflicts with RequiredFootFeatures (stressed): unification fails on both, so this analysis + has zero parses -- the real rejection dabez (above) does NOT demonstrate. + provenance: "G5 coverage sweep, LexicalEntry.AssignedHeadFeatures/AssignedFootFeatures" + expect_fail: true + blocked_by: [mrAgr] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: kesepez + note: >- + KES + mrNumPl ("-ep") + mrAgr ("-ez") -- unlike kesez above, mrNumPl runs FIRST, and its own + OutputHeadFeatures/OutputFootFeatures overwrite KES's raw AssignedHeadFeatures (sg) and + AssignedFootFeatures (unstressed) with pl/stressed before mrAgr ever reads the word's + SyntacticFeatureStruct -- so the same root whose direct AGR attachment is impossible (kesez) + succeeds once NUMPL has run first. This isolates OutputFootFeatures specifically: KES is the + only entry in the whole grammar carrying an explicit, CONFLICTING AssignedFootFeatures value, + so it is the only root that can show mrNumPl's OutputFootFeatures actually overwriting rather + than merely supplementing an unset value the way dabepez's unset-root case does. + provenance: "fold-in: dtd:element/OutputFootFeatures, PresentInLanguageGrammarAlready per conformance/fold-in-candidates.tsv -- previously only witnessed on dabepez, where the root's foot feature starts unset (unification is vacuous either way) so severing OutputFootFeatures there changes nothing" + parses: + - signature: "KES+NUMPL+AGR|kesepez" + gloss: sing-PL-AGR + rules: [mrNumPl, mrAgr] + exercises: + - "Syntactic feature agreement (RequiredHeadFeatures/OutputHeadFeatures/RequiredFootFeatures/OutputFootFeatures)" + + - word: siliz + note: >- + SIL ("plant", posV7) + mrRecurSuf ("-iz"), one application -- a plain control establishing + the suffix works at all before silizizi (below) attempts a second application. + provenance: "G5 coverage sweep (second sweep), SynthesisAffixProcessRule.MaxApplicationCount" + parses: + - signature: "SIL+RECURSUF|siliz" + gloss: plant-RECURSUF + rules: [mrRecurSuf] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: siliziz + note: >- + SIL+RECURSUF (siliz, above) with "-iz" attached a SECOND time -- the DTD's own default + multipleApplication="1" caps mrRecurSuf to exactly one application per derivation, so this + has zero parses. + provenance: "G5 coverage sweep (second sweep), SynthesisAffixProcessRule.MaxApplicationCount" + expect_fail: true + blocked_by: [mrRecurSuf] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: daleh + note: >- + DAL ("dig", posV7) + mrStemReq ("-eh") -- DAL's own allomorph carries stemName="snG5", which + mrStemReq's requiredStemName="snG5" requires, so it applies. + provenance: "G5 coverage sweep (second sweep), SynthesisAffixProcessRule.RequiredStemName" + parses: + - signature: "DAL+STEMREQ|daleh" + gloss: dig-STEMREQ + rules: [mrStemReq] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: daheh + note: >- + DAH ("climb", posV7) + mrStemReq -- DAH's own allomorph carries no stem name at all, so + mrStemReq's requiredStemName="snG5" is never satisfied and this has zero parses. + provenance: "G5 coverage sweep (second sweep), SynthesisAffixProcessRule.RequiredStemName" + expect_fail: true + blocked_by: [mrStemReq] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: dalizeh + note: >- + DAL + mrRecurSuf ("-iz") + mrStemReq ("-eh"), in that list order (mrRecurSuf before mrStemReq + on Stratum "Main"). The ordering discriminator for the mrRecurSuf~mrStemReq adjacent pair: + "dalehiz" below is the same two suffixes reversed, which only parses when the list order is + swapped. DAL qualifies for both -- mrRecurSuf has no extra gate beyond posV7, and DAL's own + allomorph carries stemName="snG5" for mrStemReq. + parses: + - signature: "DAL+RECURSUF+STEMREQ|dalizeh" + gloss: dig-RECURSUF-STEMREQ + rules: [mrRecurSuf, mrStemReq] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: dalehiz + note: >- + DAL + mrStemReq + mrRecurSuf, the reverse of "dalizeh". Zero parses under the shipped list + order (mrRecurSuf mrStemReq): only reachable when mrStemReq is transposed ahead of mrRecurSuf. + expect_fail: true + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: zimed + note: >- + ZIM ("fly", posV7, mprRRealTest) + rrRRealTest ("-ed") -- ZIM's own AssignedHeadFeatures + (featG5=symG5A) genuinely conflicts with the rule's own RequiredHeadFeatures (featG5=symG5B), + so RequiredSyntacticFeatureStruct.Unify fails and this has zero parses. mprRRealTest is a + hard set-membership gate (see grammar.xml), so this rule can never spuriously apply to any + other word in the grammar regardless of this outcome. + provenance: "G5 coverage sweep (second sweep), SynthesisRealizationalAffixProcessRule.RequiredSyntacticFeatureStruct" + expect_fail: true + blocked_by: [rrRRealTest] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" + + - word: zamed + note: >- + ZAM ("swim", posV7, mprRRealTest, family famRRealBlock) + rrRRealTest -- ZAM's featG5=symG5B + matches the rule's RequiredHeadFeatures, so the rule applies; but ZAM's family also contains + the suppletive WEP (also featG5=symG5B), and CheckBlocking substitutes WEP's own entry in + wherever ZAM's own output would surface, so the resynthesis ("wep") no longer matches this + word's own input shape ("zamed"), and this has zero parses. First time this suite exercises + Blockable/CheckBlocking through a RealizationalRule rather than an ordinary MorphologicalRule + or a CompoundingRule. + provenance: "G5 coverage sweep (second sweep), SynthesisRealizationalAffixProcessRule.Blockable" + expect_fail: true + blocked_by: [rrRRealTest] + exercises: + - "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" diff --git a/conformance/languages/suffixing-vowel-harmony/grammar.xml b/conformance/languages/suffixing-vowel-harmony/grammar.xml new file mode 100644 index 000000000..30339217a --- /dev/null +++ b/conformance/languages/suffixing-vowel-harmony/grammar.xml @@ -0,0 +1,579 @@ + + + + + SuffixingVowelHarmony + + v + n + + vAlpha + + + + cons+- + voc+- + high+- + back+- + voice+- + + + place + + velar + palatal + dental + lateral + nasalN + nasalM + rhotic + sibilant + bilabial + vocalic + + + + + Main + + + a + + + + + e + + + + + i + + + + + u + + + + + + + k + + + + + t + + + + + d + + + + + l + + + + + n + + + + + m + + + + + r + + + + + g + + + + + y + + + + + s + + + + + b + + + + + + + + + Any + + Consonant + + + + BackVowel + + + + FrontE + + + + BackA + + + + FrontI + + + + BackU + + + + GlideY + + + StopK + + + + VoicedVelar + + + + + TargetT + + VowelAnyBack + + + HighVowelAnyBack + + + + + + + backnessHarmony + + + + + + + + + + + + + + + + + + + + + + vowelMerge + + + + + + + + + + + + + + + + + vowelMultiMerge + + + + + + + + + + + + + + gradation + + + + + + + + + + + + + + + + + + + + epenthesis + + + + + + + + + + + + + + + + + + alphaHighHarmony + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Main + + + + past + + + + de + + + PAST + + + + present + + + + le + + + PRES + + + + plural + + + + ler + + + PL + + + + collective + + + + + e + + ik + + + + + + + COLL + + + + intensive + + + + + + + + + u + + + + + INTS + + + + alphaSuf + + + + in + + + ALPHA + + + + + verbTemplate + + tense + + number + + + + + + semit + SEMIT + carry + + + + kutak + KUTAK + arrive + + + + unt + UNT + fall + + + + gan + GAN + roam + + + tem + TEM + rest + + + sal + SAL + wait + + + + duii + DUII + weave + + + sueeb + SUEEB + grind + + + + sat + SAT + sit + + + set + SET + stand + + + + kalt + KALT + probe + + + + + + diff --git a/conformance/languages/suffixing-vowel-harmony/words.yaml b/conformance/languages/suffixing-vowel-harmony/words.yaml new file mode 100644 index 000000000..9acbc8ac8 --- /dev/null +++ b/conformance/languages/suffixing-vowel-harmony/words.yaml @@ -0,0 +1,381 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). Phonological rules apply, in this order, ONCE to +# the fully-concatenated underlying word (root+every suffix already joined) per the stratum's +# `phonologicalRules="prBacknessHarmony prVowelMerge prVowelMultiMerge prGradation prEpenthesis"` +# order -- NOT incrementally per suffix. That ordering is itself load-bearing: prBacknessHarmony +# must see the pre-epenthesis consonant cluster, or the transparency span would be broken by an +# epenthetic vowel the harmony rule can't see past (its span only elides consonants, not vowels). +# +# 1. semit+PAST -> underlying "semit"+"de" = "semitde". Harmony: target "e" (final); scanning +# left, the nearest vowel within <=2 intervening consonants is "i" (position 4) -- FRONT, not +# back -- so the environment does not match; rule does not fire. Epenthesis: consonant seam +# t-d (positions 5-6) gets a linking "i" -> "semitide". +# -> SEMIT+PAST|semitide, rules: [mrPast, prEpenthesis] +# 2. semit+PRES -> underlying "semit"+"le" = "semitle". Same reasoning (nearest vowel to target +# "e" is front "i"): harmony doesn't fire. Epenthesis at seam t-l -> "semitile". +# -> SEMIT+PRES|semitile, rules: [mrPres, prEpenthesis] +# 3. kutak+PAST -> underlying "kutak"+"de" = "kutakde". Harmony: target "e" (final); scanning +# left past 2 consonants (d, k) reaches "a" (position 4) -- BACK -- environment matches, rule +# fires: e->a, giving "kutakda". Gradation: the word-initial "k" (position 1) is caught by the +# anchored subrule (initialBoundaryCondition) and stays "k"; the second "k" (position 5) is NOT +# word-initial, so the catch-all subrule weakens it to "g" -> "kutagda". Epenthesis: consonant +# seam g-d (positions 5-6) gets a linking "i" -> "kutagida". +# -> KUTAK+PAST|kutagida, rules: [mrPast, prBacknessHarmony, prGradation, prEpenthesis] +# 4. kutak+PRES -> underlying "kutak"+"le" = "kutakle". Same harmony/gradation reasoning as #3 +# (target "e" backed by root-internal "a" across k+l; second "k" lenites) -> "kutagla" -> +# epenthesis at the g-l seam -> "kutagila". +# -> KUTAK+PRES|kutagila, rules: [mrPres, prBacknessHarmony, prGradation, prEpenthesis] +# 5. unt+PAST -> underlying "unt"+"de" = "untde". Harmony: target "e" (final); scanning left, the +# first 2 consonants are d, t -- that already exhausts the max=2 transparency span before any +# vowel is reached, so the back vowel "u" (position 1) is OUT OF REACH -- environment does not +# match, rule does not fire (the quantifier's upper bound is the whole point of this word). +# Epenthesis (simultaneous, so every C_C seam in the 3-consonant run n-t-d gets its own "i" in +# one pass): n-t seam and t-d seam both qualify -> "u-n-i-t-i-d-e" = "unitide". +# -> UNT+PAST|unitide, rules: [mrPast, prEpenthesis] (prBacknessHarmony correctly absent) +# +# The remaining words either reuse these same five rules on independent lexical material (the +# discontinuous-circumfix/infix pair, and the two vowel-coalescence pins) or are expect_fail words +# whose signature is simply the empty set -- see PROTOCOL.md section 3 for the `-`/empty-signature +# convention, unchanged here. +# +# Reconciliation against the oracle (self-check): the SURFACE signatures above (5/5 hand-derived +# words) matched the oracle exactly once two authoring bugs were found and fixed -- see below; every +# other word's signature (14 more) also matched on the first run after those two fixes, with no +# further disagreement. +# - Bug 1 (grammar-authoring, not a hand-derivation error): a phonological subrule that CHANGES a +# segment's identity (prBacknessHarmony's e->a, prGradation's k->g, prVowelMerge/ +# prVowelMultiMerge's literal outputs) is analysis-unreachable in self-check unless its target +# (Lhs) AND output (Rhs) are both expressed as a FeatureNaturalClass over a real, FULLY-SPECIFIED +# PhonologicalFeatureSystem (every segment given an explicit value for every feature, and every +# segment's feature bundle unique in the table -- confirmed by isolated probing: a bare +# SegmentNaturalClass/literal-Segment target or output for a CHANGING subrule always finds ZERO +# parses, regardless of anchoring or an explicit Environment). The grammar originally had no +# PhonologicalFeatureSystem at all (mirroring suffixing-evidential-adjacency-chain's phonology-free precedent, which +# doesn't need one); this grammar's 4 changing phonological rules needed one added. This is a +# genuine, previously-undocumented-outside-this-fixture engine/authoring constraint, not a hand +# derivation mistake -- the hand-derived SURFACE FORMS above were all correct from the first +# draft; only the grammar's own feature-system scaffolding needed fixing for the oracle to find +# them at all. +# - Bug 2 (a genuine hand-derivation miss, the LT-22613-style lesson this discipline exists to +# catch): prBacknessHarmony's transparency span was first authored as `min="0" max="2"` +# (0-2 intervening consonants). With min="0", the rule also fires on a back vowel IMMEDIATELY +# adjacent to a front "e" (zero consonants between) -- which spuriously matched inside the SUEEB +# lexical entry's own "u-e-e" trigger pattern (the "u" is directly followed by "e"), backing the +# first "e" to "a" BEFORE prVowelMultiMerge ever got a chance to see the intact "u-e-e" pattern, +# permanently losing the word's only valid analysis. Fixed by matching v1 rewrite/quantifier's own +# bound exactly (`min="1" max="2"`), which does not change any of the derivations above (every +# harmony-eligible word here has >=1 intervening consonant already) but removes the false-positive +# zero-consonant case. The oracle was right to reject "sueb" under the min="0" version; the +# hand-derivation's IMPLICIT assumption (that harmony only interacts with the words it was +# designed for) was naive, exactly as suffixing-evidential-adjacency-chain's own header warns. +# - Bug/finding 3 (a harness-tracing bug, found while authoring this grammar and fixed in the same +# stage): self-check's traced "rules:" verification (TraceRuleAttributor.cs) originally counted a +# phonological rule as "applied" to a word whenever its synthesis pass RAN, regardless of whether +# it matched anything -- with >=2 phonological rules sharing a stratum (this grammar's five), +# every declared phonological rule id showed up in every word's traced set unconditionally +# (confirmed by an isolated 2-rule probe grammar where a word containing NEITHER rule's target +# segment traced both as applied). Root cause: the engine's TraceManager records both +# PhonologicalRuleApplied (FailureReason.None) and PhonologicalRuleNotApplied (FailureReason set) +# as PhonologicalRuleSynthesis trace nodes, and the attributor counted both kinds. Fixed by +# filtering to FailureReason.None nodes, after which every traced set below matched this header's +# hand derivations exactly (semitide traces [mrPast, prEpenthesis]; unitide correctly lacks +# prBacknessHarmony; bare roots trace []). Per-word phonological-rule attribution is therefore +# real: a parse's `rules:` list names exactly the rules that fired with effect on that word. + +language: SuffixingVowelHarmony +inspired_by: ["suffixing agglutinative morphology with long-distance vowel harmony and consonant gradation (typological pattern, not any specific language)"] +sources: + - "WALS ch. 20/21 - Suffixing vs. Prefixing in Inflectional Morphology" + - "WALS - Vowel Harmony chapters (backness harmony typology)" + - "WALS - consonant gradation / alternation typology" +requires: [phonology] +words: + - word: semitide + note: >- + SEMIT (front-voweled root, "carry") + PAST. Harmony never fires (root/suffix material is all + front), so this word isolates simultaneous epenthesis breaking up the t-d seam from the + obligatory disjunctive tense slot -- the same pairing as the F3 cross-cutting worked example. + provenance: "F3 worked example (cross-cutting category): a disjunctive/obligatory affix-template slot combined with Simultaneous-mode epenthesis, chosen per docs/conformance-framework-implementation-notes.md's recommendation (both halves already have a proven single-feature fixture to crib from: negative/obligatory-tense-slot and rewrite/simultaneous-epenthesis)" + parses: + - signature: "SEMIT+PAST|semitide" + gloss: carry-PAST + rules: [mrPast, prEpenthesis] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + - "RewriteRule Simultaneous" + + - word: semitile + note: SEMIT + PRES, the disjunctive slot-1 sibling of semitide -- same epenthesis reasoning, present tense suffix instead. + parses: + - signature: "SEMIT+PRES|semitile" + gloss: carry-PRES + rules: [mrPres, prEpenthesis] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + - "RewriteRule Simultaneous" + + - word: semitideler + note: SEMIT + PAST(slot 1, obligatory) + PL(slot 2, optional) -- proves the optional number slot composes once the obligatory tense slot is filled, same mechanism as suffixing-evidential-adjacency-chain's walaknichik. + parses: + - signature: "SEMIT+PAST+PL|semitideler" + gloss: carry-PAST-PL + rules: [mrPast, mrPlural, prEpenthesis] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: kutagida + note: >- + KUTAK ("arrive", back-voweled root containing "k" both word-initially and again word-medially) + + PAST: the flagship word exercising the obligatory/disjunctive tense slot, iterative + long-distance backness harmony (reaching past the k+d consonant seam), consonant-gradation + allomorphy (initial k resists, medial k lenites to g), and simultaneous epenthesis all at once. + provenance: "W9.2 probe, RewriteRuleTests.LongDistanceRules" + parses: + - signature: "KUTAK+PAST|kutagida" + gloss: arrive-PAST + rules: [mrPast, prBacknessHarmony, prGradation, prEpenthesis] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + - "RewriteRule Simultaneous" + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + - "NaturalClass: Segments vs FeatureNaturalClass/SegmentNaturalClass precision" + - "Boundary markers (CharacterDefinitionTable)" + + - word: kutagila + note: KUTAK + PRES, the disjunctive slot-1 sibling of kutagida -- same harmony/gradation/epenthesis reasoning, present tense suffix instead. Also the rewrite/disjunctive pin (consonant-gradation's two ordered, word-initial-anchored subrules). + provenance: "W9.2 probe, RewriteRuleTests.DisjunctiveRules" + parses: + - signature: "KUTAK+PRES|kutagila" + gloss: arrive-PRES + rules: [mrPres, prBacknessHarmony, prGradation, prEpenthesis] + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + - "RewriteRule Simultaneous" + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + - "Boundary markers (CharacterDefinitionTable)" + + - word: kutak + note: KUTAK bare, no tense suffix at all -- slot 1 (tense) is obligatory and unfilled, so the AffixTemplate can never produce this output at all (mirrors suffixing-evidential-adjacency-chain's walakchik / negative/obligatory-tense-slot's "tun") -- zero parses. + expect_fail: true + provenance: "F3 worked example (negative category), hand-authored to close the zero-coverage 'Affix template slots' construct flagged in docs/conformance-framework-plan.md section 6" + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: kutakler + note: KUTAK + PL only, no tense -- slot 2 is unreachable without slot 1 being filled first, so this fails for the same structural reason as bare "kutak" (proving the failure is specifically about the missing obligatory tense slot, not merely "no suffix at all"). + expect_fail: true + exercises: + - "Affix template slots (obligatory/disjunctive/ordering)" + + - word: unitide + note: >- + UNT ("fall") + PAST: the root's back vowel "u" sits 3 consonants away from the suffix's target + "e" (n, t, then the suffix's own "d") -- one past the harmony rule's max=2 transparency span, + so harmony correctly does NOT fire (the quantified-environment upper bound holding, the mirror + image of kutagida's in-bound case). Simultaneous epenthesis still fires at both C_C seams in + the resulting 3-consonant run in one pass. + provenance: "W9.2 probe, RewriteRuleTests.QuantifierRules" + parses: + - signature: "UNT+PAST|unitide" + gloss: fall-PAST + rules: [mrPast, prEpenthesis] + exercises: + - "RewriteRule Simultaneous" + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: untda + note: The hypothetical "harmony reached 3 consonants" surface form -- never producible, since prBacknessHarmony's correct (bounded) behavior is exactly what forbids it; see unitide's note for the in-bound/out-of-bound contrast. + expect_fail: true + blocked_by: [prBacknessHarmony] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: gan + note: GAN ("roam") bare root, posN -- no obligatory template applies to posN, so (unlike kutak) a bare root is a complete, valid word on its own. + parses: + - signature: "GAN|gan" + gloss: roam + rules: [] + exercises: [] + + - word: guan + note: GAN infixed with the intensive marker "-u-" after the first segment -- the discontinuous-morph positive/success control (no RequiredEnvironments at all, always succeeds), paired with etemik/esalik's negative circumfix demonstration below. + parses: + - signature: "GAN+INTS|guan" + gloss: roam-INTS + rules: [ruleInfixDemo] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: tem + note: TEM ("rest") bare root, posN -- one of the two roots used in the circumfix per-occurrence-environment demonstration below (its initial "t" matches the circumfix's required right-context class). + parses: + - signature: "TEM|tem" + gloss: rest + rules: [] + exercises: [] + + - word: sal + note: SAL ("wait") bare root, posN -- the other circumfix-demonstration root; its initial "s" does NOT match the circumfix's required right-context class. + parses: + - signature: "SAL|sal" + gloss: wait + rules: [] + exercises: [] + + - word: etemik + note: >- + TEM circumfixed ("e-tem-ik"): the PREFIX piece's own local right-context is "t" (TEM's own + initial segment), which matches the required class -- but the SUFFIX piece is word-final, so + its own local right-context can never match "followed by t". Because HC checks the SAME + required environment independently at EACH contiguous piece of a discontinuous morph (see + grammar.xml's ruleCollective comment), the word is rejected even though one piece's local check + passed -- both must pass, not just one. + expect_fail: true + blocked_by: [ruleCollective] + provenance: "W3.3, history row 51 (987be2fd) per-occurrence environment checking half" + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: esalik + note: SAL circumfixed ("e-sal-ik") -- the minimal-pair partner of etemik, but here the PREFIX piece's own local right-context ("s") already fails to match the required class, so this word fails even more directly (both pieces fail, rather than just one) -- same overall rejection, different reason, proving the per-piece check isn't merely "satisfied somewhere in the word". + expect_fail: true + blocked_by: [ruleCollective] + exercises: + - "AffixProcessRule: prefix/suffix/circumfix/infix" + + - word: duii + note: The DUII lexical entry's own underlying shape, fed back in as a literal surface string -- it can never surface as itself, since prVowelMerge obligatorily collapses "u"+"i"+"i" to "u"+"y" (see duy below) whenever the environment matches, which it always does here. + expect_fail: true + blocked_by: [prVowelMerge] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: duy + note: DUII's actual surface realization -- two adjacent "i" segments preceded by "u" coalesce to the glide "y" (vowel coalescence at an agglutination-plausible seam; history row 1 provenance). + provenance: "W9.2 probe, RewriteRuleTests.MergeRules; history row 1 (812aa48e/#403)" + parses: + - signature: "DUII|duy" + gloss: weave + rules: [prVowelMerge] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: sueeb + note: The SUEEB lexical entry's own underlying shape, fed back in as a literal surface string -- like duii, it can never surface as itself, since prVowelMultiMerge obligatorily reduces "u"+"e"+"e" to "u"+"e" (see sueb below). + expect_fail: true + blocked_by: [prVowelMultiMerge] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: sueb + note: SUEEB's actual surface realization -- a three-segment pattern (u+e+e, trigger folded directly into the Lhs, no separate Environment element, unlike duy's prVowelMerge) reduces to two segments (u+e); the structural counterpart to duy's explicit-environment merge. + provenance: "W9.2 probe, RewriteRuleTests.MultipleMergeRules; history row 1 (812aa48e/#403)" + parses: + - signature: "SUEEB|sueb" + gloss: grind + rules: [prVowelMultiMerge] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: sat + note: SAT ("sit", posVAlpha) bare root, no suffix -- control for satun below. + provenance: "G5 coverage sweep, VariableFeature/AlphaVariables (prAlphaHighHarmony)" + parses: + - signature: "SAT|sat" + gloss: sit + rules: [] + exercises: [] + + - word: set + note: SET ("stand", posVAlpha) bare root, no suffix -- control for setin below. + provenance: "G5 coverage sweep, VariableFeature/AlphaVariables (prAlphaHighHarmony)" + parses: + - signature: "SET|set" + gloss: stand + rules: [] + exercises: [] + + - word: satun + note: >- + SAT + mrAlphaSuf ("-in" underlyingly) -- the root's own last vowel "a" is back, so + prAlphaHighHarmony's alpha variable captures back+ from the LeftEnvironment and imposes it on + the suffix's high vowel, turning "i" into "u". Previously zero coverage in the whole suite: + no other grammar declares a PhonologicalRule's own VariableFeatures/AlphaVariables at all. + provenance: "G5 coverage sweep, VariableFeature/AlphaVariables (prAlphaHighHarmony)" + parses: + - signature: "SAT+ALPHA|satun" + gloss: sit-ALPHA + rules: [mrAlphaSuf, prAlphaHighHarmony] + exercises: + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: setin + note: >- + SET + mrAlphaSuf -- the root's own last vowel "e" is front, so the captured alpha value is + back-, leaving the suffix's high vowel "i" unchanged (an identity case, output == input, the + same house style as prGradation's own anchored subrule) -- proves the rule is a genuine + agreement, not a one-way rewrite that always backs the vowel. + provenance: "G5 coverage sweep, VariableFeature/AlphaVariables (prAlphaHighHarmony)" + parses: + - signature: "SET+ALPHA|setin" + gloss: stand-ALPHA + rules: [mrAlphaSuf, prAlphaHighHarmony] + exercises: + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: kalut + note: >- + KALT ("probe", posVAlpha, back-voweled with an internal "lt" cluster) bare, no suffix. + prEpenthesis inserts "i" at the l-t seam ("kalt" -> "kalit"); that NEW vowel is itself a + legal prAlphaHighHarmony target one consonant from the root's back vowel "a", so harmony + then backs it to "u" -- "kalit" -> "kalut". This only happens because prEpenthesis is + declared BEFORE prAlphaHighHarmony in the stratum's phonologicalRules order: swapping them + makes harmony run first, when no high vowel yet exists to harmonize, and epenthesis then + inserts the un-harmonized "i" too late for anything to touch it (see kalit below). + parses: + - signature: "KALT|kalut" + rules: [prAlphaHighHarmony, prEpenthesis, prGradation] + exercises: + - "RewriteRule Simultaneous" + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: kalit + note: >- + KALT bare with the epenthetic vowel left un-harmonized -- this is exactly what prEpenthesis + alone (without prAlphaHighHarmony reaching the new vowel) would produce, and exactly what + the SWAPPED rule order produces instead of kalut. Not a valid surface form under this + fixture's declared order, so it stays expect_fail; kept as the ordering pair's negative + control. + expect_fail: true + blocked_by: [prAlphaHighHarmony] + exercises: + - "RewriteRule Simultaneous" + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: kalutun + note: >- + KALT + mrAlphaSuf ("-in" underlyingly): both the epenthetic vowel (from the root's own l-t + seam) and the suffix's own high vowel end up harmonized to "u", since prEpenthesis creates + the epenthetic vowel before prAlphaHighHarmony's iterative left-to-right scan ever runs, and + that scan then propagates the root's back+ value across both. The suffixed sibling of kalut. + parses: + - signature: "KALT+ALPHA|kalutun" + gloss: probe-ALPHA + rules: [mrAlphaSuf, prAlphaHighHarmony, prEpenthesis, prGradation] + exercises: + - "RewriteRule Simultaneous" + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" + + - word: kalitin + note: >- + KALT + mrAlphaSuf with neither vowel harmonized -- what the SWAPPED rule order produces + instead of kalutun (harmony runs first, finds the suffix's "i" two consonants from the root + vowel and out of its 0-1-consonant reach, then epenthesis inserts its own un-harmonized "i" + too late for anything to touch). Not a valid surface form under this fixture's declared + order; the suffixed sibling of kalit. + expect_fail: true + blocked_by: [prAlphaHighHarmony] + exercises: + - "RewriteRule Simultaneous" + - "Alpha-variable phonological environments (VariableFeature/AlphaVariables)" diff --git a/conformance/languages/templatic-root-modification/grammar.xml b/conformance/languages/templatic-root-modification/grammar.xml new file mode 100644 index 000000000..b285fa163 --- /dev/null +++ b/conformance/languages/templatic-root-modification/grammar.xml @@ -0,0 +1,492 @@ + + + + + TemplaticRootModification + + + v + vFormII + vHollow + vStemName + vSimulDemo + vIterDemo + vProthesis + vGeminate + + + + cons+- + voc+- + high+- + back+- + round+- + voice+- + + place + + velar + dental + bilabial + sibilant + nasalM + uvular + lateral + glottal + rhotic + vocalic + + + + + + + aspect + + impf + perf + juss + + + + + + + ImpfPerf + + + + + + + PerfJuss + + + + + + + + Main + + + a + + + + + + i + + + + + + u + + + + + + + k + + + + + + g + + + + + + t + + + + + + d + + + + + + b + + + + + + p + + + + + + s + + + + + + m + + + + + + q + + + + + + l + + + + + + h + + + + + + r + + + + + + + + + Any + Consonant + + + + VowelA + + + + VowelI + + + + + HighVowel + + + HFUVowel + + + + BackRnd + + + + TargetD + + + + + epenthesis + + + + + + + + + + + + + + prothesis + + + + + + + + + + + + + + + + + + feedingSimul + + + + + + + + + + + + + + + feedingIter + + + + + + + + + + + + + + + geminate + + + + + + + + + + + Main + + + + perf1sg + + + + t + + + P1SG + + + perf3sg + + + + a + + + P3SG + + + + formII + + + + + + + + + + + + + + FORMII + + + + passive + + + + + + + + + + + + + + + PASS + + + + aspImpf + + + + u + + + + IMPF + + + aspPerf + + + + i + + + + PERF + + + aspJuss + + + + a + + + + JUSS + + + + + + katab + KTB + write + + + + spr + SPR + count + + + smm + SMM + curse + + + + qal + QWL + say + + + + + halak + hilak + hulak + + HLK + go + + + + gigigi + FEEDSIM + sway + + + gigigi + FEEDITER + twirl + + + + ktub + KTUB + write.IMP + + + + rada + RAD + kindle + + + + + + + + + + diff --git a/conformance/languages/templatic-root-modification/words.yaml b/conformance/languages/templatic-root-modification/words.yaml new file mode 100644 index 000000000..4780298ac --- /dev/null +++ b/conformance/languages/templatic-root-modification/words.yaml @@ -0,0 +1,317 @@ +# HAND DERIVATION (authored BEFORE running the oracle -- see grammar.xml for the rule definitions +# these derivations reason from). +# +# 1. katab -> KTB bare, no suffix at all. No C_C seam exists anywhere in "katab" (k-a-t-a-b +# alternates C/V throughout), so prEpenthesis (posV-scoped) has no site to fire at. +# -> KTB|katab, rules: [] +# 2. katabit -> KTB + P1SG ("-t"): underlying concatenation is "katab"+"t" = "katabt", whose only +# C_C seam is b-t (positions 5-6). prEpenthesis (Simultaneous, obligatory wherever its +# environment holds) inserts a linking "i" there -> "katabit". +# -> KTB+P1SG|katabit, rules: [mrPerf1sg, prEpenthesis] +# 3. kataba -> KTB + P3SG ("-a"): underlying "katab"+"a" = "kataba", vowel-final suffix creates no +# C_C seam at all (b-a is C-V) -> prEpenthesis does not fire, contrasting with katabit and +# proving the rule is seam-conditioned, not blanket-obligatory on every suffixed word. +# -> KTB+P3SG|kataba, rules: [mrPerf3sg] +# 4. sapr -> SPR + FormII: MorphologicalInput splits "spr" into fIIFirst="s", fIIRest="pr"; +# InsertSimpleContext inserts VowelA ("a") between them -> "s"+"a"+"pr" = "sapr". posFormII is +# never scoped to prEpenthesis, so the resulting p-r medial cluster is left exactly as the rule +# produces it (this invented language tolerates medial CC in FormII output; only the KTB +# person-suffix paradigm has an obligatory seam-epenthesis rule). +# -> SPR+FORMII|sapr, rules: [mrFormII] +# 5. samm -> SMM + FormII attempted: same InsertSimpleContext split ("s"+"a"+"mm" = "samm"), but +# SMM's C2=C3 ("m"="m") is exactly the OCP-fragile shape the MorphemeCoOccurrenceRule excludes +# FormII from co-occurring with (primaryMorpheme="mrFormII", otherMorphemes="eSmm") -> zero +# parses, since "samm" has no other possible analysis (SMM's own bare shape is "smm", not +# "samm"). +# -> expect_fail, blocked_by: [mrFormII] +# +# The remaining words reuse these same five mechanisms (KTB's person-suffix/epenthesis pair, FormII's +# InsertSimpleContext, the OCP exclusion) on independent lexical/rule material -- the hollow-root +# internal passive (ModifyFromInput), the HLK stem-name paradigm (StemName region algebra, mirroring +# fusional-realizational-morphology's own mun/man/min proof exactly), the Simultaneous-vs-Iterative feeding/bleeding +# contrast pair, word-initial prothesis, and gemination-as-expansion -- or are expect_fail words whose +# signature is the empty set. See PROTOCOL.md section 3 for the `-`/empty-signature convention. +# +# Reconciliation against the oracle (self-check): all 5 words above matched the hand derivation on +# the first self-check run once the grammar's isolation discipline (one POS per phonological-rule +# demo, requiredPartsOfSpeech on every subrule) was in place, and 23 of 25 words in the file matched +# outright with no further disagreement. The remaining 2 (gigugu, gigugi) matched on SIGNATURE but +# not on the traced rules: list -- both words' fired-rule set traced as [prSimulFeeding, +# prIterFeedingControl] together, not just the one whose candidate actually survives. This is +# TraceRuleAttributor's own documented "ambiguous word" limitation (see that class's doc comment in +# src/SIL.Machine.Morphology.HermitCrab.Conformance/V2/TraceRuleAttributor.cs): surface "gigugu"/ +# "gigugi" both unify against BOTH the eFeedSimul and eFeedIter lexical candidates (they share the +# identical underlying shape "gigigi"), and even though only one candidate's synthesis-confirm +# ultimately matches the target surface, the OTHER candidate's own (failed) confirm attempt still +# fires its rule before being discarded, and the word-level trace walk unions rules fired across +# every attempted candidate, not just the surviving one. The trace is authoritative per this task's +# discipline, so rules: was widened to the honest traced union on both words (see their own notes). + +language: TemplaticRootModification +inspired_by: ["templatic root-and-pattern morphology: non-concatenative infixation, internal ablaut, and suppletive stem-name alternation (typological pattern, not any specific language)"] +sources: + - "WALS - Reduplication and templatic morphology typology chapters" + - "typological literature on root-and-pattern phonology and morphology, and the Obligatory Contour Principle" + - "typological literature on templatic verbal morphology and the HermitCrab reference corpus" +requires: [phonology] +words: + - word: katab + note: KTB bare root, no suffix -- no C_C seam exists, so prEpenthesis has no site to fire at. + parses: + - signature: "KTB|katab" + gloss: write + rules: [] + exercises: [] + + - word: katabit + note: >- + KTB + P1SG ("-t"): underlying "katab"+"t" = "katabt" has one C_C seam (b-t), obligatorily + broken by Simultaneous-mode epenthesis -- the raw unepenthesized concatenation never itself + surfaces (see "katabt" below). + provenance: "P13 synthetic oracle: Simultaneous epenthesis; confirmed live-oracle bug on row 0 (see README)" + parses: + - signature: "KTB+P1SG|katabit" + gloss: write-1SG.PERF + rules: [mrPerf1sg, prEpenthesis] + exercises: + - "RewriteRule Simultaneous" + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + + - word: katabt + note: The raw, unepenthesized concatenation of katab+"-t" -- prEpenthesis is obligatory wherever its C_C environment holds, so this surface form can never itself be a valid analysis (see katabit). + expect_fail: true + blocked_by: [prEpenthesis] + exercises: + - "RewriteRule Simultaneous" + + - word: kataba + note: KTB + P3SG ("-a"), a vowel-initial suffix -- no C_C seam forms (b-a is C-V), so epenthesis correctly does not fire, contrasting with katabit. + parses: + - signature: "KTB+P3SG|kataba" + gloss: write-3SG.PERF + rules: [mrPerf3sg] + exercises: + - "MorphologicalOutputAction: CopyFromInput/InsertSegments" + + - word: spr + note: SPR bare root (posFormII), no FormII applied -- a plain, unrestricted control. + parses: + - signature: "SPR|spr" + gloss: count + rules: [] + exercises: [] + + - word: sapr + note: >- + SPR + FormII: InsertSimpleContext splits the root into a first segment and the remainder, + inserting a fully-specified VowelA class between them -- "s"+"a"+"pr" = "sapr". This is + ZERO-coverage-today's home construct: no other v2 grammar carries InsertSimpleContext. + posFormII is never scoped to prEpenthesis, so the resulting p-r cluster is left as-is (an + invented-language phonotactic difference from the KTB paradigm, not an omission). + parses: + - signature: "SPR+FORMII|sapr" + gloss: count-FORMII + rules: [mrFormII] + exercises: + - "MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext" + + - word: smm + note: SMM bare root (posFormII), no FormII applied -- proves the root is otherwise perfectly valid on its own; only combining it with FormII is excluded (see samm below). + parses: + - signature: "SMM|smm" + gloss: curse + rules: [] + exercises: [] + + - word: samm + note: >- + SMM + FormII attempted: the same InsertSimpleContext split as sapr ("s"+"a"+"mm" = "samm"), + but SMM's C2=C3 ("m"="m") is exactly the Obligatory-Contour-Principle-fragile root shape the + MorphemeCoOccurrenceRule excludes FormII from co-occurring with -- zero parses (no other + analysis exists for "samm"). + expect_fail: true + blocked_by: [mrFormII] + exercises: + - "MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule" + + - word: qal + note: QWL ("say") hollow root, bare, active/citation form -- qala-plausible. + parses: + - signature: "QWL|qal" + gloss: say + rules: [] + exercises: [] + + - word: qil + note: >- + QWL's internal passive, realized ENTIRELY by changing the root's own medial vowel ("a"->"i") + via ModifyFromInput -- no affix at all. qila ("it was said")-plausible: a genuinely + attested templatic phenomenon, not an invented mechanism. Second half of the zero-coverage + ModifyFromInput/InsertSimpleContext construct pair (paired with sapr's InsertSimpleContext use + above). + parses: + - signature: "QWL+PASS|qil" + gloss: say-PASS + rules: [mrPassive] + exercises: + - "MorphologicalOutputAction: ModifyFromInput/InsertSimpleContext" + + - word: halak + note: HLK's default (unrestricted) allomorph, bare -- no aspect feature assigned at all, so there is no StemName region to fail. + parses: + - signature: "HLK|halak" + gloss: go + rules: [] + exercises: + - "Stem names" + + - word: halaku + note: HLK default allomorph + IMPF ("-u") -- once ANY aspect feature is assigned, snImpfPerf/snPerfJuss's regions jointly exhaust {impf,perf,juss}, so the region-less default allomorph can never combine with an aspect suffix at all. + expect_fail: true + exercises: + - "Stem names" + + - word: hilaku + note: HLK's snImpfPerf-restricted allomorph "hilak" + IMPF ("-u") -- impf is in snImpfPerf's region {impf,perf}. + parses: + - signature: "HLK+IMPF|hilaku" + gloss: go-IMPF + rules: [mrAspImpf] + exercises: + - "Stem names" + + - word: hilaka + note: HLK's snImpfPerf-restricted allomorph "hilak" + JUSS ("-a") -- juss is NOT in snImpfPerf's region {impf,perf} -- zero parses. + expect_fail: true + exercises: + - "Stem names" + + - word: hilaki + note: >- + HLK's snImpfPerf-restricted allomorph "hilak" + PERF ("-i") -- perf is in snImpfPerf's region + {impf,perf} AND also in snPerfJuss's region {perf,juss}: the shared-region row, proving the + 1st-person-equivalent overlap between the two stem names doesn't spuriously block either one + (paired with hulaki below). + provenance: "W5, StemName selection + default-stem fallback" + parses: + - signature: "HLK+PERF|hilaki" + gloss: go-PERF + rules: [mrAspPerf] + exercises: + - "Stem names" + + - word: hulaka + note: HLK's snPerfJuss-restricted allomorph "hulak" + JUSS ("-a") -- juss is in snPerfJuss's region {perf,juss}. + parses: + - signature: "HLK+JUSS|hulaka" + gloss: go-JUSS + rules: [mrAspJuss] + exercises: + - "Stem names" + + - word: hulaku + note: HLK's snPerfJuss-restricted allomorph "hulak" + IMPF ("-u") -- impf is NOT in snPerfJuss's region {perf,juss} -- zero parses. + expect_fail: true + exercises: + - "Stem names" + + - word: hulaki + note: HLK's snPerfJuss-restricted allomorph "hulak" + PERF ("-i") -- the shared-region partner of hilaki above (perf is in BOTH regions), and both allomorphs must independently validate. + parses: + - signature: "HLK+PERF|hulaki" + gloss: go-PERF + rules: [mrAspPerf] + exercises: + - "Stem names" + + - word: gigugu + note: >- + FEEDSIM ("gigigi", posSimulDemo) under prSimulFeeding (Simultaneous): both candidate target + positions (3 and 5) have their environment checked against the SAME pre-rewrite snapshot, so + BOTH rewrite -> "gigugu". Simultaneous can never feed/bleed another match in the same pass. + Reconciliation finding: the traced rules: set for BOTH gigugu and gigugi includes both + prSimulFeeding AND prIterFeedingControl, not just the one whose candidate survives -- this is + TraceRuleAttributor's own documented "ambiguous word" limitation (see that class's doc + comment): the eFeedIter/eFeedSimul candidates are BOTH attempted during analysis (surface + "gigugu" unifies against both lexical entries' shared underlying shape "gigigi"), and even + though only the FEEDSIM candidate's synthesis-confirm ultimately matches "gigugu", the OTHER + candidate's own confirm attempt (which fires its own rule before failing to match the target + surface) is traced too -- the word-level trace walk unions rules fired across every attempted + candidate, not just the winning one. Declared rules: below is the honest traced union, per the + task brief's discipline ("the TRACE is authoritative"). + provenance: "P13 synthetic oracle, RewriteRuleTests.MultipleApplicationRules: Simultaneous blocks forward feeding" + parses: + - signature: "FEEDSIM|gigugu" + gloss: sway + rules: [prSimulFeeding, prIterFeedingControl] + exercises: + - "RewriteRule Simultaneous" + + - word: gigugi + note: >- + FEEDITER ("gigigi", posIterDemo) under prIterFeedingControl (Iterative, the default): position + 3 rewrites first (against the original shape), but by the time position 5 is checked its own + environment now reads position 3's ALREADY-rewritten value ("u", not the required front "i"), + so position 5 is NOT rewritten -> "gigugi". The mirror image of gigugu's all-at-once result. + Same traced-union finding as gigugu applies here (see that word's note) -- the FEEDSIM + candidate's own failed confirm attempt also traces prSimulFeeding. + provenance: "Iterative control sibling for rewrite/simultaneous-feeding" + parses: + - signature: "FEEDITER|gigugi" + gloss: twirl + rules: [prIterFeedingControl, prSimulFeeding] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: gigigi + note: >- + Bare "gigigi" is ambiguous between the FEEDSIM and FEEDITER lexical candidates, but each + root's own rule is obligatory wherever its environment holds -- FEEDSIM's candidate + synthesis-confirms to "gigugu" (not "gigigi"), and FEEDITER's candidate synthesis-confirms to + "gigugi" (not "gigigi") -- so neither candidate survives. Zero parses in both modes, exactly + mirroring v1's own bare-root negative control. + expect_fail: true + blocked_by: [prSimulFeeding, prIterFeedingControl] + exercises: + - "RewriteRule Simultaneous" + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: iktub + note: >- + KTUB ("write.IMP", posProthesis) bare root "ktub" begins with a word-initial 2-consonant + cluster ("kt") -- prProthesis obligatorily breaks it with a prothetic "i", a word-initial + prothesis pattern (cf. Form I imperative "uktub"). + provenance: "P1, RewriteRuleTests.BoundaryRules (bare-root word-initial epenthesis)" + parses: + - signature: "KTUB|iktub" + gloss: write.IMP + rules: [prProthesis] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: ktub + note: The raw, un-prothesized underlying shape -- prProthesis is obligatory whenever a word begins with a consonant cluster, so this surface form can never itself be a valid analysis. + expect_fail: true + blocked_by: [prProthesis] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: radda + note: >- + RAD ("kindle", posGeminate) bare root "rada" -- prGeminate unconditionally expands its single + "d" into two identical segments (1 segment -> 2 segments, no Environment at all), modeling + gemination as spreading. The raw unexpanded "rada" can never itself surface (see rada below). + provenance: "W9.2 probe, RewriteRuleTests.ExpandRules" + parses: + - signature: "RAD|radda" + gloss: kindle + rules: [prGeminate] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" + + - word: rada + note: The raw, un-geminated underlying shape -- prGeminate is unconditional (obligatory wherever "d" appears), so this surface form can never itself be a valid analysis. + expect_fail: true + blocked_by: [prGeminate] + exercises: + - "RewriteRule Iterative (epenthesis/deletion/feature/expansion/merge)" diff --git a/conformance/obligation-triage.tsv b/conformance/obligation-triage.tsv new file mode 100644 index 000000000..d959ce379 --- /dev/null +++ b/conformance/obligation-triage.tsv @@ -0,0 +1,60 @@ +# Triage of every coverage obligation, with status derived mechanically from gate-obligations.tsv +# and dataflow-obligations.tsv -- never hand-marked. +# bucket 1 = a word in an existing grammar should do it +# bucket 2 = needs a small grammar change HCLoader can produce and real morphology exhibits +# bucket 3 = legitimate but strained; low value +# 4-EXCLUDED = nothing can ever cover it +# 4-TOOLING = the obligation is real; the harness cannot express it (fix the tool, not the corpus) +# 4-ENGINE = the engine decides it but never traces it, so it cannot be observed +kind item bucket status construct_in_plain_language reason +arm AllomorphCoOccurrenceRules:Blocked 4-TOOLING Open this allomorph may only appear alongside that morpheme primaryAllomorph/otherAllomorphs are DTD #REQUIRED, so Sever always throws -- no word can ever witness this; needs a whole-element removal primitive +arm AllomorphCoOccurrenceRules:Control 4-TOOLING Open same, unblocked same +arm MorphemeCoOccurrenceRules:Blocked 4-TOOLING Open this morpheme may only appear alongside that one primaryMorpheme/otherMorphemes are DTD #REQUIRED, same as the allomorph pair +arm MorphemeCoOccurrenceRules:Control 4-TOOLING Open same, unblocked same +arm HeadRequiredSyntacticFeatureStruct:Blocked 1 COVERED the head of a compound must carry given features present in compounding-breadth and a language grammar; severing headPartsOfSpeech changed no word +arm HeadRequiredSyntacticFeatureStruct:Control 1 COVERED same, unblocked follows the Blocked arm +arm NonHeadProdRestrictMprFeatures:Blocked 2 Open the non-head of a compound must be productive for this rule no grammar declares nonHeadProdRestrictionsMprFeatures; its trace call works, so a grammar edit alone would cover it +arm NonHeadProdRestrictMprFeatures:Control 2 Open same, unblocked same +arm NonHeadRequiredSyntacticFeatureStruct:Blocked 4-ENGINE Open the non-head of a compound must carry given features AnalysisCompoundingRule.cs:65-73 discards a POS-mismatched nonhead with a bare continue and no trace call, so the synthesis raise site is dead in practice; needs one instrumentation line +arm NonHeadRequiredSyntacticFeatureStruct:Control 4-ENGINE Open same, unblocked same +cell LexicalEntry.partOfSpeech->AffixTemplate.requiredPartsOfSpeech 2 Open a slot template applies only to one part of speech every MorphologicalRule in every fixture redundantly re-declares its template requiredPartsOfSpeech, so severing the template alone never flips a word; needs a slot rule without its own gate +cell MorphologicalRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech 2 Open a derivation changes category, then a template checks the new one same redundant re-declaration +cell MorphologicalRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech 2 Open a derivation changes category, then a later affix checks it severing outputPartOfSpeech stops the override rather than blanking the category, so the stem reverts to its pre-derivation POS; needs a reader that rejects THAT value +cell MorphologicalRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech 2 Open a derivation changes category, then a sound rule checks it only two rules in the corpus have outputPartOfSpeech != requiredPartsOfSpeech and neither reaches a mismatched same-stratum subrule gate +cell LexicalEntry.ruleFeatures->PhonologicalSubrule.requiredMPRFeatures 4-EXCLUDED Open a sound rule fires only on roots flagged for it (exception feature / minor rule) the gate is a plain set-membership test (SynthesisRewriteSubruleSpec.cs:47-49), so severing a feature the ROOT presets can only turn a passing word into a failing one -- never the reverse. Only an affix-conferred or affix-destroyed feature can witness a required gate, which is what the three covered siblings use +cell LexicalEntry.ruleFeatures->PhonologicalSubrule.excludedMPRFeatures 2 COVERED a sound rule skips roots flagged as exceptions same absence; HCLoader.cs:2058 from FLEx's Excluded rule features +cell MorphologicalOutput.MPRFeatures->PhonologicalSubrule.requiredMPRFeatures 2 COVERED an affix confers a flag that a later sound rule requires same construct absence, affix-sourced rather than root-sourced +cell MorphologicalOutput.MPRFeatures->PhonologicalSubrule.excludedMPRFeatures 2 COVERED an affix confers a flag that blocks a later sound rule same construct absence +cell MorphologicalOutput.MPRFeatures->MorphologicalInput.excludedMPRFeatures 4-EXCLUDED COVERED an affix confers a flag that blocks a later affix witness is behaviourally genuine but should not have counted: HCLoader populates the reader ONLY from slot.ReferringObjects.OfType() (HCLoader.cs:1717, irregular-form blocking), never from an affix output, so no FieldWorks project can produce an affix-conferred version of this chain. Producibility does not compose -- both attributes are producible, the chain is not. +cell Allomorph.stemName->MorphologicalRule.requiredStemName 2 Open a rule demands a specific stem (principal parts) engine compares stem names by object identity; the only fixture with the reader declares ONE StemName, so no word can flip both sides. templatic-root-modification has two but no requiredStemName rule +cell LexicalEntry.ruleFeatures->MorphologicalInput.requiredMPRFeatures 2 Open a root flag that a later affix requires swept across all 71 words of both hosting fixtures with no flip; needs the ordering structure ygofz used, not just another word +cell CompoundingRule.outputPartOfSpeech->AffixTemplate.requiredPartsOfSpeech 2 Open a compound gets a category, then a template checks it outputPartOfSpeech exists only in compounding-breadth, which hosts no template POS gate +cell CompoundingRule.outputPartOfSpeech->MorphologicalRule.requiredPartsOfSpeech 2 COVERED a compound gets a category, then an affix checks it same: writer and reader are in different fixtures +cell CompoundingRule.outputPartOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech 2 Open a compound gets a category, then a sound rule checks it same: writer and reader are in different fixtures +arm HeadPattern:Blocked 2 Open the head of a compound must match a phonological shape no fixture's compounding candidates ever fail a shape match; they match by construction +arm HeadPattern:Control 2 Open same, matching depends on a shape that can fail +arm NonHeadPattern:Blocked 2 Open the non-head of a compound must match a phonological shape same as HeadPattern +arm NonHeadPattern:Control 2 Open same, matching same as HeadPattern +arm MaxApplicationCount:Blocked 3 Open an iterating rule stopped by its own application cap real (bounded reduplication) but a word must reach the cap exactly; strained to construct +arm MaxApplicationCount:Control 3 Open the same rule under the cap only meaningful beside the Blocked arm +arm NonPartialRuleProhibitedAfterFinalTemplate:Blocked 3 Open a non-partial rule may not apply after the final template template-ordering edge; present in a fixture but severing final/partial changed no word +arm NonPartialRuleProhibitedAfterFinalTemplate:Control 3 Open same, permitted follows the Blocked arm +arm NonPartialRuleRequiredAfterNonFinalTemplate:Blocked 3 Open a non-partial rule is required after a non-final template no fixture combines a partial rule with an explicit non-final template +arm NonPartialRuleRequiredAfterNonFinalTemplate:Control 3 Open same, satisfied follows the Blocked arm +arm ObligatorySyntacticFeatures:Blocked 4-EXCLUDED Open a promised feature never got filled in HCLoader never sets it, so no FieldWorks project can produce the construct; a witness would prove nothing about real use +arm ObligatorySyntacticFeatures:Control 4-EXCLUDED Open same, satisfied same +arm SurfaceFormMismatch:Blocked 4-EXCLUDED Open the engine's own reconstruction disagreed with the surface no XML reaches it; a pure engine-internal check with no grammar input +arm SurfaceFormMismatch:Control 4-EXCLUDED Open same, agreeing same +arm BoundRoot:Control 4-EXCLUDED Open a bound root used as a free word construct sits on Allomorph, which the DTD always nests under LexicalEntry and never under a rule -- no rule identity exists to attribute a Control arm to +arm ExcludedMprFeatures:Control 1 COVERED an affix skipped for a flag it excludes resolved by GrammarRuleIndex.ResolveAncestorRuleId: MorphologicalInput always nests under a rule, so the control word already in the corpus can now be attributed +arm ExcludedStemName:Control 4-EXCLUDED Open a rule refusing a specific stem same: Allomorph has no rule ancestor +arm PartialParse:Control 4-EXCLUDED Open a parse that consumed only part of the word construct sits on AffixTemplate, which nests under Stratum and which the DTD never gives an id -- no identity of any kind to attribute to +arm RequiredMprFeatures:Control 1 COVERED an affix firing on a flag it requires same ancestor resolution +arm RequiredStemName:Control 4-EXCLUDED Open a rule firing on the stem it demands same: Allomorph has no rule ancestor +arm RequiredSyntacticFeatureStruct:Control 1 COVERED a rule firing on features it requires same, via PhonologicalSubrule -> PhonologicalRule +arm DisjunctiveAllomorph:Blocked 4-TOOLING Open a more specific allomorph pre-empted a general one reachable through element content and allomorph order, not an attribute; no isolable severance primitive exists +arm DisjunctiveAllomorph:Control 4-TOOLING Open same, not pre-empted same +arm Environments:Blocked 4-TOOLING Open an allomorph rejected by its environment reachable through RequiredEnvironments/ExcludedEnvironments element content, not an attribute +arm Environments:Control 4-TOOLING Open same, accepted same +arm Pattern:Blocked 4-TOOLING Open a rule's phonological pattern did not match reachable through PhoneticSequence element content, not an attribute +arm Pattern:Control 4-TOOLING Open same, matched same diff --git a/conformance/parity-check.py b/conformance/parity-check.py new file mode 100644 index 000000000..7077a52a2 --- /dev/null +++ b/conformance/parity-check.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +""" +Conformance v1->v2 migration parity proof. + +Mechanically verifies the migration floors that guard the ONE irreversible step -- deletion of the v1 +fixture tree -- plus an absolute v2 construct-coverage check that outlives the deletion (gate G4). +Exits NONZERO on any violation, so it can gate CI and the delete commit. + +Checks (ledger "Floor summary (G4 parity check keys)"): + A. Provenance -- every v1 manifest.json 'provenance' string appears VERBATIM (exact value, not + substring) in some v2 words.yaml 'provenance:' field. One-way v1 -> v2. + B. Per-construct -- every construct named in any v1 manifest is exercised by >=1 v2 word (coverage.csv). + C. XAmple floor -- every construct covered by a requires:[] v1 fixture is exercised by >=1 word in a + requires:[] v2 grammar (quechua/latin/athabaskan or a requires:[] edge-case). + D. Absolute -- every constructs.txt construct except 'Tracing (TraceType)' is exercised by >=1 + v2 word. Independent of v1 tooling, so it still proves G4 after the delete. + +Once the v1 tree is deleted, A/B/C find zero v1 fixtures and report "migration complete"; only D runs. + +Usage: python conformance/parity-check.py [conformance_root] (default: this script's directory) +""" +import csv +import json +import os +import re +import sys + +OUT_OF_SCOPE = "Tracing (TraceType)" +EXPECTED_V1_COUNT = 41 # the frozen v1 fixture set, established during the v1->v2 migration + + +def die(msg): + print(f"parity-check: FATAL: {msg}", file=sys.stderr) + sys.exit(2) + + +def load_constructs_txt(path): + out = [] + with open(path, encoding="utf-8") as f: + for raw in f: + line = raw.strip() + if line and not line.startswith("#"): + out.append(line) + return out + + +def discover_v1(root): + """v1 fixture = a directory with manifest.json that is NOT under languages/ or edge-cases/ (those + are v2, keyed by words.yaml). Returns list of parsed manifests.""" + manifests = [] + for dirpath, _dirs, files in os.walk(root): + norm = dirpath.replace("\\", "/") + if "/languages/" in norm + "/" or "/edge-cases/" in norm + "/": + continue + if "manifest.json" in files: + with open(os.path.join(dirpath, "manifest.json"), encoding="utf-8") as f: + manifests.append(json.load(f)) + return manifests + + +def load_coverage(path): + """coverage.csv -> (set of all covered constructs, dict language -> set of constructs).""" + covered = set() + by_lang = {} + with open(path, encoding="utf-8", newline="") as f: + reader = csv.DictReader(f) + rows = 0 + for row in reader: + rows += 1 + construct = row["construct"] + lang = row["language"] + if construct: + covered.add(construct) + by_lang.setdefault(lang, set()).add(construct) + if rows == 0: + die(f"{path} has no data rows -- refusing to prove parity against an empty coverage table") + return covered, by_lang + + +PROV_RE = re.compile(r'^\s*provenance:\s*(.*\S)\s*$') +LANG_RE = re.compile(r'^language:\s*(.*\S)\s*$') +REQ_RE = re.compile(r'^requires:\s*\[(.*)\]\s*$') + + +def _strip_quotes(s): + if len(s) >= 2 and s[0] in "\"'" and s[-1] == s[0]: + return s[1:-1] + return s + + +def load_v2_words(langs_dir, edge_dir): + """Scan every v2 words.yaml. Returns (set of provenance strings, dict language -> requires-list).""" + provenance = set() + lang_requires = {} + for base in (langs_dir, edge_dir): + if not os.path.isdir(base): + continue + for name in sorted(os.listdir(base)): + wy = os.path.join(base, name, "words.yaml") + if not os.path.isfile(wy): + continue + lang = None + requires = None + with open(wy, encoding="utf-8") as f: + for raw in f: + # skip full-line comments so a '#'-commented example provenance never counts + if raw.lstrip().startswith("#"): + continue + m = PROV_RE.match(raw) + if m: + provenance.add(_strip_quotes(m.group(1))) + continue + if lang is None: + lm = LANG_RE.match(raw) + if lm: + lang = _strip_quotes(lm.group(1)) + if requires is None: + rm = REQ_RE.match(raw) + if rm: + inner = rm.group(1).strip() + requires = [t.strip() for t in inner.split(",") if t.strip()] + if lang is None: + die(f"{wy} has no 'language:' field") + if requires is None: + die(f"{wy} has no 'requires:' field") + lang_requires[lang] = requires + return provenance, lang_requires + + +def main(): + root = sys.argv[1] if len(sys.argv) > 1 else os.path.dirname(os.path.abspath(__file__)) + root = os.path.abspath(root) + coverage_csv = os.path.join(root, "coverage.csv") + constructs_txt = os.path.join(root, "constructs.txt") + langs_dir = os.path.join(root, "languages") + edge_dir = os.path.join(root, "edge-cases") + + for p in (coverage_csv, constructs_txt): + if not os.path.isfile(p): + die(f"missing required input: {p}") + + checklist = load_constructs_txt(constructs_txt) + v2_covered, v2_by_lang = load_coverage(coverage_csv) + v2_provenance, v2_lang_requires = load_v2_words(langs_dir, edge_dir) + v1 = discover_v1(root) + + failures = [] # list of (check, message) + print(f"parity-check: root={root}") + print(f"parity-check: discovered {len(v1)} v1 fixture(s), " + f"{len(v2_by_lang)} v2 grammar(s) in coverage.csv, " + f"{len(v2_provenance)} v2 provenance string(s), {len(checklist)} constructs.txt entries") + + v1_present = len(v1) > 0 + if v1_present and len(v1) != EXPECTED_V1_COUNT: + die(f"expected exactly {EXPECTED_V1_COUNT} v1 fixtures (the frozen set) or 0 (deleted); " + f"found {len(v1)} -- discovery bug or unexpected tree state, refusing to certify") + + # ---- A/B/C: v1 -> v2 floors (only while v1 exists) ---- + if not v1_present: + print("parity-check: no v1 fixtures found -- migration complete; running only absolute check D.") + else: + v1_constructs = set() + v1_provenance = set() + xample_constructs = set() # constructs of requires:[] v1 fixtures + for m in v1: + cons = set(m.get("constructs", [])) + v1_constructs |= cons + if "provenance" in m and m["provenance"]: + v1_provenance.add(m["provenance"]) + if m.get("requires", []) == []: + xample_constructs |= cons + if not v1_constructs: + die("parsed 0 constructs from v1 manifests -- schema/parse bug, refusing to certify") + + # A. provenance exact-value containment + missing_prov = sorted(p for p in v1_provenance if p not in v2_provenance) + if missing_prov: + for p in missing_prov: + failures.append(("A/provenance", f"v1 provenance not found verbatim in any v2 words.yaml: {p!r}")) + print(f"[{'PASS' if not missing_prov else 'FAIL'}] A. provenance: " + f"{len(v1_provenance) - len(missing_prov)}/{len(v1_provenance)} v1 strings carried verbatim") + + # B. per-construct floor + missing_cons = sorted(c for c in v1_constructs if c not in v2_covered) + if missing_cons: + for c in missing_cons: + failures.append(("B/per-construct", f"v1 construct not covered by any v2 word: {c!r}")) + print(f"[{'PASS' if not missing_cons else 'FAIL'}] B. per-construct floor: " + f"{len(v1_constructs) - len(missing_cons)}/{len(v1_constructs)} v1 constructs covered in v2") + + # C. XAmple floor: xample constructs must be covered by a requires:[] v2 grammar + xample_v2_langs = {lang for lang, req in v2_lang_requires.items() if req == []} + xample_v2_covered = set() + for lang in xample_v2_langs: + xample_v2_covered |= v2_by_lang.get(lang, set()) + missing_xample = sorted(c for c in xample_constructs if c not in xample_v2_covered) + if missing_xample: + for c in missing_xample: + failures.append(("C/xample", f"requires:[] v1 construct has no requires:[] v2 home: {c!r}")) + print(f"[{'PASS' if not missing_xample else 'FAIL'}] C. XAmple floor: " + f"{len(xample_constructs) - len(missing_xample)}/{len(xample_constructs)} requires:[] constructs " + f"have a requires:[] v2 home (v2 requires:[] grammars: {sorted(xample_v2_langs)})") + + # ---- D: absolute construct coverage (always) ---- + in_scope = [c for c in checklist if c != OUT_OF_SCOPE] + uncovered = sorted(c for c in in_scope if c not in v2_covered) + if uncovered: + for c in uncovered: + failures.append(("D/absolute", f"constructs.txt construct at zero v2 coverage: {c!r}")) + print(f"[{'PASS' if not uncovered else 'FAIL'}] D. absolute coverage: " + f"{len(in_scope) - len(uncovered)}/{len(in_scope)} in-scope constructs covered " + f"('{OUT_OF_SCOPE}' out of scope by design)") + + print() + if failures: + print(f"parity-check: FAILED with {len(failures)} violation(s):") + for check, msg in failures: + print(f" [{check}] {msg}") + sys.exit(1) + print("parity-check: ALL CHECKS PASSED -- v1 coverage is fully preserved in v2; safe to delete the v1 tree.") + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/conformance/rule-interaction-pairs.tsv b/conformance/rule-interaction-pairs.tsv new file mode 100644 index 000000000..796b1c1f2 --- /dev/null +++ b/conformance/rule-interaction-pairs.tsv @@ -0,0 +1,1470 @@ +# GENERATED by hc-conformance --write-rule-interaction-pairs. One line per pipeline-permitted +# ordered pair of rule-bearing units within a Stratum (or between two adjacent Strata) -- +# OrderingGenerator.EnumerateStratumPairs's denominator for rule-interaction coverage, classified +# by CheckStratumPairDisjointDomains. Self-pairs are included (see the method doc for why); an +# AffixTemplate is one unit, never exploded into its Slot rules -- those are already pinned by +# OrderingGenerator's adjacent-pair AffixTemplateSlots list. pair_kind is same-stage, cross-stage, +# or cross-stratum. domain_relation is only ever Disjoint/Overlaps for a PhonologicalRule pair; +# every other unit-kind combination is Undetermined by construction. +fixture stratum_a stratum_b pair_kind unit_a_kind unit_a unit_b_kind unit_b domain_relation +edge-cases/alpha-variable-name-collision Main Main SameStage PhonologicalRule prDoubleAlpha PhonologicalRule prDoubleAlpha Overlaps +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crDecoy MorphologicalRule crDecoy Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crDecoy MorphologicalRule crJoin Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crDecoy MorphologicalRule crJoinInsert Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crDecoy MorphologicalRule crNever Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crDecoy MorphologicalRule mrTplSuf Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoin MorphologicalRule crDecoy Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoin MorphologicalRule crJoin Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoin MorphologicalRule crJoinInsert Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoin MorphologicalRule crNever Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoin MorphologicalRule mrTplSuf Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoinInsert MorphologicalRule crDecoy Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoinInsert MorphologicalRule crJoin Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoinInsert MorphologicalRule crJoinInsert Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoinInsert MorphologicalRule crNever Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crJoinInsert MorphologicalRule mrTplSuf Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crNever MorphologicalRule crDecoy Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crNever MorphologicalRule crJoin Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crNever MorphologicalRule crJoinInsert Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crNever MorphologicalRule crNever Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule crNever MorphologicalRule mrTplSuf Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule mrTplSuf MorphologicalRule crDecoy Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule mrTplSuf MorphologicalRule crJoin Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule mrTplSuf MorphologicalRule crJoinInsert Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule mrTplSuf MorphologicalRule crNever Undetermined +edge-cases/compounding-breadth Main Main SameStage MorphologicalRule mrTplSuf MorphologicalRule mrTplSuf Undetermined +edge-cases/deep-optional-affix-nesting Main Main SameStage AffixTemplate deepOptionalTemplate AffixTemplate deepOptionalTemplate Undetermined +edge-cases/diacritic-segments Main Main SameStage MorphologicalRule rDim MorphologicalRule rDim Undetermined +edge-cases/diacritic-segments Main Main SameStage MorphologicalRule rDim MorphologicalRule rPl Undetermined +edge-cases/diacritic-segments Main Main SameStage MorphologicalRule rDim AffixTemplate suffixTemplate Undetermined +edge-cases/diacritic-segments Main Main SameStage MorphologicalRule rPl MorphologicalRule rDim Undetermined +edge-cases/diacritic-segments Main Main SameStage MorphologicalRule rPl MorphologicalRule rPl Undetermined +edge-cases/diacritic-segments Main Main SameStage MorphologicalRule rPl AffixTemplate suffixTemplate Undetermined +edge-cases/diacritic-segments Main Main SameStage AffixTemplate suffixTemplate MorphologicalRule rDim Undetermined +edge-cases/diacritic-segments Main Main SameStage AffixTemplate suffixTemplate MorphologicalRule rPl Undetermined +edge-cases/diacritic-segments Main Main SameStage AffixTemplate suffixTemplate AffixTemplate suffixTemplate Undetermined +edge-cases/disjunctive-recheck Main Main SameStage MorphologicalRule ruleD MorphologicalRule ruleD Undetermined +edge-cases/disjunctive-recheck Main Main SameStage MorphologicalRule ruleD MorphologicalRule ruleT Undetermined +edge-cases/disjunctive-recheck Main Main SameStage MorphologicalRule ruleT MorphologicalRule ruleD Undetermined +edge-cases/disjunctive-recheck Main Main SameStage MorphologicalRule ruleT MorphologicalRule ruleT Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrAgr Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrEmph Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrLoud Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrAgr MorphologicalRule rrPast Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrEmph MorphologicalRule mrAgr Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrEmph MorphologicalRule mrEmph Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrEmph MorphologicalRule mrLoud Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrEmph MorphologicalRule rrPast Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrLoud MorphologicalRule mrAgr Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrLoud MorphologicalRule mrEmph Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrLoud MorphologicalRule mrLoud Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule mrLoud MorphologicalRule rrPast Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrAgr Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrEmph Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrLoud Undetermined +edge-cases/feature-gating-breadth Main Main SameStage MorphologicalRule rrPast MorphologicalRule rrPast Undetermined +edge-cases/feature-system-breadth Main Main SameStage MorphologicalRule mrSuffixK MorphologicalRule mrSuffixK Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtDecoy PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtDecoy PhonologicalRule prDecFeat Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtDecoy PhonologicalRule prDecFnc Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtDecoy PhonologicalRule prDecNc Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwap PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwap PhonologicalRule mtSwap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwap PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwap PhonologicalRule prDecFeat Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwap PhonologicalRule prDecFnc Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwap PhonologicalRule prDecNc Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwapOverlap PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwapOverlap PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwapOverlap PhonologicalRule prDecFeat Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwapOverlap PhonologicalRule prDecFnc Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule mtSwapOverlap PhonologicalRule prDecNc Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule mtSwap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule prAlpha Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule prDecFeat Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule prDecFnc Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule prDecNc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prAlpha PhonologicalRule prHighTrigger Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecFeat PhonologicalRule prDecFeat Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecFeat PhonologicalRule prDecFnc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecFeat PhonologicalRule prDecNc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecFnc PhonologicalRule prDecFnc Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecNc PhonologicalRule prDecFnc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecNc PhonologicalRule prDecNc Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule mtSwap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule prAlpha Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule prDecFeat Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule prDecFnc Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule prDecNc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule prDecoy Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prDecoy PhonologicalRule prHighTrigger Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule mtSwap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule prDecFeat Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule prDecFnc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule prDecNc Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prHighTrigger PhonologicalRule prHighTrigger Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule mtSwap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prAlpha Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prDecFeat Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prDecFnc Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prDecNc Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prDecoy Overlaps +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prHighTrigger Disjoint +edge-cases/feature-system-breadth Main Main SameStage PhonologicalRule prRaise PhonologicalRule prRaise Overlaps +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule mtDecoy Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule mtSwap Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule mtSwapOverlap Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prAlpha Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prDecFeat Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prDecFnc Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prDecNc Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prDecoy Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prHighTrigger Undetermined +edge-cases/feature-system-breadth Main Main CrossStage MorphologicalRule mrSuffixK PhonologicalRule prRaise Undetermined +edge-cases/free-fluctuating-allomorph-pair S S SameStage MorphologicalRule ruleS MorphologicalRule ruleS Undetermined +edge-cases/loader-default-symbol main main SameStage PhonologicalRule pr1 PhonologicalRule pr1 Undetermined +edge-cases/loader-isactive-breadth Main Main SameStage AffixTemplate decoyTemplate AffixTemplate decoyTemplate Undetermined +edge-cases/loader-isactive-breadth Main Main SameStage AffixTemplate decoyTemplate AffixTemplate liveTemplate Undetermined +edge-cases/loader-isactive-breadth Main Main SameStage AffixTemplate liveTemplate AffixTemplate decoyTemplate Undetermined +edge-cases/loader-isactive-breadth Main Main SameStage AffixTemplate liveTemplate AffixTemplate liveTemplate Undetermined +edge-cases/metathesis-comparison-crash Main Main SameStage PhonologicalRule mtSwap PhonologicalRule mtSwap Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrConferExcl MorphologicalRule mrConferExcl Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrConferExcl MorphologicalRule mrExclReader Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrConferExcl MorphologicalRule mrRep0 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrConferExcl MorphologicalRule mrRep2 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrConferExcl AffixTemplate finalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrConferExcl AffixTemplate nonFinalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrExclReader MorphologicalRule mrConferExcl Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrExclReader MorphologicalRule mrExclReader Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrExclReader MorphologicalRule mrRep0 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrExclReader MorphologicalRule mrRep2 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrExclReader AffixTemplate finalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrExclReader AffixTemplate nonFinalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep0 MorphologicalRule mrConferExcl Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep0 MorphologicalRule mrExclReader Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep0 MorphologicalRule mrRep0 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep0 MorphologicalRule mrRep2 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep0 AffixTemplate finalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep0 AffixTemplate nonFinalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep2 MorphologicalRule mrConferExcl Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep2 MorphologicalRule mrExclReader Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep2 MorphologicalRule mrRep0 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep2 MorphologicalRule mrRep2 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep2 AffixTemplate finalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage MorphologicalRule mrRep2 AffixTemplate nonFinalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate finalTemplate MorphologicalRule mrConferExcl Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate finalTemplate MorphologicalRule mrExclReader Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate finalTemplate MorphologicalRule mrRep0 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate finalTemplate MorphologicalRule mrRep2 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate finalTemplate AffixTemplate finalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate finalTemplate AffixTemplate nonFinalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate nonFinalTemplate MorphologicalRule mrConferExcl Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate nonFinalTemplate MorphologicalRule mrExclReader Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate nonFinalTemplate MorphologicalRule mrRep0 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate nonFinalTemplate MorphologicalRule mrRep2 Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate nonFinalTemplate AffixTemplate finalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Main Main SameStage AffixTemplate nonFinalTemplate AffixTemplate nonFinalTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Second Second SameStage MorphologicalRule mrPO MorphologicalRule mrPO Undetermined +edge-cases/morphotactic-attribute-breadth Second Second SameStage MorphologicalRule mrPO AffixTemplate pogTemplate Undetermined +edge-cases/morphotactic-attribute-breadth Second Second SameStage AffixTemplate pogTemplate MorphologicalRule mrPO Undetermined +edge-cases/morphotactic-attribute-breadth Second Second SameStage AffixTemplate pogTemplate AffixTemplate pogTemplate Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrDelExclSrc MorphologicalRule mrDelExclSrc Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrDelExclSrc MorphologicalRule mrNPfx Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrDelExclSrc MorphologicalRule mrSuf Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrDelExclSrc MorphologicalRule mrSufAlt Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrNPfx MorphologicalRule mrDelExclSrc Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrNPfx MorphologicalRule mrNPfx Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrNPfx MorphologicalRule mrSuf Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrNPfx MorphologicalRule mrSufAlt Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSuf MorphologicalRule mrDelExclSrc Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSuf MorphologicalRule mrNPfx Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSuf MorphologicalRule mrSuf Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSuf MorphologicalRule mrSufAlt Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSufAlt MorphologicalRule mrDelExclSrc Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSufAlt MorphologicalRule mrNPfx Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSufAlt MorphologicalRule mrSuf Undetermined +edge-cases/mpr-gated-exception Main Main SameStage MorphologicalRule mrSufAlt MorphologicalRule mrSufAlt Undetermined +edge-cases/mpr-gated-exception Main Main SameStage PhonologicalRule prNasalAssimAlveolar PhonologicalRule prNasalAssimAlveolar Overlaps +edge-cases/mpr-gated-exception Main Main SameStage PhonologicalRule prNasalAssimAlveolar PhonologicalRule prObstruentDeletion Overlaps +edge-cases/mpr-gated-exception Main Main SameStage PhonologicalRule prNasalAssimBilabial PhonologicalRule prNasalAssimAlveolar Overlaps +edge-cases/mpr-gated-exception Main Main SameStage PhonologicalRule prNasalAssimBilabial PhonologicalRule prNasalAssimBilabial Overlaps +edge-cases/mpr-gated-exception Main Main SameStage PhonologicalRule prNasalAssimBilabial PhonologicalRule prObstruentDeletion Overlaps +edge-cases/mpr-gated-exception Main Main SameStage PhonologicalRule prObstruentDeletion PhonologicalRule prObstruentDeletion Overlaps +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrDelExclSrc PhonologicalRule prNasalAssimAlveolar Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrDelExclSrc PhonologicalRule prNasalAssimBilabial Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrDelExclSrc PhonologicalRule prObstruentDeletion Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrNPfx PhonologicalRule prNasalAssimAlveolar Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrNPfx PhonologicalRule prNasalAssimBilabial Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrNPfx PhonologicalRule prObstruentDeletion Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrSuf PhonologicalRule prNasalAssimAlveolar Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrSuf PhonologicalRule prNasalAssimBilabial Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrSuf PhonologicalRule prObstruentDeletion Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrSufAlt PhonologicalRule prNasalAssimAlveolar Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrSufAlt PhonologicalRule prNasalAssimBilabial Undetermined +edge-cases/mpr-gated-exception Main Main CrossStage MorphologicalRule mrSufAlt PhonologicalRule prObstruentDeletion Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrEndC MorphologicalRule mrEndC Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrEndC MorphologicalRule mrThemeA Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrEndC MorphologicalRule mrThemeB Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrThemeA MorphologicalRule mrEndC Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrThemeA MorphologicalRule mrThemeA Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrThemeA MorphologicalRule mrThemeB Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrThemeB MorphologicalRule mrEndC Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrThemeB MorphologicalRule mrThemeA Undetermined +edge-cases/mpr-group-overwrite-without-realizational S S SameStage MorphologicalRule mrThemeB MorphologicalRule mrThemeB Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGatePQ MorphologicalRule mrGatePQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGatePQ MorphologicalRule mrGateX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGatePQ MorphologicalRule mrSetP Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGatePQ MorphologicalRule mrSetQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGatePQ MorphologicalRule mrSetX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGatePQ MorphologicalRule mrSetY Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGateX MorphologicalRule mrGatePQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGateX MorphologicalRule mrGateX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGateX MorphologicalRule mrSetP Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGateX MorphologicalRule mrSetQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGateX MorphologicalRule mrSetX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrGateX MorphologicalRule mrSetY Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetP MorphologicalRule mrGatePQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetP MorphologicalRule mrGateX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetP MorphologicalRule mrSetP Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetP MorphologicalRule mrSetQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetP MorphologicalRule mrSetX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetP MorphologicalRule mrSetY Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetQ MorphologicalRule mrGatePQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetQ MorphologicalRule mrGateX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetQ MorphologicalRule mrSetP Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetQ MorphologicalRule mrSetQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetQ MorphologicalRule mrSetX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetQ MorphologicalRule mrSetY Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetX MorphologicalRule mrGatePQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetX MorphologicalRule mrGateX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetX MorphologicalRule mrSetP Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetX MorphologicalRule mrSetQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetX MorphologicalRule mrSetX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetX MorphologicalRule mrSetY Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetY MorphologicalRule mrGatePQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetY MorphologicalRule mrGateX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetY MorphologicalRule mrSetP Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetY MorphologicalRule mrSetQ Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetY MorphologicalRule mrSetX Undetermined +edge-cases/mpr-overwrite-order-dependence Main Main SameStage MorphologicalRule mrSetY MorphologicalRule mrSetY Undetermined +edge-cases/process-morphology-in-place-mutation S S SameStage MorphologicalRule mrAblaut MorphologicalRule mrAblaut Undetermined +edge-cases/right-to-left-anchor-environment Main Main SameStage PhonologicalRule prRtlAnchor PhonologicalRule prRtlAnchor Overlaps +edge-cases/right-to-left-anchor-environment Main Main SameStage PhonologicalRule prRtlAnchor PhonologicalRule prSpread Overlaps +edge-cases/right-to-left-anchor-environment Main Main SameStage PhonologicalRule prSpread PhonologicalRule prSpread Overlaps +edge-cases/simultaneous-epenthesis-cascade Main Main SameStage PhonologicalRule prule4 PhonologicalRule prule4 Overlaps +edge-cases/stem-name-restricted-root-allomorph S S SameStage MorphologicalRule mrPers1 MorphologicalRule mrPers1 Undetermined +edge-cases/stem-name-restricted-root-allomorph S S SameStage MorphologicalRule mrPers1 MorphologicalRule mrPers2 Undetermined +edge-cases/stem-name-restricted-root-allomorph S S SameStage MorphologicalRule mrPers2 MorphologicalRule mrPers1 Undetermined +edge-cases/stem-name-restricted-root-allomorph S S SameStage MorphologicalRule mrPers2 MorphologicalRule mrPers2 Undetermined +edge-cases/strrep-identity Main Main SameStage MorphologicalRule ruleObj MorphologicalRule ruleObj Undetermined +edge-cases/strrep-identity Main Main SameStage MorphologicalRule ruleObj MorphologicalRule rulePfx Undetermined +edge-cases/strrep-identity Main Main SameStage MorphologicalRule rulePfx MorphologicalRule ruleObj Undetermined +edge-cases/strrep-identity Main Main SameStage MorphologicalRule rulePfx MorphologicalRule rulePfx Undetermined +edge-cases/subrule-morphosyntactic-gating Main Main SameStage MorphologicalRule mrDerive MorphologicalRule mrDerive Undetermined +edge-cases/subrule-morphosyntactic-gating Main Main SameStage PhonologicalRule prGate PhonologicalRule prGate Overlaps +edge-cases/subrule-morphosyntactic-gating Main Main CrossStage MorphologicalRule mrDerive PhonologicalRule prGate Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncLead MorphologicalRule mruleTruncLead Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncLead MorphologicalRule mruleTruncOptIns Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncLead MorphologicalRule mruleTruncTrail Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncOptIns MorphologicalRule mruleTruncLead Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncOptIns MorphologicalRule mruleTruncOptIns Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncOptIns MorphologicalRule mruleTruncTrail Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncTrail MorphologicalRule mruleTruncLead Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncTrail MorphologicalRule mruleTruncOptIns Undetermined +edge-cases/truncate-morphotactic Main Main SameStage MorphologicalRule mruleTruncTrail MorphologicalRule mruleTruncTrail Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrAblaut MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCircumfixGeT MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundConstrained MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundHN MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrCompoundNH MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrNasalInfix MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPast2 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers1 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers2 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPers3 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPl2 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe1 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrPrefixBe2 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrSuffixS3 MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule mrTense MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrAblaut Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrCircumfixGeT Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrCompoundConstrained Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrCompoundHN Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrCompoundNH Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrNasalInfix Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPast2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPers1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPers2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPers3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPl2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPrefixBe1 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPrefixBe2 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrSuffixS3 Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrTense Undetermined +languages/fusional-realizational-morphology Main Main SameStage MorphologicalRule rrPast MorphologicalRule rrPast Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndH MorphologicalRule mrEndH Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndH MorphologicalRule mrEndW Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndH MorphologicalRule mrEndZ Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndH MorphologicalRule mrThemeX Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndH MorphologicalRule mrThemeY Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndW MorphologicalRule mrEndH Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndW MorphologicalRule mrEndW Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndW MorphologicalRule mrEndZ Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndW MorphologicalRule mrThemeX Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndW MorphologicalRule mrThemeY Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndZ MorphologicalRule mrEndH Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndZ MorphologicalRule mrEndW Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndZ MorphologicalRule mrEndZ Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndZ MorphologicalRule mrThemeX Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrEndZ MorphologicalRule mrThemeY Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeX MorphologicalRule mrEndH Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeX MorphologicalRule mrEndW Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeX MorphologicalRule mrEndZ Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeX MorphologicalRule mrThemeX Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeX MorphologicalRule mrThemeY Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeY MorphologicalRule mrEndH Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeY MorphologicalRule mrEndW Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeY MorphologicalRule mrEndZ Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeY MorphologicalRule mrThemeX Undetermined +languages/fusional-realizational-morphology MprGroups MprGroups SameStage MorphologicalRule mrThemeY MorphologicalRule mrThemeY Undetermined +languages/metathesis-phase-isolation ComplexMeta ComplexMeta SameStage MorphologicalRule mrUSuffix MorphologicalRule mrUSuffix Undetermined +languages/metathesis-phase-isolation ComplexMeta ComplexMeta SameStage PhonologicalRule mrComplexMeta PhonologicalRule mrComplexMeta Undetermined +languages/metathesis-phase-isolation ComplexMeta ComplexMeta CrossStage MorphologicalRule mrUSuffix PhonologicalRule mrComplexMeta Undetermined +languages/metathesis-phase-isolation ComplexMeta SimpleMeta CrossStratum PhonologicalRule mrComplexMeta MorphologicalRule mrISuffix Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrCircum MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrInfixUm MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrLnk MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrPerf MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupCV MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrRedupFull MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage MorphologicalRule mrTrunc MorphologicalRule mrTrunc Undetermined +languages/metathesis-phase-isolation Morphology Morphology SameStage PhonologicalRule prNonContig PhonologicalRule prNonContig Overlaps +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrCircum PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrInfixUm PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrLnk PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrPerf PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrRedupCV PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrRedupFull PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation Morphology Morphology CrossStage MorphologicalRule mrTrunc PhonologicalRule prNonContig Undetermined +languages/metathesis-phase-isolation SimpleMeta SimpleMeta SameStage MorphologicalRule mrISuffix MorphologicalRule mrISuffix Undetermined +languages/metathesis-phase-isolation SimpleMeta SimpleMeta SameStage PhonologicalRule mrSimpleMeta PhonologicalRule mrSimpleMeta Undetermined +languages/metathesis-phase-isolation SimpleMeta SimpleMeta CrossStage MorphologicalRule mrISuffix PhonologicalRule mrSimpleMeta Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrCircum Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrInfixUm Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrLnk Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrPerf Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrRedupCV Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrRedupFull Undetermined +languages/metathesis-phase-isolation SimpleMeta Morphology CrossStratum PhonologicalRule mrSimpleMeta MorphologicalRule mrTrunc Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundHN MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrCompoundNH MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrDeriv MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrDeriv MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrDeriv MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrDeriv MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrDeriv MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixMa2 MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixMa2 MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixMa2 MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixMa2 MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixMa2 MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixPi1 MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixPi1 MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixPi1 MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixPi1 MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Derivation Derivation SameStage MorphologicalRule mrPrefixPi1 MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Inflection Inflection SameStage MorphologicalRule mrInfl MorphologicalRule mrInfl Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prDelReins PhonologicalRule prDelReins Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prDelReins PhonologicalRule prMDC1 Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prDelReins PhonologicalRule prMDC2 Disjoint +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prDelReins PhonologicalRule prMultiSeg Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prMDC1 PhonologicalRule prMDC1 Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prMDC1 PhonologicalRule prMDC2 Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prMDC2 PhonologicalRule prMDC2 Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prMultiSeg PhonologicalRule prMDC1 Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prMultiSeg PhonologicalRule prMDC2 Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Phonology SameStage PhonologicalRule prMultiSeg PhonologicalRule prMultiSeg Overlaps +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prDelReins MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prDelReins MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prDelReins MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prDelReins MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prDelReins MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC1 MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC1 MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC1 MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC1 MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC1 MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC2 MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC2 MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC2 MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC2 MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMDC2 MorphologicalRule mrPrefixPi1 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMultiSeg MorphologicalRule mrCompoundHN Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMultiSeg MorphologicalRule mrCompoundNH Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMultiSeg MorphologicalRule mrDeriv Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMultiSeg MorphologicalRule mrPrefixMa2 Undetermined +languages/polysynthetic-stratal-derivation-chain Phonology Derivation CrossStratum PhonologicalRule prMultiSeg MorphologicalRule mrPrefixPi1 Undetermined +languages/prefixal-discontinuous-slot-dependency Main Main SameStage AffixTemplate verbPrefixTemplate AffixTemplate verbPrefixTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidAssum AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidConjectural AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidDirect AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidMir AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrEvidReportative AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1 AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson1PlIncl AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2 AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson2Pl AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPerson3 AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage MorphologicalRule mrPlural AffixTemplate verbTemplate Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrEvidAssum Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrEvidConjectural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrEvidDirect Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrEvidMir Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrEvidReportative Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPerson1 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPerson1PlIncl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPerson2 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPerson2Pl Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPerson3 Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPlural Undetermined +languages/suffixing-evidential-adjacency-chain Main Main SameStage AffixTemplate verbTemplate AffixTemplate verbTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAgr AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrAppl AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrCaus AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndH AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndW AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrEndZ AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtX AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrExtY AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrFV AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrNumPl AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhXSource AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrPhonoDestroy AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRecurSuf AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrRedup AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrStemReq AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule mrTense AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrPast AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage MorphologicalRule rrRRealTest AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrAgr Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrAppl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrCaus Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrEndH Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrEndW Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrEndZ Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrExtX Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrExtY Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrFV Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrNumPl Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrPhXSource Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrPhonoDestroy Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrRecurSuf Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrRedup Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrStemReq Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule mrTense Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule rrPast Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate MorphologicalRule rrRRealTest Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage AffixTemplate extensionTemplate AffixTemplate extensionTemplate Undetermined +languages/suffixing-extension-slot-ordering Main Main SameStage PhonologicalRule prNasalMutation PhonologicalRule prNasalMutation Overlaps +languages/suffixing-extension-slot-ordering Main Main SameStage PhonologicalRule prNasalMutation PhonologicalRule prPhonoExcl Overlaps +languages/suffixing-extension-slot-ordering Main Main SameStage PhonologicalRule prNasalMutation PhonologicalRule prPhonoReq Overlaps +languages/suffixing-extension-slot-ordering Main Main SameStage PhonologicalRule prPhonoExcl PhonologicalRule prPhonoExcl Overlaps +languages/suffixing-extension-slot-ordering Main Main SameStage PhonologicalRule prPhonoReq PhonologicalRule prPhonoExcl Overlaps +languages/suffixing-extension-slot-ordering Main Main SameStage PhonologicalRule prPhonoReq PhonologicalRule prPhonoReq Overlaps +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrAgr PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrAgr PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrAgr PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrAppl PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrAppl PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrAppl PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrCaus PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrCaus PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrCaus PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndH PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndH PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndH PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndW PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndW PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndW PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndZ PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndZ PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrEndZ PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrExtX PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrExtX PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrExtX PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrExtY PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrExtY PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrExtY PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrFV PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrFV PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrFV PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrNumPl PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrNumPl PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrNumPl PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrPhXSource PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrPhXSource PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrPhXSource PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrPhonoDestroy PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrPhonoDestroy PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrPhonoDestroy PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrRecurSuf PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrRecurSuf PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrRecurSuf PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrRedup PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrRedup PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrRedup PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrStemReq PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrStemReq PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrStemReq PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrTense PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrTense PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule mrTense PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule rrPast PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule rrPast PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule rrPast PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule rrRRealTest PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule rrRRealTest PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage MorphologicalRule rrRRealTest PhonologicalRule prPhonoReq Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage AffixTemplate extensionTemplate PhonologicalRule prNasalMutation Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage AffixTemplate extensionTemplate PhonologicalRule prPhonoExcl Undetermined +languages/suffixing-extension-slot-ordering Main Main CrossStage AffixTemplate extensionTemplate PhonologicalRule prPhonoReq Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrAlphaSuf AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPast AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPlural AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule mrPres AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleCollective AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage MorphologicalRule ruleInfixDemo AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrAlphaSuf Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPast Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPlural Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate MorphologicalRule mrPres Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate MorphologicalRule ruleCollective Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate MorphologicalRule ruleInfixDemo Undetermined +languages/suffixing-vowel-harmony Main Main SameStage AffixTemplate verbTemplate AffixTemplate verbTemplate Undetermined +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prAlphaHighHarmony PhonologicalRule prAlphaHighHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prBacknessHarmony PhonologicalRule prAlphaHighHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prBacknessHarmony PhonologicalRule prBacknessHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prBacknessHarmony PhonologicalRule prEpenthesis Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prBacknessHarmony PhonologicalRule prGradation Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prBacknessHarmony PhonologicalRule prVowelMerge Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prBacknessHarmony PhonologicalRule prVowelMultiMerge Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prAlphaHighHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prEpenthesis Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prGradation PhonologicalRule prAlphaHighHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prGradation PhonologicalRule prEpenthesis Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prGradation PhonologicalRule prGradation Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMerge PhonologicalRule prAlphaHighHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMerge PhonologicalRule prEpenthesis Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMerge PhonologicalRule prGradation Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMerge PhonologicalRule prVowelMerge Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMerge PhonologicalRule prVowelMultiMerge Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMultiMerge PhonologicalRule prAlphaHighHarmony Overlaps +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMultiMerge PhonologicalRule prEpenthesis Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMultiMerge PhonologicalRule prGradation Disjoint +languages/suffixing-vowel-harmony Main Main SameStage PhonologicalRule prVowelMultiMerge PhonologicalRule prVowelMultiMerge Overlaps +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrAlphaSuf PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrAlphaSuf PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrAlphaSuf PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrAlphaSuf PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrAlphaSuf PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrAlphaSuf PhonologicalRule prVowelMultiMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPast PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPast PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPast PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPast PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPast PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPast PhonologicalRule prVowelMultiMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPlural PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPlural PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPlural PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPlural PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPlural PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPlural PhonologicalRule prVowelMultiMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPres PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPres PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPres PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPres PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPres PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule mrPres PhonologicalRule prVowelMultiMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleCollective PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleCollective PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleCollective PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleCollective PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleCollective PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleCollective PhonologicalRule prVowelMultiMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleInfixDemo PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleInfixDemo PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleInfixDemo PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleInfixDemo PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleInfixDemo PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage MorphologicalRule ruleInfixDemo PhonologicalRule prVowelMultiMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage AffixTemplate verbTemplate PhonologicalRule prAlphaHighHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage AffixTemplate verbTemplate PhonologicalRule prBacknessHarmony Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage AffixTemplate verbTemplate PhonologicalRule prEpenthesis Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage AffixTemplate verbTemplate PhonologicalRule prGradation Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage AffixTemplate verbTemplate PhonologicalRule prVowelMerge Undetermined +languages/suffixing-vowel-harmony Main Main CrossStage AffixTemplate verbTemplate PhonologicalRule prVowelMultiMerge Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspImpf MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspJuss MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrAspPerf MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrFormII MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPassive MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf1sg MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrAspImpf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrAspJuss Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrAspPerf Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrFormII Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrPassive Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrPerf1sg Undetermined +languages/templatic-root-modification Main Main SameStage MorphologicalRule mrPerf3sg MorphologicalRule mrPerf3sg Undetermined +languages/templatic-root-modification Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prEpenthesis Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prGeminate Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prIterFeedingControl Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prProthesis Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prEpenthesis PhonologicalRule prSimulFeeding Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prGeminate PhonologicalRule prGeminate Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prIterFeedingControl PhonologicalRule prGeminate Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prIterFeedingControl PhonologicalRule prIterFeedingControl Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prProthesis PhonologicalRule prGeminate Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prProthesis PhonologicalRule prIterFeedingControl Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prProthesis PhonologicalRule prProthesis Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prProthesis PhonologicalRule prSimulFeeding Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prSimulFeeding PhonologicalRule prGeminate Disjoint +languages/templatic-root-modification Main Main SameStage PhonologicalRule prSimulFeeding PhonologicalRule prIterFeedingControl Overlaps +languages/templatic-root-modification Main Main SameStage PhonologicalRule prSimulFeeding PhonologicalRule prSimulFeeding Overlaps +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspImpf PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspImpf PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspImpf PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspImpf PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspImpf PhonologicalRule prSimulFeeding Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspJuss PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspJuss PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspJuss PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspJuss PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspJuss PhonologicalRule prSimulFeeding Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspPerf PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspPerf PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspPerf PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspPerf PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrAspPerf PhonologicalRule prSimulFeeding Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrFormII PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrFormII PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrFormII PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrFormII PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrFormII PhonologicalRule prSimulFeeding Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPassive PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPassive PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPassive PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPassive PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPassive PhonologicalRule prSimulFeeding Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf1sg PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf1sg PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf1sg PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf1sg PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf1sg PhonologicalRule prSimulFeeding Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf3sg PhonologicalRule prEpenthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf3sg PhonologicalRule prGeminate Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf3sg PhonologicalRule prIterFeedingControl Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf3sg PhonologicalRule prProthesis Undetermined +languages/templatic-root-modification Main Main CrossStage MorphologicalRule mrPerf3sg PhonologicalRule prSimulFeeding Undetermined diff --git a/conformance/rules.csv b/conformance/rules.csv new file mode 100644 index 000000000..233569278 --- /dev/null +++ b/conformance/rules.csv @@ -0,0 +1,206 @@ +language,rule_id,words +AlphaVariableNameCollision,prDoubleAlpha,ia +CompoundingBreadth,crDecoy,!kaptu +CompoundingBreadth,crJoin,katu;!katumi +CompoundingBreadth,crJoinInsert, +CompoundingBreadth,crNever,!kamtu +CompoundingBreadth,mrTplSuf, +PathologicalDeepOptionalAffixNesting,mrP1,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP10,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP11,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP12,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP2,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP3,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP4,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP5,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP6,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP7,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP8,xxxxxxk;xxxxxxxxxxxxk +PathologicalDeepOptionalAffixNesting,mrP9,xxxxxxk;xxxxxxxxxxxxk +LatinDiacriticProbe,rDim,caféta;kelîta;!añota;!gölta +LatinDiacriticProbe,rPl,años;cafés;göls;kelîs +DisjunctiveRecheckProbe,ruleD,pakza;!pakda;pitda +DisjunctiveRecheckProbe,ruleT,!wakta;wokta +FeatureGatingBreadth,mrAgr,kalka;kalkano +FeatureGatingBreadth,mrEmph,nalnomu;kalmuid +FeatureGatingBreadth,mrLoud,nalno;nalnomu;kalkano +FeatureGatingBreadth,rrPast,kalid;kalmuid +FeatureSystemBreadth,mrSuffixK,ikt +FeatureSystemBreadth,mtDecoy, +FeatureSystemBreadth,mtSwap,it;ikt;!tik +FeatureSystemBreadth,mtSwapOverlap,ikt;!itk;tlk +FeatureSystemBreadth,prAlpha,isk +FeatureSystemBreadth,prDecFeat, +FeatureSystemBreadth,prDecFnc, +FeatureSystemBreadth,prDecNc, +FeatureSystemBreadth,prDecoy, +FeatureSystemBreadth,prHighTrigger, +FeatureSystemBreadth,prRaise,ik;ikt +FreeFluctuatingAllomorphPair,ruleS,kits;!kots +N2-DefaultSymbol,pr1,!bdt +IsActiveBreadth,mrBoundaryPfx,mo+kul +IsActiveBreadth,mrDecoy,!pekul +IsActiveBreadth,mrPfx,takul +IsActiveBreadth,mrRuleOnly,!qokul +IsActiveBreadth,mrSlotOnly,!qekul +IsActiveBreadth,mrTemplateOnly,!qukul +MetathesisComparisonCrash,mtSwap, +MorphotacticAttributeBreadth,aSol, +MorphotacticAttributeBreadth,mrCoA,topsakatana;topsakanabu +MorphotacticAttributeBreadth,mrCoB,topsakatana;topsakanabu +MorphotacticAttributeBreadth,mrCoC,topsakatana +MorphotacticAttributeBreadth,mrCoD,topsakatana;topsakanabu +MorphotacticAttributeBreadth,mrConferExcl,topdo +MorphotacticAttributeBreadth,mrExclReader,!topdori;topri +MorphotacticAttributeBreadth,mrMA,kulbubidu +MorphotacticAttributeBreadth,mrMB,kulbubidu;topsakanabu +MorphotacticAttributeBreadth,mrMReq,kulbubidu +MorphotacticAttributeBreadth,mrNF,!kulpu +MorphotacticAttributeBreadth,mrPO,pogti;pogliti +MorphotacticAttributeBreadth,mrPartial,kulmo;kulgimo;kulmoru +MorphotacticAttributeBreadth,mrPogAffix,pogli;pogliti +MorphotacticAttributeBreadth,mrReal,topdo;topri;kul;kulde;kuldede;kulgi;kulmo;kulru;bak;dom;bakgi;sim;rog;simru;top;topsakatana;kulbubidu;kulgimo;kulmoru;topsakanabu +MorphotacticAttributeBreadth,mrRealDecoy,!kulsi +MorphotacticAttributeBreadth,mrRep0,!kulba +MorphotacticAttributeBreadth,mrRep2,kulde;kuldede +MorphotacticAttributeBreadth,mrUnblockable,kulgi;bakgi;kulgimo +MorphotacticAttributeBreadth,subCoA, +MorphotacticAttributeBreadth,subCoB, +MorphotacticAttributeBreadth,subCoC, +MorphotacticAttributeBreadth,subCoD, +Ranavu,mrDelExclSrc,mentanukam +Ranavu,mrNPfx,menulik;membalo;mentanukam +Ranavu,mrSuf,sanitan;!vokadan +Ranavu,mrSufAlt,vokadi +Ranavu,prNasalAssimAlveolar,menulik;mentanukam +Ranavu,prNasalAssimBilabial,membalo +Ranavu,prObstruentDeletion,menulik;!menanukam +MprGroupOverwriteWithoutRealizational,mrEndC,udofq;!wudofq +MprGroupOverwriteWithoutRealizational,mrThemeA,udof;wudof;udofq +MprGroupOverwriteWithoutRealizational,mrThemeB,wudof +MprOverwriteOrderDependence,mrGatePQ,femopiquvo;femoqupivo +MprOverwriteOrderDependence,mrGateX,!daboxayuzi;daboyuxazi +MprOverwriteOrderDependence,mrSetP,femopiqu;femoqupi;femopiquvo;femoqupivo +MprOverwriteOrderDependence,mrSetQ,femopiqu;femoqupi;femopiquvo;femoqupivo +MprOverwriteOrderDependence,mrSetX,daboxayu;daboyuxa;daboyuxazi +MprOverwriteOrderDependence,mrSetY,daboxayu;daboyuxa;daboyuxazi +ProcessMorphologyInPlaceMutation,mrAblaut,a +RightToLeftAnchorEnvironment,prRtlAnchor,aae;ae;eeae +RightToLeftAnchorEnvironment,prSpread,eeae +IterativeEpenthesisCascadeProbe,prule4, +StemNameRestrictedRootAllomorph,mrPers1,kapom +StemNameRestrictedRootAllomorph,mrPers2,tamur +StrRepIdentityProbe,ruleObj,ndpat;!ndmat;imat;!ipat +StrRepIdentityProbe,rulePfx,pat;mat;mupat;mumat;!mwpat;mwuta;!muuta;ndpat;imat +SubruleMorphosyntacticGating,mrDerive,bat +SubruleMorphosyntacticGating,prGate,pat;bat +TruncateRulesProbe,mruleTruncLead,ag;as;gas +TruncateRulesProbe,mruleTruncOptIns,gbubibi;gas +TruncateRulesProbe,mruleTruncTrail,sa +FusionalRealizationalMorphology,mrAblaut,sang +FusionalRealizationalMorphology,mrCircumfixGeT,gelobt;gelobth +FusionalRealizationalMorphology,mrCompoundConstrained,mitlav;ficlav;!seclav;!genlav;!mitlavlav +FusionalRealizationalMorphology,mrCompoundHN,pannox;!panbenox;corriv +FusionalRealizationalMorphology,mrCompoundNH,lexdom;lexbedom +FusionalRealizationalMorphology,mrEndH,sodh;gofwh +FusionalRealizationalMorphology,mrEndW,katw;!sodw;gofzw;gofwh +FusionalRealizationalMorphology,mrEndZ,gofz;!ygofz;xpedz;!yxpedz;gofzw +FusionalRealizationalMorphology,mrNasalInfix,vinc +FusionalRealizationalMorphology,mrPast2,!ducit +FusionalRealizationalMorphology,mrPers1,mano;mino +FusionalRealizationalMorphology,mrPers2,mans +FusionalRealizationalMorphology,mrPers3,mint +FusionalRealizationalMorphology,mrPl2,ducunt +FusionalRealizationalMorphology,mrPrefixBe1,benox +FusionalRealizationalMorphology,mrPrefixBe2,lexbedom +FusionalRealizationalMorphology,mrSuffixS3,lobh;gelobth +FusionalRealizationalMorphology,mrTense,feres +FusionalRealizationalMorphology,mrThemeX,xped;yxped;xpedz +FusionalRealizationalMorphology,mrThemeY,yxped +FusionalRealizationalMorphology,rrPast,ferid;!feresid +MetathesisPhaseIsolation,mrCircum,keadilan +MetathesisPhaseIsolation,mrComplexMeta,mu+i +MetathesisPhaseIsolation,mrISuffix,pui +MetathesisPhaseIsolation,mrInfixUm,sumulat +MetathesisPhaseIsolation,mrLnk,bahain +MetathesisPhaseIsolation,mrPerf,katibɯd +MetathesisPhaseIsolation,mrRedupCV,tutula +MetathesisPhaseIsolation,mrRedupFull,tulatula +MetathesisPhaseIsolation,mrSimpleMeta,nui;!niu +MetathesisPhaseIsolation,mrTrunc,pur +MetathesisPhaseIsolation,mrUSuffix,mu+i +MetathesisPhaseIsolation,prNonContig,!idil;katibɯd;!katabɯd +PolysyntheticStratalDerivationChain,mrCompoundHN,akutat;!akupitat;!silaaku +PolysyntheticStratalDerivationChain,mrCompoundNH,silanuk;silamanuk +PolysyntheticStratalDerivationChain,mrDeriv,nunaliq;nunaliqvuq +PolysyntheticStratalDerivationChain,mrInfl,nunaliqvuq;!nunavuq;takuvuq +PolysyntheticStratalDerivationChain,mrPrefixMa2,silamanuk +PolysyntheticStratalDerivationChain,mrPrefixPi1,pitat +PolysyntheticStratalDerivationChain,prDelReins,bubu;!buibu +PolysyntheticStratalDerivationChain,prMDC1,buuubuuu;!buiibuii;!uuu +PolysyntheticStratalDerivationChain,prMDC2,mau;!matu;uui;!utui +PolysyntheticStratalDerivationChain,prMultiSeg,kuuukuuu;!kuiikuii +PrefixalDiscontinuousSlotDependency,mrAdvA,gabishiyidkal;hogabishiyidkal +PrefixalDiscontinuousSlotDependency,mrAdvB,hogabishiyidkal +PrefixalDiscontinuousSlotDependency,mrClass,shiyidkal;niyidtan;bishiyidkal;!kal;shiwodkal;gabishiyidkal;hogabishiyidkal +PrefixalDiscontinuousSlotDependency,mrModeIntrans,shiwodkal +PrefixalDiscontinuousSlotDependency,mrModeTrans,shiyidkal;niyidtan;bishiyidkal;gabishiyidkal;hogabishiyidkal +PrefixalDiscontinuousSlotDependency,mrObj,bishiyidkal;!bishiwodkal;gabishiyidkal;hogabishiyidkal +PrefixalDiscontinuousSlotDependency,mrSubj,shiyidkal;niyidtan;bishiyidkal;!yidkal;shiwodkal;gabishiyidkal;hogabishiyidkal +SuffixingEvidentialAdjacencyChain,aKanta,!kantancha +SuffixingEvidentialAdjacencyChain,mrEvidAssum,walaknitan;walaknichiktan;!walakntan +SuffixingEvidentialAdjacencyChain,mrEvidConjectural,sipuncha;takincha;!walaknkicha +SuffixingEvidentialAdjacencyChain,mrEvidDirect,sipuymi;siputukumi;siputukuchikmi;sipulupami;walaknkichikmi +SuffixingEvidentialAdjacencyChain,mrEvidMir,walakniwas;!walaknichikwas +SuffixingEvidentialAdjacencyChain,mrEvidReportative,walaknkisi;walaknkishi +SuffixingEvidentialAdjacencyChain,mrPerson1,tupay;sipuy;walakni;!walaky;walaknichik;sipuymi;takiy;kantay;walaknitan;walaknichiktan;walakniwas +SuffixingEvidentialAdjacencyChain,mrPerson1PlIncl,siputukumi;siputukuchikmi;!siputuku +SuffixingEvidentialAdjacencyChain,mrPerson2,walaknki;walaknkisi;walaknkishi;walaknkichikmi +SuffixingEvidentialAdjacencyChain,mrPerson2Pl,sipulupami;!sipulupachikmi +SuffixingEvidentialAdjacencyChain,mrPerson3,sipun;sipuncha;takincha +SuffixingEvidentialAdjacencyChain,mrPlural,walaknichik;walaknichiktan;siputukuchikmi;walaknkichikmi +SuffixingExtensionSlotOrdering,mrAgr,dabepez;dabez;!kesez;kesepez +SuffixingExtensionSlotOrdering,mrAppl,andikila;andikishila;andikilisha +SuffixingExtensionSlotOrdering,mrCaus,andikisha;andikishila;andikilisha +SuffixingExtensionSlotOrdering,mrEndH,belh;sekwh +SuffixingExtensionSlotOrdering,mrEndW,kibw;!belw;sekzw;sekwh +SuffixingExtensionSlotOrdering,mrEndZ,xkibz;!yxkibz;sekzw +SuffixingExtensionSlotOrdering,mrExtX,xkib;yxkib;xkibz +SuffixingExtensionSlotOrdering,mrExtY,yxkib +SuffixingExtensionSlotOrdering,mrFV,andika;andikisha;andikila;andikishila;andikilisha +SuffixingExtensionSlotOrdering,mrNumPl,dabep;dabepez;kesepez +SuffixingExtensionSlotOrdering,mrPhXSource,lisez +SuffixingExtensionSlotOrdering,mrPhonoDestroy,npael +SuffixingExtensionSlotOrdering,mrRecurSuf,siliz;!siliziz;dalizeh +SuffixingExtensionSlotOrdering,mrRedup,kimbiakimbia +SuffixingExtensionSlotOrdering,mrStemReq,daleh;!daheh;dalizeh +SuffixingExtensionSlotOrdering,mrTense,limape +SuffixingExtensionSlotOrdering,prNasalMutation,mba;!mpa +SuffixingExtensionSlotOrdering,prPhonoExcl,!mbe +SuffixingExtensionSlotOrdering,prPhonoReq,!nbael;nba;!npa +SuffixingExtensionSlotOrdering,rrPast,limaile;!limapeile +SuffixingExtensionSlotOrdering,rrRRealTest,!zimed;!zamed +SuffixingVowelHarmony,mrAlphaSuf,satun;setin;kalutun +SuffixingVowelHarmony,mrPast,semitide;semitideler;kutagida;unitide +SuffixingVowelHarmony,mrPlural,semitideler +SuffixingVowelHarmony,mrPres,semitile;kutagila +SuffixingVowelHarmony,prAlphaHighHarmony,satun;setin;kalut;!kalit;kalutun;!kalitin +SuffixingVowelHarmony,prBacknessHarmony,kutagida;kutagila;!untda +SuffixingVowelHarmony,prEpenthesis,semitide;semitile;semitideler;kutagida;kutagila;unitide;kalut;kalutun +SuffixingVowelHarmony,prGradation,kutagida;kutagila;kalut;kalutun +SuffixingVowelHarmony,prVowelMerge,!duii;duy +SuffixingVowelHarmony,prVowelMultiMerge,!sueeb;sueb +SuffixingVowelHarmony,ruleCollective,!etemik;!esalik +SuffixingVowelHarmony,ruleInfixDemo,guan +TemplaticRootModification,mrAspImpf,hilaku +TemplaticRootModification,mrAspJuss,hulaka +TemplaticRootModification,mrAspPerf,hilaki;hulaki +TemplaticRootModification,mrFormII,sapr;!samm +TemplaticRootModification,mrPassive,qil +TemplaticRootModification,mrPerf1sg,katabit +TemplaticRootModification,mrPerf3sg,kataba +TemplaticRootModification,prEpenthesis,katabit;!katabt +TemplaticRootModification,prGeminate,radda;!rada +TemplaticRootModification,prIterFeedingControl,gigugu;gigugi;!gigigi +TemplaticRootModification,prProthesis,iktub;!ktub +TemplaticRootModification,prSimulFeeding,gigugu;gigugi;!gigigi diff --git a/conformance/schema/conformance-manifest.schema.json b/conformance/schema/conformance-manifest.schema.json new file mode 100644 index 000000000..d883154bc --- /dev/null +++ b/conformance/schema/conformance-manifest.schema.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/sillsdev/machine/conformance/schema/conformance-manifest.schema.json", + "title": "hc-conformance-manifest/v1", + "description": "Provenance and integrity for the conformance fixtures. Not a copy of the ground truth: words.yaml is the canonical authored format and grammar.xml the authoritative grammar; this records paths, formats and hashes only. All paths are canonical repository-relative paths using '/', never relative to this manifest.", + "type": "object", + "additionalProperties": false, + "required": [ + "formatVersion", + "wordsAuthoringFormatVersion", + "grammarFormatVersion", + "dtdPath", + "dtdSha256", + "sourceHash", + "fixtures" + ], + "properties": { + "formatVersion": { "const": "hc-conformance-manifest/v1" }, + "wordsAuthoringFormatVersion": { "const": "hc-conformance-words/v1" }, + "grammarFormatVersion": { "const": "sil-machine-hermit-crab-input-xml/v1" }, + "dtdPath": { "$ref": "#/$defs/path" }, + "dtdSha256": { "$ref": "#/$defs/sha256" }, + "sourceHash": { "$ref": "#/$defs/sha256" }, + "fixtures": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/fixture" } } + }, + "$defs": { + "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, + "path": { "type": "string", "pattern": "^[^\\\\]+$", "minLength": 1 }, + "fixture": { + "type": "object", + "additionalProperties": false, + "required": [ + "fixtureId", + "category", + "displayLanguage", + "grammarPath", + "grammarSha256", + "wordsPath", + "wordsSha256", + "caseCount", + "expectedCrash" + ], + "properties": { + "fixtureId": { "type": "string", "pattern": "^(languages|edge-cases)/[^/]+$" }, + "category": { "enum": ["language", "edge-case"] }, + "displayLanguage": { "type": "string", "minLength": 1 }, + "grammarPath": { "$ref": "#/$defs/path" }, + "grammarSha256": { "$ref": "#/$defs/sha256" }, + "wordsPath": { "$ref": "#/$defs/path" }, + "wordsSha256": { "$ref": "#/$defs/sha256" }, + "caseCount": { "type": "integer", "minimum": 1 }, + "expectedCrash": { "type": "boolean" } + }, + "allOf": [ + { + "description": "A crash fixture declares exactly one case.", + "if": { "properties": { "expectedCrash": { "const": true } }, "required": ["expectedCrash"] }, + "then": { "properties": { "caseCount": { "const": 1 } } } + } + ] + } + } +} diff --git a/conformance/schema/words.schema.json b/conformance/schema/words.schema.json new file mode 100644 index 000000000..04270bcfe --- /dev/null +++ b/conformance/schema/words.schema.json @@ -0,0 +1,101 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/sillsdev/machine/conformance/schema/words.schema.json", + "title": "hc-conformance-words/v1", + "description": "The authoring data model of a fixture's words.yaml. Plain YAML only: no aliases, anchors, merge keys, or custom tags.", + "type": "object", + "additionalProperties": false, + "required": ["language", "words"], + "properties": { + "language": { "type": "string", "minLength": 1 }, + "inspired_by": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "sources": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "requires": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "budget_ms": { "type": "integer", "minimum": 1 }, + "expect_crash": { "type": "boolean" }, + "words": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/word" } + } + }, + "$defs": { + "word": { + "type": "object", + "additionalProperties": false, + "required": ["word", "note"], + "properties": { + "word": { "type": "string", "minLength": 1 }, + "note": { "type": "string", "minLength": 1 }, + "provenance": { "type": "string" }, + "expect_fail": { "type": "boolean" }, + "expect_skip": { "type": "boolean" }, + "blocked_by": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "neutralizes": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "exercises": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, + "parses": { "type": "array", "items": { "$ref": "#/$defs/parse" } }, + "claimed_cells": { "type": "array", "items": { "$ref": "#/$defs/claimedCell" }, "uniqueItems": true } + }, + "allOf": [ + { + "description": "A word cannot be both a rejection and a skip.", + "not": { + "type": "object", + "properties": { + "expect_fail": { "const": true }, + "expect_skip": { "const": true } + }, + "required": ["expect_fail", "expect_skip"] + } + }, + { + "description": "A rejected word has no parses.", + "if": { "type": "object", "properties": { "expect_fail": { "const": true } }, "required": ["expect_fail"] }, + "then": { "properties": { "parses": { "type": "array", "maxItems": 0 } } } + }, + { + "description": "A skipped word has no parses.", + "if": { "type": "object", "properties": { "expect_skip": { "const": true } }, "required": ["expect_skip"] }, + "then": { "properties": { "parses": { "type": "array", "maxItems": 0 } } } + }, + { + "description": "blocked_by describes a rejection. neutralizes does not: a word can observe a deactivation by analysing differently rather than by failing, so it is admitted on any outcome.", + "if": { "type": "object", "required": ["blocked_by"] }, + "then": { "properties": { "expect_fail": { "const": true } }, "required": ["expect_fail"] } + } + ] + }, + "parse": { + "type": "object", + "additionalProperties": false, + "required": ["signature", "rules"], + "properties": { + "signature": { "type": "string", "minLength": 1 }, + "gloss": { "type": "string" }, + "guess": { "type": "boolean" }, + "rules": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "exercises": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } + } + }, + "claimedCell": { + "description": "A word's declaration that it is meant to witness one cell of conformance/dataflow-obligations.tsv. Checked, never trusted: DataflowClaimGate fails the build if 'cell' does not exist in that ledger or its status is not Satisfied. 'severing'/'before'/'after'/'proof' are an optional inline review bundle -- the literal machine evidence (before/after parse outcome) this claim was reviewed against, present only all four together, since a partial bundle cannot be recomputed. DataflowClaimGate re-severs the writer and reader (derived from the ledger row, not from this text) and treats any mismatch against 'before'/'after' as a stale review, reported but never a build failure by itself. 'distinct_from' independently names the plain control word -- one that shows the claimed cell's gated/mutated condition is not vacuous, i.e. that the rule can fire at all -- checked for existence and outcome difference regardless of whether a review bundle is present.", + "type": "object", + "additionalProperties": false, + "required": ["cell"], + "properties": { + "cell": { "type": "string", "minLength": 1 }, + "severing": { "type": "string", "minLength": 1 }, + "before": { "type": "string", "minLength": 1 }, + "after": { "type": "string", "minLength": 1 }, + "distinct_from": { "type": "string", "minLength": 1 }, + "proof": { "type": "string", "minLength": 1 } + }, + "dependentRequired": { + "severing": ["before", "after", "proof"], + "before": ["severing", "after", "proof"], + "after": ["severing", "before", "proof"], + "proof": ["severing", "before", "after"] + } + } + } +} diff --git a/conformance/semantic-catalog.yaml b/conformance/semantic-catalog.yaml new file mode 100644 index 000000000..c87febfe3 --- /dev/null +++ b/conformance/semantic-catalog.yaml @@ -0,0 +1,2598 @@ +# HermitCrab semantic catalog +# +# GENERATED by hc-conformance --write-semantic-catalog. Every one of the 1059 surfaces the +# inventory generates is named by exactly one surfaceMappings row, so a surface added to the DTD +# is unmapped and the audit fails until someone classifies it. That fail-closed property is the +# whole point; regenerating is a deliberate act, not something a build does for you. +# +# 108 features group the grammar-observable surfaces by DTD element and are +# `unclassified`: the bootstrap records that no human has judged their phase effects, rather +# than fabricating effects to satisfy the audit. Promoting one to `semantic` means supplying all +# three phase effects, which the audit then requires. +# +# 7 features classify the rest by surface kind. This is where the surfaces a grammar +# author cannot write are accounted for by name instead of vanishing into a filter. +# +# 1059 mapping rows. Wildcards are rejected, not expanded. +profile: sil.machine.hc-semantic-catalog/v1 +auditedSourceScopes: [] +features: + - id: grammar/AffixTemplate + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AffixTemplate. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AffixTemplates + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AffixTemplates. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Allomorph + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Allomorph. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AllomorphCoOccurrenceRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AllomorphCoOccurrenceRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AllomorphCoOccurrenceRules + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AllomorphCoOccurrenceRules. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Allomorphs + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Allomorphs. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AlphaVariable + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AlphaVariable. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AlphaVariables + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AlphaVariables. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AssignedFootFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AssignedFootFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/AssignedHeadFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element AssignedHeadFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/BoundaryDefinition + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element BoundaryDefinition. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/BoundaryDefinitions + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element BoundaryDefinitions. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/BoundaryMarker + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element BoundaryMarker. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/CharacterDefinitionTable + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element CharacterDefinitionTable. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/ComplexFeature + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element ComplexFeature. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/CompoundingRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element CompoundingRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/CompoundingSubrule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element CompoundingSubrule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/CompoundingSubrules + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element CompoundingSubrules. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/CopyFromInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element CopyFromInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Environment + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Environment. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/ExcludedEnvironments + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element ExcludedEnvironments. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Families + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Families. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Family + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Family. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/FeatureNaturalClass + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element FeatureNaturalClass. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/FeatureValue + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element FeatureValue. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/FootFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element FootFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Gloss + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Gloss. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/HeadFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element HeadFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/HeadMorphologicalInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element HeadMorphologicalInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/HeadRequiredFootFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element HeadRequiredFootFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/HeadRequiredHeadFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element HeadRequiredHeadFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/HermitCrabInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element HermitCrabInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/InsertSegments + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element InsertSegments. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/InsertSimpleContext + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element InsertSimpleContext. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Language + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Language. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/LeftEnvironment + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element LeftEnvironment. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/LexicalEntries + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element LexicalEntries. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/LexicalEntry + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element LexicalEntry. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MetathesisRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MetathesisRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/ModifyFromInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element ModifyFromInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphemeCoOccurrenceRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphemeCoOccurrenceRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphemeCoOccurrenceRules + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphemeCoOccurrenceRules. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphemeId + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphemeId. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalOutput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalOutput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalPhonologicalRuleFeature + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalPhonologicalRuleFeature. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalPhonologicalRuleFeatureGroup + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalPhonologicalRuleFeatureGroup. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalPhonologicalRuleFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalPhonologicalRuleFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalRuleDefinitions + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalRuleDefinitions. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalSubrule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalSubrule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/MorphologicalSubrules + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element MorphologicalSubrules. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Name + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Name. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/NaturalClasses + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element NaturalClasses. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/NextWord + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element NextWord. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/NonHeadMorphologicalInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element NonHeadMorphologicalInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/NonHeadRequiredFootFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element NonHeadRequiredFootFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/NonHeadRequiredHeadFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element NonHeadRequiredHeadFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Null + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Null. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/OptionalSegmentSequence + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element OptionalSegmentSequence. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/OutputFootFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element OutputFootFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/OutputHeadFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element OutputHeadFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/OutputSubcategorizationOverride + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element OutputSubcategorizationOverride. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/OutputSubcategorizationOverrides + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element OutputSubcategorizationOverrides. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PartOfSpeech + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PartOfSpeech. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PartsOfSpeech + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PartsOfSpeech. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhoneticInput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhoneticInput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhoneticOutput + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhoneticOutput. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhoneticSequence + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhoneticSequence. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhoneticShape + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhoneticShape. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhoneticTemplate + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhoneticTemplate. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhonologicalFeatureSystem + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhonologicalFeatureSystem. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhonologicalRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhonologicalRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhonologicalRuleDefinitions + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhonologicalRuleDefinitions. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhonologicalSubrule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhonologicalSubrule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PhonologicalSubrules + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PhonologicalSubrules. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/PreviousWord + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element PreviousWord. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Properties + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Properties. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Property + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Property. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/RealizationalFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element RealizationalFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/RealizationalRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element RealizationalRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Region + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Region. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Regions + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Regions. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Representation + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Representation. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Representations + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Representations. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/RequiredEnvironments + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element RequiredEnvironments. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/RequiredFootFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element RequiredFootFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/RequiredHeadFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element RequiredHeadFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/RightEnvironment + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element RightEnvironment. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Segment + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Segment. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SegmentDefinition + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SegmentDefinition. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SegmentDefinitions + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SegmentDefinitions. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SegmentNaturalClass + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SegmentNaturalClass. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Segments + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Segments. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SimpleContext + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SimpleContext. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Slot + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Slot. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/StemName + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element StemName. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/StemNames + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element StemNames. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Strata + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Strata. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Stratum + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Stratum. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/StructuralDescription + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element StructuralDescription. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Symbol + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Symbol. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SymbolicFeature + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SymbolicFeature. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/Symbols + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element Symbols. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SyntacticRule + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SyntacticRule. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/SyntacticRules + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element SyntacticRules. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/VariableFeature + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element VariableFeature. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: grammar/VariableFeatures + disposition: unclassified + reason: "Grammar-observable surfaces of DTD element VariableFeatures. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd", "conformance/semantic-coverage-baseline.txt"] + - id: schema/attribute + disposition: loader + reason: "An attribute declaration itself; its enumerated values are the unit a grammar can choose, and those are classified separately." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] + - id: schema/attribute-default + disposition: metadata + reason: "The declared default of an attribute. Which value is in effect is observable; the declaration of the default is not." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] + - id: schema/attribute-type + disposition: metadata + reason: "The declared XML type of an attribute. Schema bookkeeping with no parse behaviour of its own." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] + - id: schema/content-group + disposition: loader + reason: "A content-model group. Constrains what a document may contain; the loader enforces it before any parse behaviour exists." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] + - id: schema/default + disposition: metadata + reason: "A DTD default declaration. Schema bookkeeping." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] + - id: schema/placement + disposition: loader + reason: "Child occurrence and cardinality within a content model. Genuinely semantic as occurrence multiplicity, but not writable as a value in a grammar, so it is out of reach of the coverage ledger." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] + - id: schema/special-content + disposition: metadata + reason: "An EMPTY or ANY content declaration. Schema bookkeeping." + citations: ["src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"] +surfaceMappings: + - surface: "dtd:attribute-default/AffixTemplate/final/default/true" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AffixTemplate/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AffixTemplate/requiredPartsOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AffixTemplate/requiredSubcategorizedRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Allomorph/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Allomorph/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Allomorph/isBound/default/false" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Allomorph/stemName/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AllomorphCoOccurrenceRule/adjacency/default/anywhere" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AllomorphCoOccurrenceRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AllomorphCoOccurrenceRule/otherAllomorphs/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AllomorphCoOccurrenceRule/primaryAllomorph/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AllomorphCoOccurrenceRule/type/default/exclude" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AlphaVariable/polarity/default/plus" + feature: schema/attribute-default + - surface: "dtd:attribute-default/AlphaVariable/variableFeature/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/BoundaryDefinition/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/BoundaryDefinition/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/BoundaryMarker/boundary/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/BoundaryMarker/id/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CharacterDefinitionTable/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CharacterDefinitionTable/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/ComplexFeature/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/ComplexFeature/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/blockable/default/true" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/headPartsOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/headProdRestrictionsMprFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/headSubcategorizedRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/multipleApplication/default/1" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/nonHeadPartsOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/nonHeadProdRestrictionsMprFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/nonHeadSubcategorizedRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/outputObligatoryFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/outputPartOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/outputProdRestrictionsMprFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingRule/outputSubcategorization/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CompoundingSubrule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/CopyFromInput/index/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Family/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Family/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/FeatureNaturalClass/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/FeatureNaturalClass/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/FeatureValue/feature/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/FeatureValue/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/FeatureValue/symbolValues/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/HeadMorphologicalInput/excludedMPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/HeadMorphologicalInput/requiredMPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/InsertSegments/characterDefinitionTable/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Language/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/family/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/morphologicalRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/obligatoryFootFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/obligatoryHeadFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/partOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/partial/default/false" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/ruleFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/LexicalEntry/subcategorizations/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MetathesisRule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MetathesisRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MetathesisRule/leftSwitch/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MetathesisRule/multipleApplicationOrder/default/leftToRightIterative" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MetathesisRule/rightSwitch/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/ModifyFromInput/index/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphemeCoOccurrenceRule/adjacency/default/anywhere" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphemeCoOccurrenceRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphemeCoOccurrenceRule/otherMorphemes/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphemeCoOccurrenceRule/primaryMorpheme/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphemeCoOccurrenceRule/type/default/exclude" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalInput/excludedMPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalInput/requiredMPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalOutput/MPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalOutput/redupMorphType/default/implicit" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalPhonologicalRuleFeature/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalPhonologicalRuleFeature/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalPhonologicalRuleFeatureGroup/features/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalPhonologicalRuleFeatureGroup/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalPhonologicalRuleFeatureGroup/matchType/default/any" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalPhonologicalRuleFeatureGroup/outputType/default/overwrite" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/blockable/default/true" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/multipleApplication/default/1" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/outputObligatoryFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/outputPartOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/outputSubcategorization/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/partial/default/false" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/requiredPartsOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/requiredStemName/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalRule/requiredSubcategorizedRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalSubrule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/MorphologicalSubrule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/NextWord/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Null/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/OptionalSegmentSequence/id/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/OptionalSegmentSequence/max/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/OptionalSegmentSequence/min/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/OutputSubcategorizationOverride/inputSubcategorization/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/OutputSubcategorizationOverride/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/OutputSubcategorizationOverride/outputSubcategorization/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PartOfSpeech/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhoneticSequence/id/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhoneticTemplate/finalBoundaryCondition/default/false" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhoneticTemplate/initialBoundaryCondition/default/false" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalFeatureSystem/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalRule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalRule/multipleApplicationOrder/default/leftToRightIterative" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalSubrule/excludedMPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalSubrule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalSubrule/requiredMPRFeatures/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PhonologicalSubrule/requiredPartsOfSpeech/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/PreviousWord/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Property/name/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/RealizationalRule/blockable/default/true" + feature: schema/attribute-default + - surface: "dtd:attribute-default/RealizationalRule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/RealizationalRule/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Segment/id/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Segment/segment/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SegmentDefinition/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SegmentDefinition/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SegmentNaturalClass/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SegmentNaturalClass/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Segments/characterDefinitionTable/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Segments/id/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SimpleContext/id/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SimpleContext/naturalClass/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Slot/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Slot/morphologicalRules/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Slot/optional/default/false" + feature: schema/attribute-default + - surface: "dtd:attribute-default/StemName/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/StemName/partsOfSpeech/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/characterDefinitionTable/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/cyclicity/default/noncyclic" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/morphologicalRuleOrder/default/linear" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/morphologicalRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/phonologicalRuleOrder/default/linear" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Stratum/phonologicalRules/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/Symbol/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SymbolicFeature/defaultSymbol/implied" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SymbolicFeature/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SymbolicFeature/isActive/default/yes" + feature: schema/attribute-default + - surface: "dtd:attribute-default/SyntacticRule/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/VariableFeature/id/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/VariableFeature/name/required" + feature: schema/attribute-default + - surface: "dtd:attribute-default/VariableFeature/phonologicalFeature/required" + feature: schema/attribute-default + - surface: "dtd:attribute-type/AffixTemplate/final/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AffixTemplate/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AffixTemplate/requiredPartsOfSpeech/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AffixTemplate/requiredSubcategorizedRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Allomorph/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Allomorph/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Allomorph/isBound/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Allomorph/stemName/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AllomorphCoOccurrenceRule/adjacency/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AllomorphCoOccurrenceRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AllomorphCoOccurrenceRule/otherAllomorphs/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AllomorphCoOccurrenceRule/primaryAllomorph/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AllomorphCoOccurrenceRule/type/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AlphaVariable/polarity/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/AlphaVariable/variableFeature/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/BoundaryDefinition/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/BoundaryDefinition/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/BoundaryMarker/boundary/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/BoundaryMarker/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CharacterDefinitionTable/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CharacterDefinitionTable/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/ComplexFeature/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/ComplexFeature/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/blockable/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/headPartsOfSpeech/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/headProdRestrictionsMprFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/headSubcategorizedRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/multipleApplication/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/nonHeadPartsOfSpeech/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/nonHeadProdRestrictionsMprFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/nonHeadSubcategorizedRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/outputObligatoryFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/outputPartOfSpeech/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/outputProdRestrictionsMprFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingRule/outputSubcategorization/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CompoundingSubrule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/CopyFromInput/index/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Family/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Family/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/FeatureNaturalClass/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/FeatureNaturalClass/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/FeatureValue/feature/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/FeatureValue/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/FeatureValue/symbolValues/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/HeadMorphologicalInput/excludedMPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/HeadMorphologicalInput/requiredMPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/InsertSegments/characterDefinitionTable/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Language/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/family/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/morphologicalRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/obligatoryFootFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/obligatoryHeadFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/partOfSpeech/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/partial/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/ruleFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/LexicalEntry/subcategorizations/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MetathesisRule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MetathesisRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MetathesisRule/leftSwitch/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MetathesisRule/multipleApplicationOrder/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MetathesisRule/rightSwitch/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/ModifyFromInput/index/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphemeCoOccurrenceRule/adjacency/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphemeCoOccurrenceRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphemeCoOccurrenceRule/otherMorphemes/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphemeCoOccurrenceRule/primaryMorpheme/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphemeCoOccurrenceRule/type/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalInput/excludedMPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalInput/requiredMPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalOutput/MPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalOutput/redupMorphType/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalPhonologicalRuleFeature/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalPhonologicalRuleFeature/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalPhonologicalRuleFeatureGroup/features/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalPhonologicalRuleFeatureGroup/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalPhonologicalRuleFeatureGroup/matchType/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalPhonologicalRuleFeatureGroup/outputType/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/blockable/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/multipleApplication/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/outputObligatoryFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/outputPartOfSpeech/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/outputSubcategorization/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/partial/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/requiredPartsOfSpeech/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/requiredStemName/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalRule/requiredSubcategorizedRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalSubrule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/MorphologicalSubrule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/NextWord/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Null/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/OptionalSegmentSequence/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/OptionalSegmentSequence/max/CDATA" + feature: schema/attribute-type + - surface: "dtd:attribute-type/OptionalSegmentSequence/min/CDATA" + feature: schema/attribute-type + - surface: "dtd:attribute-type/OutputSubcategorizationOverride/inputSubcategorization/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/OutputSubcategorizationOverride/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/OutputSubcategorizationOverride/outputSubcategorization/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PartOfSpeech/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhoneticSequence/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhoneticTemplate/finalBoundaryCondition/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhoneticTemplate/initialBoundaryCondition/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalFeatureSystem/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalRule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalRule/multipleApplicationOrder/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalSubrule/excludedMPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalSubrule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalSubrule/requiredMPRFeatures/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PhonologicalSubrule/requiredPartsOfSpeech/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/PreviousWord/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Property/name/CDATA" + feature: schema/attribute-type + - surface: "dtd:attribute-type/RealizationalRule/blockable/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/RealizationalRule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/RealizationalRule/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Segment/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Segment/segment/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SegmentDefinition/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SegmentDefinition/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SegmentNaturalClass/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SegmentNaturalClass/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Segments/characterDefinitionTable/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Segments/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SimpleContext/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SimpleContext/naturalClass/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Slot/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Slot/morphologicalRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Slot/optional/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/StemName/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/StemName/partsOfSpeech/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/characterDefinitionTable/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/cyclicity/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/morphologicalRuleOrder/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/morphologicalRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/phonologicalRuleOrder/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Stratum/phonologicalRules/IDREFS" + feature: schema/attribute-type + - surface: "dtd:attribute-type/Symbol/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SymbolicFeature/defaultSymbol/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SymbolicFeature/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SymbolicFeature/isActive/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/SyntacticRule/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/VariableFeature/id/ID" + feature: schema/attribute-type + - surface: "dtd:attribute-type/VariableFeature/name/enumeration" + feature: schema/attribute-type + - surface: "dtd:attribute-type/VariableFeature/phonologicalFeature/IDREF" + feature: schema/attribute-type + - surface: "dtd:attribute/AffixTemplate/final" + feature: schema/attribute + - surface: "dtd:attribute/AffixTemplate/isActive" + feature: schema/attribute + - surface: "dtd:attribute/AffixTemplate/requiredPartsOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/AffixTemplate/requiredSubcategorizedRules" + feature: schema/attribute + - surface: "dtd:attribute/Allomorph/id" + feature: schema/attribute + - surface: "dtd:attribute/Allomorph/isActive" + feature: schema/attribute + - surface: "dtd:attribute/Allomorph/isBound" + feature: schema/attribute + - surface: "dtd:attribute/Allomorph/stemName" + feature: schema/attribute + - surface: "dtd:attribute/AllomorphCoOccurrenceRule/adjacency" + feature: schema/attribute + - surface: "dtd:attribute/AllomorphCoOccurrenceRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/AllomorphCoOccurrenceRule/otherAllomorphs" + feature: schema/attribute + - surface: "dtd:attribute/AllomorphCoOccurrenceRule/primaryAllomorph" + feature: schema/attribute + - surface: "dtd:attribute/AllomorphCoOccurrenceRule/type" + feature: schema/attribute + - surface: "dtd:attribute/AlphaVariable/polarity" + feature: schema/attribute + - surface: "dtd:attribute/AlphaVariable/variableFeature" + feature: schema/attribute + - surface: "dtd:attribute/BoundaryDefinition/id" + feature: schema/attribute + - surface: "dtd:attribute/BoundaryDefinition/isActive" + feature: schema/attribute + - surface: "dtd:attribute/BoundaryMarker/boundary" + feature: schema/attribute + - surface: "dtd:attribute/BoundaryMarker/id" + feature: schema/attribute + - surface: "dtd:attribute/CharacterDefinitionTable/id" + feature: schema/attribute + - surface: "dtd:attribute/CharacterDefinitionTable/isActive" + feature: schema/attribute + - surface: "dtd:attribute/ComplexFeature/id" + feature: schema/attribute + - surface: "dtd:attribute/ComplexFeature/isActive" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/blockable" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/headPartsOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/headProdRestrictionsMprFeatures" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/headSubcategorizedRules" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/id" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/multipleApplication" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/nonHeadPartsOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/nonHeadProdRestrictionsMprFeatures" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/nonHeadSubcategorizedRules" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/outputObligatoryFeatures" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/outputPartOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/outputProdRestrictionsMprFeatures" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingRule/outputSubcategorization" + feature: schema/attribute + - surface: "dtd:attribute/CompoundingSubrule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/CopyFromInput/index" + feature: schema/attribute + - surface: "dtd:attribute/Family/id" + feature: schema/attribute + - surface: "dtd:attribute/Family/isActive" + feature: schema/attribute + - surface: "dtd:attribute/FeatureNaturalClass/id" + feature: schema/attribute + - surface: "dtd:attribute/FeatureNaturalClass/isActive" + feature: schema/attribute + - surface: "dtd:attribute/FeatureValue/feature" + feature: schema/attribute + - surface: "dtd:attribute/FeatureValue/isActive" + feature: schema/attribute + - surface: "dtd:attribute/FeatureValue/symbolValues" + feature: schema/attribute + - surface: "dtd:attribute/HeadMorphologicalInput/excludedMPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/HeadMorphologicalInput/requiredMPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/InsertSegments/characterDefinitionTable" + feature: schema/attribute + - surface: "dtd:attribute/Language/isActive" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/family" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/id" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/isActive" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/morphologicalRules" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/obligatoryFootFeatures" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/obligatoryHeadFeatures" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/partOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/partial" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/ruleFeatures" + feature: schema/attribute + - surface: "dtd:attribute/LexicalEntry/subcategorizations" + feature: schema/attribute + - surface: "dtd:attribute/MetathesisRule/id" + feature: schema/attribute + - surface: "dtd:attribute/MetathesisRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/MetathesisRule/leftSwitch" + feature: schema/attribute + - surface: "dtd:attribute/MetathesisRule/multipleApplicationOrder" + feature: schema/attribute + - surface: "dtd:attribute/MetathesisRule/rightSwitch" + feature: schema/attribute + - surface: "dtd:attribute/ModifyFromInput/index" + feature: schema/attribute + - surface: "dtd:attribute/MorphemeCoOccurrenceRule/adjacency" + feature: schema/attribute + - surface: "dtd:attribute/MorphemeCoOccurrenceRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/MorphemeCoOccurrenceRule/otherMorphemes" + feature: schema/attribute + - surface: "dtd:attribute/MorphemeCoOccurrenceRule/primaryMorpheme" + feature: schema/attribute + - surface: "dtd:attribute/MorphemeCoOccurrenceRule/type" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalInput/excludedMPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalInput/requiredMPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalOutput/MPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalOutput/redupMorphType" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalPhonologicalRuleFeature/id" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalPhonologicalRuleFeature/isActive" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalPhonologicalRuleFeatureGroup/features" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalPhonologicalRuleFeatureGroup/isActive" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalPhonologicalRuleFeatureGroup/matchType" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalPhonologicalRuleFeatureGroup/outputType" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/blockable" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/id" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/multipleApplication" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/outputObligatoryFeatures" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/outputPartOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/outputSubcategorization" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/partial" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/requiredPartsOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/requiredStemName" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalRule/requiredSubcategorizedRules" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalSubrule/id" + feature: schema/attribute + - surface: "dtd:attribute/MorphologicalSubrule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/NextWord/id" + feature: schema/attribute + - surface: "dtd:attribute/Null/id" + feature: schema/attribute + - surface: "dtd:attribute/OptionalSegmentSequence/id" + feature: schema/attribute + - surface: "dtd:attribute/OptionalSegmentSequence/max" + feature: schema/attribute + - surface: "dtd:attribute/OptionalSegmentSequence/min" + feature: schema/attribute + - surface: "dtd:attribute/OutputSubcategorizationOverride/inputSubcategorization" + feature: schema/attribute + - surface: "dtd:attribute/OutputSubcategorizationOverride/isActive" + feature: schema/attribute + - surface: "dtd:attribute/OutputSubcategorizationOverride/outputSubcategorization" + feature: schema/attribute + - surface: "dtd:attribute/PartOfSpeech/id" + feature: schema/attribute + - surface: "dtd:attribute/PhoneticSequence/id" + feature: schema/attribute + - surface: "dtd:attribute/PhoneticTemplate/finalBoundaryCondition" + feature: schema/attribute + - surface: "dtd:attribute/PhoneticTemplate/initialBoundaryCondition" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalFeatureSystem/isActive" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalRule/id" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalRule/multipleApplicationOrder" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalSubrule/excludedMPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalSubrule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalSubrule/requiredMPRFeatures" + feature: schema/attribute + - surface: "dtd:attribute/PhonologicalSubrule/requiredPartsOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/PreviousWord/id" + feature: schema/attribute + - surface: "dtd:attribute/Property/name" + feature: schema/attribute + - surface: "dtd:attribute/RealizationalRule/blockable" + feature: schema/attribute + - surface: "dtd:attribute/RealizationalRule/id" + feature: schema/attribute + - surface: "dtd:attribute/RealizationalRule/isActive" + feature: schema/attribute + - surface: "dtd:attribute/Segment/id" + feature: schema/attribute + - surface: "dtd:attribute/Segment/segment" + feature: schema/attribute + - surface: "dtd:attribute/SegmentDefinition/id" + feature: schema/attribute + - surface: "dtd:attribute/SegmentDefinition/isActive" + feature: schema/attribute + - surface: "dtd:attribute/SegmentNaturalClass/id" + feature: schema/attribute + - surface: "dtd:attribute/SegmentNaturalClass/isActive" + feature: schema/attribute + - surface: "dtd:attribute/Segments/characterDefinitionTable" + feature: schema/attribute + - surface: "dtd:attribute/Segments/id" + feature: schema/attribute + - surface: "dtd:attribute/SimpleContext/id" + feature: schema/attribute + - surface: "dtd:attribute/SimpleContext/naturalClass" + feature: schema/attribute + - surface: "dtd:attribute/Slot/isActive" + feature: schema/attribute + - surface: "dtd:attribute/Slot/morphologicalRules" + feature: schema/attribute + - surface: "dtd:attribute/Slot/optional" + feature: schema/attribute + - surface: "dtd:attribute/StemName/id" + feature: schema/attribute + - surface: "dtd:attribute/StemName/partsOfSpeech" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/characterDefinitionTable" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/cyclicity" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/isActive" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/morphologicalRuleOrder" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/morphologicalRules" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/phonologicalRuleOrder" + feature: schema/attribute + - surface: "dtd:attribute/Stratum/phonologicalRules" + feature: schema/attribute + - surface: "dtd:attribute/Symbol/id" + feature: schema/attribute + - surface: "dtd:attribute/SymbolicFeature/defaultSymbol" + feature: schema/attribute + - surface: "dtd:attribute/SymbolicFeature/id" + feature: schema/attribute + - surface: "dtd:attribute/SymbolicFeature/isActive" + feature: schema/attribute + - surface: "dtd:attribute/SyntacticRule/id" + feature: schema/attribute + - surface: "dtd:attribute/VariableFeature/id" + feature: schema/attribute + - surface: "dtd:attribute/VariableFeature/name" + feature: schema/attribute + - surface: "dtd:attribute/VariableFeature/phonologicalFeature" + feature: schema/attribute + - surface: "dtd:content/AffixTemplate/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/AffixTemplates/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Allomorph/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/AllomorphCoOccurrenceRule/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/AllomorphCoOccurrenceRules/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Allomorphs/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/AlphaVariable/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/AlphaVariables/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/AssignedFootFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/AssignedHeadFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/BoundaryDefinition/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/BoundaryDefinitions/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/BoundaryMarker/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/CharacterDefinitionTable/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/ComplexFeature/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/CompoundingRule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/CompoundingSubrule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/CompoundingSubrules/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/CopyFromInput/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/Environment/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/ExcludedEnvironments/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Families/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Family/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/FeatureNaturalClass/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/FeatureValue/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/FootFeatures/r.0.choice@zero-or-more" + feature: schema/content-group + - surface: "dtd:content/FootFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Gloss/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/HeadFeatures/r.0.choice@zero-or-more" + feature: schema/content-group + - surface: "dtd:content/HeadFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/HeadMorphologicalInput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/HeadRequiredFootFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/HeadRequiredHeadFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/HermitCrabInput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/InsertSegments/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/InsertSimpleContext/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Language/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/LeftEnvironment/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/LexicalEntries/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/LexicalEntry/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MetathesisRule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/ModifyFromInput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphemeCoOccurrenceRule/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/MorphemeCoOccurrenceRules/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphemeId/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/MorphologicalInput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphologicalOutput/r.choice@zero-or-more" + feature: schema/content-group + - surface: "dtd:content/MorphologicalPhonologicalRuleFeature/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/MorphologicalPhonologicalRuleFeatureGroup/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphologicalPhonologicalRuleFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphologicalRule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphologicalRuleDefinitions/r.choice@zero-or-more" + feature: schema/content-group + - surface: "dtd:content/MorphologicalSubrule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/MorphologicalSubrules/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Name/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/NaturalClasses/r.choice@one-or-more" + feature: schema/content-group + - surface: "dtd:content/NextWord/r.choice@one" + feature: schema/content-group + - surface: "dtd:content/NonHeadMorphologicalInput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/NonHeadRequiredFootFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/NonHeadRequiredHeadFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Null/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/OptionalSegmentSequence/r.choice@one-or-more" + feature: schema/content-group + - surface: "dtd:content/OutputFootFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/OutputHeadFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/OutputSubcategorizationOverride/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/OutputSubcategorizationOverrides/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PartOfSpeech/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PartsOfSpeech/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhoneticInput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhoneticOutput/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhoneticSequence/r.choice@zero-or-more" + feature: schema/content-group + - surface: "dtd:content/PhoneticShape/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/PhoneticTemplate/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhonologicalFeatureSystem/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhonologicalRule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhonologicalRuleDefinitions/r.choice@zero-or-more" + feature: schema/content-group + - surface: "dtd:content/PhonologicalSubrule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PhonologicalSubrules/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/PreviousWord/r.choice@one" + feature: schema/content-group + - surface: "dtd:content/Properties/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Property/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/RealizationalFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/RealizationalRule/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Region/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Regions/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Representation/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/Representations/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/RequiredEnvironments/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/RequiredFootFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/RequiredHeadFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/RightEnvironment/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Segment/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/SegmentDefinition/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/SegmentDefinitions/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/SegmentNaturalClass/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Segments/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/SimpleContext/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Slot/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/StemName/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/StemNames/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Strata/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Stratum/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/StructuralDescription/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Symbol/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/SymbolicFeature/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/Symbols/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/SyntacticRule/r.pcdata@one" + feature: schema/special-content + - surface: "dtd:content/SyntacticRules/r.sequence@one" + feature: schema/content-group + - surface: "dtd:content/VariableFeature/r.empty@one" + feature: schema/special-content + - surface: "dtd:content/VariableFeatures/r.sequence@one" + feature: schema/content-group + - surface: "dtd:default/AffixTemplate/final/true" + feature: schema/default + - surface: "dtd:default/AffixTemplate/isActive/yes" + feature: schema/default + - surface: "dtd:default/Allomorph/isActive/yes" + feature: schema/default + - surface: "dtd:default/Allomorph/isBound/false" + feature: schema/default + - surface: "dtd:default/AllomorphCoOccurrenceRule/adjacency/anywhere" + feature: schema/default + - surface: "dtd:default/AllomorphCoOccurrenceRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/AllomorphCoOccurrenceRule/type/exclude" + feature: schema/default + - surface: "dtd:default/AlphaVariable/polarity/plus" + feature: schema/default + - surface: "dtd:default/BoundaryDefinition/isActive/yes" + feature: schema/default + - surface: "dtd:default/CharacterDefinitionTable/isActive/yes" + feature: schema/default + - surface: "dtd:default/ComplexFeature/isActive/yes" + feature: schema/default + - surface: "dtd:default/CompoundingRule/blockable/true" + feature: schema/default + - surface: "dtd:default/CompoundingRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/CompoundingRule/multipleApplication/1" + feature: schema/default + - surface: "dtd:default/CompoundingSubrule/isActive/yes" + feature: schema/default + - surface: "dtd:default/Family/isActive/yes" + feature: schema/default + - surface: "dtd:default/FeatureNaturalClass/isActive/yes" + feature: schema/default + - surface: "dtd:default/FeatureValue/isActive/yes" + feature: schema/default + - surface: "dtd:default/Language/isActive/yes" + feature: schema/default + - surface: "dtd:default/LexicalEntry/isActive/yes" + feature: schema/default + - surface: "dtd:default/LexicalEntry/partial/false" + feature: schema/default + - surface: "dtd:default/MetathesisRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/MetathesisRule/multipleApplicationOrder/leftToRightIterative" + feature: schema/default + - surface: "dtd:default/MorphemeCoOccurrenceRule/adjacency/anywhere" + feature: schema/default + - surface: "dtd:default/MorphemeCoOccurrenceRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/MorphemeCoOccurrenceRule/type/exclude" + feature: schema/default + - surface: "dtd:default/MorphologicalOutput/redupMorphType/implicit" + feature: schema/default + - surface: "dtd:default/MorphologicalPhonologicalRuleFeature/isActive/yes" + feature: schema/default + - surface: "dtd:default/MorphologicalPhonologicalRuleFeatureGroup/isActive/yes" + feature: schema/default + - surface: "dtd:default/MorphologicalPhonologicalRuleFeatureGroup/matchType/any" + feature: schema/default + - surface: "dtd:default/MorphologicalPhonologicalRuleFeatureGroup/outputType/overwrite" + feature: schema/default + - surface: "dtd:default/MorphologicalRule/blockable/true" + feature: schema/default + - surface: "dtd:default/MorphologicalRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/MorphologicalRule/multipleApplication/1" + feature: schema/default + - surface: "dtd:default/MorphologicalRule/partial/false" + feature: schema/default + - surface: "dtd:default/MorphologicalSubrule/isActive/yes" + feature: schema/default + - surface: "dtd:default/OutputSubcategorizationOverride/isActive/yes" + feature: schema/default + - surface: "dtd:default/PhoneticTemplate/finalBoundaryCondition/false" + feature: schema/default + - surface: "dtd:default/PhoneticTemplate/initialBoundaryCondition/false" + feature: schema/default + - surface: "dtd:default/PhonologicalFeatureSystem/isActive/yes" + feature: schema/default + - surface: "dtd:default/PhonologicalRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/PhonologicalRule/multipleApplicationOrder/leftToRightIterative" + feature: schema/default + - surface: "dtd:default/PhonologicalSubrule/isActive/yes" + feature: schema/default + - surface: "dtd:default/RealizationalRule/blockable/true" + feature: schema/default + - surface: "dtd:default/RealizationalRule/isActive/yes" + feature: schema/default + - surface: "dtd:default/SegmentDefinition/isActive/yes" + feature: schema/default + - surface: "dtd:default/SegmentNaturalClass/isActive/yes" + feature: schema/default + - surface: "dtd:default/Slot/isActive/yes" + feature: schema/default + - surface: "dtd:default/Slot/optional/false" + feature: schema/default + - surface: "dtd:default/Stratum/cyclicity/noncyclic" + feature: schema/default + - surface: "dtd:default/Stratum/isActive/yes" + feature: schema/default + - surface: "dtd:default/Stratum/morphologicalRuleOrder/linear" + feature: schema/default + - surface: "dtd:default/Stratum/phonologicalRuleOrder/linear" + feature: schema/default + - surface: "dtd:default/SymbolicFeature/isActive/yes" + feature: schema/default + - surface: "dtd:element/AffixTemplate" + feature: grammar/AffixTemplate + - surface: "dtd:element/AffixTemplates" + feature: grammar/AffixTemplates + - surface: "dtd:element/Allomorph" + feature: grammar/Allomorph + - surface: "dtd:element/AllomorphCoOccurrenceRule" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:element/AllomorphCoOccurrenceRules" + feature: grammar/AllomorphCoOccurrenceRules + - surface: "dtd:element/Allomorphs" + feature: grammar/Allomorphs + - surface: "dtd:element/AlphaVariable" + feature: grammar/AlphaVariable + - surface: "dtd:element/AlphaVariables" + feature: grammar/AlphaVariables + - surface: "dtd:element/AssignedFootFeatures" + feature: grammar/AssignedFootFeatures + - surface: "dtd:element/AssignedHeadFeatures" + feature: grammar/AssignedHeadFeatures + - surface: "dtd:element/BoundaryDefinition" + feature: grammar/BoundaryDefinition + - surface: "dtd:element/BoundaryDefinitions" + feature: grammar/BoundaryDefinitions + - surface: "dtd:element/BoundaryMarker" + feature: grammar/BoundaryMarker + - surface: "dtd:element/CharacterDefinitionTable" + feature: grammar/CharacterDefinitionTable + - surface: "dtd:element/ComplexFeature" + feature: grammar/ComplexFeature + - surface: "dtd:element/CompoundingRule" + feature: grammar/CompoundingRule + - surface: "dtd:element/CompoundingSubrule" + feature: grammar/CompoundingSubrule + - surface: "dtd:element/CompoundingSubrules" + feature: grammar/CompoundingSubrules + - surface: "dtd:element/CopyFromInput" + feature: grammar/CopyFromInput + - surface: "dtd:element/Environment" + feature: grammar/Environment + - surface: "dtd:element/ExcludedEnvironments" + feature: grammar/ExcludedEnvironments + - surface: "dtd:element/Families" + feature: grammar/Families + - surface: "dtd:element/Family" + feature: grammar/Family + - surface: "dtd:element/FeatureNaturalClass" + feature: grammar/FeatureNaturalClass + - surface: "dtd:element/FeatureValue" + feature: grammar/FeatureValue + - surface: "dtd:element/FootFeatures" + feature: grammar/FootFeatures + - surface: "dtd:element/Gloss" + feature: grammar/Gloss + - surface: "dtd:element/HeadFeatures" + feature: grammar/HeadFeatures + - surface: "dtd:element/HeadMorphologicalInput" + feature: grammar/HeadMorphologicalInput + - surface: "dtd:element/HeadRequiredFootFeatures" + feature: grammar/HeadRequiredFootFeatures + - surface: "dtd:element/HeadRequiredHeadFeatures" + feature: grammar/HeadRequiredHeadFeatures + - surface: "dtd:element/HermitCrabInput" + feature: grammar/HermitCrabInput + - surface: "dtd:element/InsertSegments" + feature: grammar/InsertSegments + - surface: "dtd:element/InsertSimpleContext" + feature: grammar/InsertSimpleContext + - surface: "dtd:element/Language" + feature: grammar/Language + - surface: "dtd:element/LeftEnvironment" + feature: grammar/LeftEnvironment + - surface: "dtd:element/LexicalEntries" + feature: grammar/LexicalEntries + - surface: "dtd:element/LexicalEntry" + feature: grammar/LexicalEntry + - surface: "dtd:element/MetathesisRule" + feature: grammar/MetathesisRule + - surface: "dtd:element/ModifyFromInput" + feature: grammar/ModifyFromInput + - surface: "dtd:element/MorphemeCoOccurrenceRule" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:element/MorphemeCoOccurrenceRules" + feature: grammar/MorphemeCoOccurrenceRules + - surface: "dtd:element/MorphemeId" + feature: grammar/MorphemeId + - surface: "dtd:element/MorphologicalInput" + feature: grammar/MorphologicalInput + - surface: "dtd:element/MorphologicalOutput" + feature: grammar/MorphologicalOutput + - surface: "dtd:element/MorphologicalPhonologicalRuleFeature" + feature: grammar/MorphologicalPhonologicalRuleFeature + - surface: "dtd:element/MorphologicalPhonologicalRuleFeatureGroup" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:element/MorphologicalPhonologicalRuleFeatures" + feature: grammar/MorphologicalPhonologicalRuleFeatures + - surface: "dtd:element/MorphologicalRule" + feature: grammar/MorphologicalRule + - surface: "dtd:element/MorphologicalRuleDefinitions" + feature: grammar/MorphologicalRuleDefinitions + - surface: "dtd:element/MorphologicalSubrule" + feature: grammar/MorphologicalSubrule + - surface: "dtd:element/MorphologicalSubrules" + feature: grammar/MorphologicalSubrules + - surface: "dtd:element/Name" + feature: grammar/Name + - surface: "dtd:element/NaturalClasses" + feature: grammar/NaturalClasses + - surface: "dtd:element/NextWord" + feature: grammar/NextWord + - surface: "dtd:element/NonHeadMorphologicalInput" + feature: grammar/NonHeadMorphologicalInput + - surface: "dtd:element/NonHeadRequiredFootFeatures" + feature: grammar/NonHeadRequiredFootFeatures + - surface: "dtd:element/NonHeadRequiredHeadFeatures" + feature: grammar/NonHeadRequiredHeadFeatures + - surface: "dtd:element/Null" + feature: grammar/Null + - surface: "dtd:element/OptionalSegmentSequence" + feature: grammar/OptionalSegmentSequence + - surface: "dtd:element/OutputFootFeatures" + feature: grammar/OutputFootFeatures + - surface: "dtd:element/OutputHeadFeatures" + feature: grammar/OutputHeadFeatures + - surface: "dtd:element/OutputSubcategorizationOverride" + feature: grammar/OutputSubcategorizationOverride + - surface: "dtd:element/OutputSubcategorizationOverrides" + feature: grammar/OutputSubcategorizationOverrides + - surface: "dtd:element/PartOfSpeech" + feature: grammar/PartOfSpeech + - surface: "dtd:element/PartsOfSpeech" + feature: grammar/PartsOfSpeech + - surface: "dtd:element/PhoneticInput" + feature: grammar/PhoneticInput + - surface: "dtd:element/PhoneticOutput" + feature: grammar/PhoneticOutput + - surface: "dtd:element/PhoneticSequence" + feature: grammar/PhoneticSequence + - surface: "dtd:element/PhoneticShape" + feature: grammar/PhoneticShape + - surface: "dtd:element/PhoneticTemplate" + feature: grammar/PhoneticTemplate + - surface: "dtd:element/PhonologicalFeatureSystem" + feature: grammar/PhonologicalFeatureSystem + - surface: "dtd:element/PhonologicalRule" + feature: grammar/PhonologicalRule + - surface: "dtd:element/PhonologicalRuleDefinitions" + feature: grammar/PhonologicalRuleDefinitions + - surface: "dtd:element/PhonologicalSubrule" + feature: grammar/PhonologicalSubrule + - surface: "dtd:element/PhonologicalSubrules" + feature: grammar/PhonologicalSubrules + - surface: "dtd:element/PreviousWord" + feature: grammar/PreviousWord + - surface: "dtd:element/Properties" + feature: grammar/Properties + - surface: "dtd:element/Property" + feature: grammar/Property + - surface: "dtd:element/RealizationalFeatures" + feature: grammar/RealizationalFeatures + - surface: "dtd:element/RealizationalRule" + feature: grammar/RealizationalRule + - surface: "dtd:element/Region" + feature: grammar/Region + - surface: "dtd:element/Regions" + feature: grammar/Regions + - surface: "dtd:element/Representation" + feature: grammar/Representation + - surface: "dtd:element/Representations" + feature: grammar/Representations + - surface: "dtd:element/RequiredEnvironments" + feature: grammar/RequiredEnvironments + - surface: "dtd:element/RequiredFootFeatures" + feature: grammar/RequiredFootFeatures + - surface: "dtd:element/RequiredHeadFeatures" + feature: grammar/RequiredHeadFeatures + - surface: "dtd:element/RightEnvironment" + feature: grammar/RightEnvironment + - surface: "dtd:element/Segment" + feature: grammar/Segment + - surface: "dtd:element/SegmentDefinition" + feature: grammar/SegmentDefinition + - surface: "dtd:element/SegmentDefinitions" + feature: grammar/SegmentDefinitions + - surface: "dtd:element/SegmentNaturalClass" + feature: grammar/SegmentNaturalClass + - surface: "dtd:element/Segments" + feature: grammar/Segments + - surface: "dtd:element/SimpleContext" + feature: grammar/SimpleContext + - surface: "dtd:element/Slot" + feature: grammar/Slot + - surface: "dtd:element/StemName" + feature: grammar/StemName + - surface: "dtd:element/StemNames" + feature: grammar/StemNames + - surface: "dtd:element/Strata" + feature: grammar/Strata + - surface: "dtd:element/Stratum" + feature: grammar/Stratum + - surface: "dtd:element/StructuralDescription" + feature: grammar/StructuralDescription + - surface: "dtd:element/Symbol" + feature: grammar/Symbol + - surface: "dtd:element/SymbolicFeature" + feature: grammar/SymbolicFeature + - surface: "dtd:element/Symbols" + feature: grammar/Symbols + - surface: "dtd:element/SyntacticRule" + feature: grammar/SyntacticRule + - surface: "dtd:element/SyntacticRules" + feature: grammar/SyntacticRules + - surface: "dtd:element/VariableFeature" + feature: grammar/VariableFeature + - surface: "dtd:element/VariableFeatures" + feature: grammar/VariableFeatures + - surface: "dtd:enum/AffixTemplate/final/false" + feature: grammar/AffixTemplate + - surface: "dtd:enum/AffixTemplate/final/true" + feature: grammar/AffixTemplate + - surface: "dtd:enum/AffixTemplate/isActive/no" + feature: grammar/AffixTemplate + - surface: "dtd:enum/AffixTemplate/isActive/yes" + feature: grammar/AffixTemplate + - surface: "dtd:enum/Allomorph/isActive/no" + feature: grammar/Allomorph + - surface: "dtd:enum/Allomorph/isActive/yes" + feature: grammar/Allomorph + - surface: "dtd:enum/Allomorph/isBound/false" + feature: grammar/Allomorph + - surface: "dtd:enum/Allomorph/isBound/true" + feature: grammar/Allomorph + - surface: "dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToLeft" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToRight" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/adjacency/anywhere" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToLeft" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToRight" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/isActive/no" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/isActive/yes" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/type/exclude" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AllomorphCoOccurrenceRule/type/require" + feature: grammar/AllomorphCoOccurrenceRule + - surface: "dtd:enum/AlphaVariable/polarity/minus" + feature: grammar/AlphaVariable + - surface: "dtd:enum/AlphaVariable/polarity/plus" + feature: grammar/AlphaVariable + - surface: "dtd:enum/BoundaryDefinition/isActive/no" + feature: grammar/BoundaryDefinition + - surface: "dtd:enum/BoundaryDefinition/isActive/yes" + feature: grammar/BoundaryDefinition + - surface: "dtd:enum/CharacterDefinitionTable/isActive/no" + feature: grammar/CharacterDefinitionTable + - surface: "dtd:enum/CharacterDefinitionTable/isActive/yes" + feature: grammar/CharacterDefinitionTable + - surface: "dtd:enum/ComplexFeature/isActive/no" + feature: grammar/ComplexFeature + - surface: "dtd:enum/ComplexFeature/isActive/yes" + feature: grammar/ComplexFeature + - surface: "dtd:enum/CompoundingRule/blockable/false" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/blockable/true" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/isActive/no" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/isActive/yes" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/0" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/1" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/2" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/3" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/4" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/5" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/6" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/7" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/8" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingRule/multipleApplication/9" + feature: grammar/CompoundingRule + - surface: "dtd:enum/CompoundingSubrule/isActive/no" + feature: grammar/CompoundingSubrule + - surface: "dtd:enum/CompoundingSubrule/isActive/yes" + feature: grammar/CompoundingSubrule + - surface: "dtd:enum/Family/isActive/no" + feature: grammar/Family + - surface: "dtd:enum/Family/isActive/yes" + feature: grammar/Family + - surface: "dtd:enum/FeatureNaturalClass/isActive/no" + feature: grammar/FeatureNaturalClass + - surface: "dtd:enum/FeatureNaturalClass/isActive/yes" + feature: grammar/FeatureNaturalClass + - surface: "dtd:enum/FeatureValue/isActive/no" + feature: grammar/FeatureValue + - surface: "dtd:enum/FeatureValue/isActive/yes" + feature: grammar/FeatureValue + - surface: "dtd:enum/Language/isActive/no" + feature: grammar/Language + - surface: "dtd:enum/Language/isActive/yes" + feature: grammar/Language + - surface: "dtd:enum/LexicalEntry/isActive/no" + feature: grammar/LexicalEntry + - surface: "dtd:enum/LexicalEntry/isActive/yes" + feature: grammar/LexicalEntry + - surface: "dtd:enum/LexicalEntry/partial/false" + feature: grammar/LexicalEntry + - surface: "dtd:enum/LexicalEntry/partial/true" + feature: grammar/LexicalEntry + - surface: "dtd:enum/MetathesisRule/isActive/no" + feature: grammar/MetathesisRule + - surface: "dtd:enum/MetathesisRule/isActive/yes" + feature: grammar/MetathesisRule + - surface: "dtd:enum/MetathesisRule/multipleApplicationOrder/leftToRightIterative" + feature: grammar/MetathesisRule + - surface: "dtd:enum/MetathesisRule/multipleApplicationOrder/rightToLeftIterative" + feature: grammar/MetathesisRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToLeft" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToRight" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/adjacency/anywhere" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToLeft" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToRight" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/isActive/no" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/isActive/yes" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/type/exclude" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphemeCoOccurrenceRule/type/require" + feature: grammar/MorphemeCoOccurrenceRule + - surface: "dtd:enum/MorphologicalOutput/redupMorphType/implicit" + feature: grammar/MorphologicalOutput + - surface: "dtd:enum/MorphologicalOutput/redupMorphType/prefix" + feature: grammar/MorphologicalOutput + - surface: "dtd:enum/MorphologicalOutput/redupMorphType/suffix" + feature: grammar/MorphologicalOutput + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/no" + feature: grammar/MorphologicalPhonologicalRuleFeature + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/yes" + feature: grammar/MorphologicalPhonologicalRuleFeature + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/no" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/yes" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/all" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/any" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/append" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/overwrite" + feature: grammar/MorphologicalPhonologicalRuleFeatureGroup + - surface: "dtd:enum/MorphologicalRule/blockable/false" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/blockable/true" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/isActive/no" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/isActive/yes" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/0" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/1" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/2" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/3" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/4" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/5" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/6" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/7" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/8" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/multipleApplication/9" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/partial/false" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalRule/partial/true" + feature: grammar/MorphologicalRule + - surface: "dtd:enum/MorphologicalSubrule/isActive/no" + feature: grammar/MorphologicalSubrule + - surface: "dtd:enum/MorphologicalSubrule/isActive/yes" + feature: grammar/MorphologicalSubrule + - surface: "dtd:enum/OutputSubcategorizationOverride/isActive/no" + feature: grammar/OutputSubcategorizationOverride + - surface: "dtd:enum/OutputSubcategorizationOverride/isActive/yes" + feature: grammar/OutputSubcategorizationOverride + - surface: "dtd:enum/PhoneticTemplate/finalBoundaryCondition/false" + feature: grammar/PhoneticTemplate + - surface: "dtd:enum/PhoneticTemplate/finalBoundaryCondition/true" + feature: grammar/PhoneticTemplate + - surface: "dtd:enum/PhoneticTemplate/initialBoundaryCondition/false" + feature: grammar/PhoneticTemplate + - surface: "dtd:enum/PhoneticTemplate/initialBoundaryCondition/true" + feature: grammar/PhoneticTemplate + - surface: "dtd:enum/PhonologicalFeatureSystem/isActive/no" + feature: grammar/PhonologicalFeatureSystem + - surface: "dtd:enum/PhonologicalFeatureSystem/isActive/yes" + feature: grammar/PhonologicalFeatureSystem + - surface: "dtd:enum/PhonologicalRule/isActive/no" + feature: grammar/PhonologicalRule + - surface: "dtd:enum/PhonologicalRule/isActive/yes" + feature: grammar/PhonologicalRule + - surface: "dtd:enum/PhonologicalRule/multipleApplicationOrder/leftToRightIterative" + feature: grammar/PhonologicalRule + - surface: "dtd:enum/PhonologicalRule/multipleApplicationOrder/rightToLeftIterative" + feature: grammar/PhonologicalRule + - surface: "dtd:enum/PhonologicalRule/multipleApplicationOrder/simultaneous" + feature: grammar/PhonologicalRule + - surface: "dtd:enum/PhonologicalSubrule/isActive/no" + feature: grammar/PhonologicalSubrule + - surface: "dtd:enum/PhonologicalSubrule/isActive/yes" + feature: grammar/PhonologicalSubrule + - surface: "dtd:enum/RealizationalRule/blockable/false" + feature: grammar/RealizationalRule + - surface: "dtd:enum/RealizationalRule/blockable/true" + feature: grammar/RealizationalRule + - surface: "dtd:enum/RealizationalRule/isActive/no" + feature: grammar/RealizationalRule + - surface: "dtd:enum/RealizationalRule/isActive/yes" + feature: grammar/RealizationalRule + - surface: "dtd:enum/SegmentDefinition/isActive/no" + feature: grammar/SegmentDefinition + - surface: "dtd:enum/SegmentDefinition/isActive/yes" + feature: grammar/SegmentDefinition + - surface: "dtd:enum/SegmentNaturalClass/isActive/no" + feature: grammar/SegmentNaturalClass + - surface: "dtd:enum/SegmentNaturalClass/isActive/yes" + feature: grammar/SegmentNaturalClass + - surface: "dtd:enum/Slot/isActive/no" + feature: grammar/Slot + - surface: "dtd:enum/Slot/isActive/yes" + feature: grammar/Slot + - surface: "dtd:enum/Slot/optional/false" + feature: grammar/Slot + - surface: "dtd:enum/Slot/optional/true" + feature: grammar/Slot + - surface: "dtd:enum/Stratum/cyclicity/cyclic" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/cyclicity/noncyclic" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/isActive/no" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/isActive/yes" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/morphologicalRuleOrder/linear" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/morphologicalRuleOrder/unordered" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/phonologicalRuleOrder/linear" + feature: grammar/Stratum + - surface: "dtd:enum/Stratum/phonologicalRuleOrder/simultaneous" + feature: grammar/Stratum + - surface: "dtd:enum/SymbolicFeature/isActive/no" + feature: grammar/SymbolicFeature + - surface: "dtd:enum/SymbolicFeature/isActive/yes" + feature: grammar/SymbolicFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B1" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B2" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B3" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B4" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B5" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B6" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B7" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B8" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%B9" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%BA" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%BB" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%BC" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%BD" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%BE" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CE%BF" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%80" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%81" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%83" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%84" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%85" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%86" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%87" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%88" + feature: grammar/VariableFeature + - surface: "dtd:enum/VariableFeature/name/%CF%89" + feature: grammar/VariableFeature + - surface: "dtd:placement/AffixTemplate/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/AffixTemplate/r.1/Slot/one-or-more" + feature: schema/placement + - surface: "dtd:placement/AffixTemplates/r.0/AffixTemplate/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Allomorph/r.0/PhoneticShape/one" + feature: schema/placement + - surface: "dtd:placement/Allomorph/r.1/RequiredEnvironments/optional" + feature: schema/placement + - surface: "dtd:placement/Allomorph/r.2/ExcludedEnvironments/optional" + feature: schema/placement + - surface: "dtd:placement/Allomorph/r.3/Properties/optional" + feature: schema/placement + - surface: "dtd:placement/AllomorphCoOccurrenceRules/r.0/AllomorphCoOccurrenceRule/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Allomorphs/r.0/Allomorph/one-or-more" + feature: schema/placement + - surface: "dtd:placement/AlphaVariables/r.0/AlphaVariable/one-or-more" + feature: schema/placement + - surface: "dtd:placement/AssignedFootFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/AssignedHeadFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/BoundaryDefinition/r.0/Representations/one" + feature: schema/placement + - surface: "dtd:placement/BoundaryDefinitions/r.0/BoundaryDefinition/one-or-more" + feature: schema/placement + - surface: "dtd:placement/CharacterDefinitionTable/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/CharacterDefinitionTable/r.1/SegmentDefinitions/one" + feature: schema/placement + - surface: "dtd:placement/CharacterDefinitionTable/r.2/BoundaryDefinitions/optional" + feature: schema/placement + - surface: "dtd:placement/ComplexFeature/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.1/CompoundingSubrules/one" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.2/OutputSubcategorizationOverrides/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.3/OutputHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.4/OutputFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.5/HeadRequiredHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.6/NonHeadRequiredHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.7/HeadRequiredFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingRule/r.8/NonHeadRequiredFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingSubrule/r.0/VariableFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/CompoundingSubrule/r.1/HeadMorphologicalInput/one" + feature: schema/placement + - surface: "dtd:placement/CompoundingSubrule/r.2/NonHeadMorphologicalInput/one" + feature: schema/placement + - surface: "dtd:placement/CompoundingSubrule/r.3/MorphologicalOutput/one" + feature: schema/placement + - surface: "dtd:placement/CompoundingSubrules/r.0/CompoundingSubrule/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Environment/r.0/LeftEnvironment/optional" + feature: schema/placement + - surface: "dtd:placement/Environment/r.1/RightEnvironment/optional" + feature: schema/placement + - surface: "dtd:placement/ExcludedEnvironments/r.0/Environment/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Families/r.0/Family/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/FeatureNaturalClass/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/FeatureNaturalClass/r.1/FeatureValue/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/FeatureValue/r.0/FeatureValue/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/FootFeatures/r.0.0/SymbolicFeature/one" + feature: schema/placement + - surface: "dtd:placement/FootFeatures/r.0.1/ComplexFeature/one" + feature: schema/placement + - surface: "dtd:placement/HeadFeatures/r.0.0/SymbolicFeature/one" + feature: schema/placement + - surface: "dtd:placement/HeadFeatures/r.0.1/ComplexFeature/one" + feature: schema/placement + - surface: "dtd:placement/HeadMorphologicalInput/r.0/PhoneticSequence/one-or-more" + feature: schema/placement + - surface: "dtd:placement/HeadRequiredFootFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/HeadRequiredHeadFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/HermitCrabInput/r.0/Language/one-or-more" + feature: schema/placement + - surface: "dtd:placement/InsertSegments/r.0/PhoneticShape/one" + feature: schema/placement + - surface: "dtd:placement/InsertSimpleContext/r.0/SimpleContext/one" + feature: schema/placement + - surface: "dtd:placement/Language/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/Language/r.1/PartsOfSpeech/one" + feature: schema/placement + - surface: "dtd:placement/Language/r.10/PhonologicalRuleDefinitions/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.11/Strata/one" + feature: schema/placement + - surface: "dtd:placement/Language/r.12/MorphemeCoOccurrenceRules/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.13/AllomorphCoOccurrenceRules/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.14/SyntacticRules/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.2/PhonologicalFeatureSystem/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/Language/r.3/HeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.4/FootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.5/MorphologicalPhonologicalRuleFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.6/StemNames/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.7/CharacterDefinitionTable/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Language/r.8/NaturalClasses/optional" + feature: schema/placement + - surface: "dtd:placement/Language/r.9/Families/optional" + feature: schema/placement + - surface: "dtd:placement/LeftEnvironment/r.0/PhoneticTemplate/one" + feature: schema/placement + - surface: "dtd:placement/LexicalEntries/r.0/LexicalEntry/one-or-more" + feature: schema/placement + - surface: "dtd:placement/LexicalEntry/r.0/Allomorphs/one" + feature: schema/placement + - surface: "dtd:placement/LexicalEntry/r.1/AssignedHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/LexicalEntry/r.2/AssignedFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/LexicalEntry/r.3/MorphemeId/optional" + feature: schema/placement + - surface: "dtd:placement/LexicalEntry/r.4/Gloss/optional" + feature: schema/placement + - surface: "dtd:placement/LexicalEntry/r.5/Properties/optional" + feature: schema/placement + - surface: "dtd:placement/MetathesisRule/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/MetathesisRule/r.1/StructuralDescription/one" + feature: schema/placement + - surface: "dtd:placement/ModifyFromInput/r.0/SimpleContext/one" + feature: schema/placement + - surface: "dtd:placement/MorphemeCoOccurrenceRules/r.0/MorphemeCoOccurrenceRule/one-or-more" + feature: schema/placement + - surface: "dtd:placement/MorphologicalInput/r.0/PhoneticSequence/one-or-more" + feature: schema/placement + - surface: "dtd:placement/MorphologicalOutput/r.0/CopyFromInput/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalOutput/r.1/InsertSimpleContext/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalOutput/r.2/ModifyFromInput/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalOutput/r.3/InsertSegments/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalPhonologicalRuleFeatureGroup/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalPhonologicalRuleFeatures/r.0/MorphologicalPhonologicalRuleFeature/one-or-more" + feature: schema/placement + - surface: "dtd:placement/MorphologicalPhonologicalRuleFeatures/r.1/MorphologicalPhonologicalRuleFeatureGroup/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.1/MorphologicalSubrules/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.2/OutputSubcategorizationOverrides/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.3/OutputHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.4/OutputFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.5/RequiredHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.6/RequiredFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.7/MorphemeId/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.8/Gloss/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRule/r.9/Properties/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRuleDefinitions/r.0/MorphologicalRule/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRuleDefinitions/r.1/RealizationalRule/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalRuleDefinitions/r.2/CompoundingRule/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.0/VariableFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.1/MorphologicalInput/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.2/MorphologicalOutput/one" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.3/RequiredHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.4/RequiredFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.5/RequiredEnvironments/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.6/ExcludedEnvironments/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrule/r.7/Properties/optional" + feature: schema/placement + - surface: "dtd:placement/MorphologicalSubrules/r.0/MorphologicalSubrule/one-or-more" + feature: schema/placement + - surface: "dtd:placement/NaturalClasses/r.0/FeatureNaturalClass/one" + feature: schema/placement + - surface: "dtd:placement/NaturalClasses/r.1/SegmentNaturalClass/one" + feature: schema/placement + - surface: "dtd:placement/NextWord/r.0/PhoneticTemplate/one" + feature: schema/placement + - surface: "dtd:placement/NextWord/r.1/Null/one" + feature: schema/placement + - surface: "dtd:placement/NonHeadMorphologicalInput/r.0/PhoneticSequence/one-or-more" + feature: schema/placement + - surface: "dtd:placement/NonHeadRequiredFootFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/NonHeadRequiredHeadFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/OptionalSegmentSequence/r.0/Segment/one" + feature: schema/placement + - surface: "dtd:placement/OptionalSegmentSequence/r.1/Segments/one" + feature: schema/placement + - surface: "dtd:placement/OptionalSegmentSequence/r.2/SimpleContext/one" + feature: schema/placement + - surface: "dtd:placement/OptionalSegmentSequence/r.3/BoundaryMarker/one" + feature: schema/placement + - surface: "dtd:placement/OutputFootFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/OutputHeadFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/OutputSubcategorizationOverrides/r.0/OutputSubcategorizationOverride/one-or-more" + feature: schema/placement + - surface: "dtd:placement/PartOfSpeech/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/PartsOfSpeech/r.0/PartOfSpeech/one-or-more" + feature: schema/placement + - surface: "dtd:placement/PhoneticInput/r.0/PhoneticSequence/optional" + feature: schema/placement + - surface: "dtd:placement/PhoneticOutput/r.0/PhoneticSequence/optional" + feature: schema/placement + - surface: "dtd:placement/PhoneticSequence/r.0/Segment/one" + feature: schema/placement + - surface: "dtd:placement/PhoneticSequence/r.1/Segments/one" + feature: schema/placement + - surface: "dtd:placement/PhoneticSequence/r.2/SimpleContext/one" + feature: schema/placement + - surface: "dtd:placement/PhoneticSequence/r.3/OptionalSegmentSequence/one" + feature: schema/placement + - surface: "dtd:placement/PhoneticSequence/r.4/BoundaryMarker/one" + feature: schema/placement + - surface: "dtd:placement/PhoneticTemplate/r.0/PhoneticSequence/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalFeatureSystem/r.0/SymbolicFeature/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/PhonologicalRule/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalRule/r.1/VariableFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/PhonologicalRule/r.2/PhoneticInput/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalRule/r.3/PhonologicalSubrules/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalRuleDefinitions/r.0/PhonologicalRule/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalRuleDefinitions/r.1/MetathesisRule/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalSubrule/r.0/PhoneticOutput/one" + feature: schema/placement + - surface: "dtd:placement/PhonologicalSubrule/r.1/Environment/optional" + feature: schema/placement + - surface: "dtd:placement/PhonologicalSubrule/r.2/PreviousWord/optional" + feature: schema/placement + - surface: "dtd:placement/PhonologicalSubrule/r.3/NextWord/optional" + feature: schema/placement + - surface: "dtd:placement/PhonologicalSubrules/r.0/PhonologicalSubrule/one-or-more" + feature: schema/placement + - surface: "dtd:placement/PreviousWord/r.0/PhoneticTemplate/one" + feature: schema/placement + - surface: "dtd:placement/PreviousWord/r.1/Null/one" + feature: schema/placement + - surface: "dtd:placement/Properties/r.0/Property/one-or-more" + feature: schema/placement + - surface: "dtd:placement/RealizationalFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.1/MorphologicalSubrules/one" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.2/RealizationalFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.3/RequiredHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.4/RequiredFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.5/MorphemeId/optional" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.6/Gloss/optional" + feature: schema/placement + - surface: "dtd:placement/RealizationalRule/r.7/Properties/optional" + feature: schema/placement + - surface: "dtd:placement/Region/r.0/AssignedHeadFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/Region/r.1/AssignedFootFeatures/optional" + feature: schema/placement + - surface: "dtd:placement/Regions/r.0/Region/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Representations/r.0/Representation/one-or-more" + feature: schema/placement + - surface: "dtd:placement/RequiredEnvironments/r.0/Environment/one-or-more" + feature: schema/placement + - surface: "dtd:placement/RequiredFootFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/RequiredHeadFeatures/r.0/FeatureValue/one-or-more" + feature: schema/placement + - surface: "dtd:placement/RightEnvironment/r.0/PhoneticTemplate/one" + feature: schema/placement + - surface: "dtd:placement/SegmentDefinition/r.0/Representations/one" + feature: schema/placement + - surface: "dtd:placement/SegmentDefinition/r.1/FeatureValue/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/SegmentDefinitions/r.0/SegmentDefinition/one-or-more" + feature: schema/placement + - surface: "dtd:placement/SegmentNaturalClass/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/SegmentNaturalClass/r.1/Segment/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/Segments/r.0/PhoneticShape/one" + feature: schema/placement + - surface: "dtd:placement/SimpleContext/r.0/AlphaVariables/optional" + feature: schema/placement + - surface: "dtd:placement/Slot/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/StemName/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/StemName/r.1/Regions/one" + feature: schema/placement + - surface: "dtd:placement/StemNames/r.0/StemName/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Strata/r.0/Stratum/one-or-more" + feature: schema/placement + - surface: "dtd:placement/Stratum/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/Stratum/r.1/MorphologicalRuleDefinitions/optional" + feature: schema/placement + - surface: "dtd:placement/Stratum/r.2/AffixTemplates/optional" + feature: schema/placement + - surface: "dtd:placement/Stratum/r.3/LexicalEntries/optional" + feature: schema/placement + - surface: "dtd:placement/StructuralDescription/r.0/PhoneticTemplate/one" + feature: schema/placement + - surface: "dtd:placement/SymbolicFeature/r.0/Name/one" + feature: schema/placement + - surface: "dtd:placement/SymbolicFeature/r.1/Symbols/one" + feature: schema/placement + - surface: "dtd:placement/Symbols/r.0/Symbol/one-or-more" + feature: schema/placement + - surface: "dtd:placement/SyntacticRules/r.0/SyntacticRule/zero-or-more" + feature: schema/placement + - surface: "dtd:placement/VariableFeatures/r.0/VariableFeature/one-or-more" + feature: schema/placement diff --git a/conformance/semantic-coverage-baseline.txt b/conformance/semantic-coverage-baseline.txt new file mode 100644 index 000000000..79dfa9aea --- /dev/null +++ b/conformance/semantic-coverage-baseline.txt @@ -0,0 +1,113 @@ +# Grammar-observable semantic coverage ledger +# +# Generated. Every line is a surface ID from the DTD inventory that a grammar.xml COULD name (an +# element that can appear, or an enumerated attribute value that can be written) and that no fixture +# under conformance/ currently exercises. +# +# Format: . Blank lines and lines starting with "#" are ignored. +# +# dead-schema The engine never mentions the owning element, so no grammar can give it semantic +# coverage. NOT trusted from this file: the gate recomputes it by scanning +# src/SIL.Machine.Morphology.HermitCrab for a quoted occurrence of the element name. +# Implementing such an element makes this line wrong and fails the gate. +# todo Coverable. This is the fixture-authoring worklist. +# dtd-default The value is identical to its attribute's DTD default. XmlLanguageLoader reads the +# grammar with ValidationType.DTD, so the parser supplies that value for EVERY document +# and a fixture that writes it is indistinguishable from one that omits it. No word can +# discriminate them, so these are NOT work items. Recomputed from the inventory's own +# attribute-default surface, never trusted from this file. +# alphabet-quotient +# One value of an enumerated alphabet whose MECHANISM a sibling value already covers, +# such as the Greek letter naming a phonological variable, or a mid-range repetition +# count. Declaring the remaining letters in a grammar exercises no further behaviour, +# so they are quotiented rather than padded for. ALSO not trusted from this file: the +# gate rejects a quotient line whose (element, attribute) has no covered sibling, so a +# waiver cannot stand in for a mechanism nothing exercises. +# +# The gate asserts this file equals the recomputed uncovered set EXACTLY, in both directions: +# - an uncovered surface absent here fails as a NEW GAP; +# - a line here that a fixture now covers fails as STALE, so closing a gap means deleting its line. +# The file can therefore only shrink toward its dead-schema floor. +# +# Regenerate with: hc-conformance --semantic-coverage --write-coverage-baseline +# +# DENOMINATOR. The DTD inventory generates 1059 surfaces; only 264 are grammar-observable and appear +# here. The other 795 are excluded because a grammar author cannot write them: they are schema facts +# about the document type, not choices in a document. Counts by kind, from the inventory: +# 211 xml-read 149 attribute 149 attribute-type 149 attribute-default +# 184 placement 91 content-group 54 default 19 special-content +# Excluded is NOT the same as unimportant: `placement` is child cardinality and `attribute` covers the +# IDREFS ordering carriers (Stratum@phonologicalRules, @morphologicalRules, @activeTemplates), and +# demanding fixtures for those needs a different mechanism than reading a value out of a document. +# That mechanism does not exist here, so this ledger measures 264 surfaces and says so rather than +# reporting a percentage of a number it silently shrank. +dtd:element/NextWord dead-schema +dtd:element/Null dead-schema +dtd:element/OutputSubcategorizationOverride dead-schema +dtd:element/OutputSubcategorizationOverrides dead-schema +dtd:element/PreviousWord dead-schema +dtd:element/SyntacticRule dead-schema +dtd:element/SyntacticRules dead-schema +dtd:enum/ComplexFeature/isActive/yes dtd-default +dtd:enum/CompoundingRule/isActive/yes dtd-default +dtd:enum/CompoundingRule/multipleApplication/1 dtd-default +dtd:enum/CompoundingRule/multipleApplication/2 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/3 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/4 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/5 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/6 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/7 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/8 alphabet-quotient +dtd:enum/CompoundingRule/multipleApplication/9 alphabet-quotient +dtd:enum/CompoundingSubrule/isActive/yes dtd-default +dtd:enum/FeatureValue/isActive/yes dtd-default +dtd:enum/MetathesisRule/isActive/yes dtd-default +dtd:enum/MetathesisRule/multipleApplicationOrder/leftToRightIterative dtd-default +dtd:enum/MorphologicalOutput/redupMorphType/implicit dtd-default +dtd:enum/MorphologicalRule/blockable/true dtd-default +dtd:enum/MorphologicalRule/multipleApplication/1 dtd-default +dtd:enum/MorphologicalRule/multipleApplication/3 alphabet-quotient +dtd:enum/MorphologicalRule/multipleApplication/4 alphabet-quotient +dtd:enum/MorphologicalRule/multipleApplication/5 alphabet-quotient +dtd:enum/MorphologicalRule/multipleApplication/6 alphabet-quotient +dtd:enum/MorphologicalRule/multipleApplication/7 alphabet-quotient +dtd:enum/MorphologicalRule/multipleApplication/8 alphabet-quotient +dtd:enum/MorphologicalRule/multipleApplication/9 alphabet-quotient +dtd:enum/MorphologicalRule/partial/false dtd-default +dtd:enum/OutputSubcategorizationOverride/isActive/no dead-schema +dtd:enum/OutputSubcategorizationOverride/isActive/yes dead-schema +dtd:enum/PhoneticTemplate/finalBoundaryCondition/false dtd-default +dtd:enum/PhoneticTemplate/initialBoundaryCondition/false dtd-default +dtd:enum/PhonologicalFeatureSystem/isActive/yes dtd-default +dtd:enum/PhonologicalRule/isActive/yes dtd-default +dtd:enum/PhonologicalRule/multipleApplicationOrder/leftToRightIterative dtd-default +dtd:enum/PhonologicalSubrule/isActive/yes dtd-default +dtd:enum/RealizationalRule/blockable/true dtd-default +dtd:enum/RealizationalRule/isActive/yes dtd-default +dtd:enum/SegmentNaturalClass/isActive/yes dtd-default +dtd:enum/Slot/optional/false dtd-default +dtd:enum/Stratum/cyclicity/noncyclic dtd-default +dtd:enum/Stratum/phonologicalRuleOrder/linear dtd-default +dtd:enum/SymbolicFeature/isActive/yes dtd-default +dtd:enum/VariableFeature/name/%CE%B3 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%B4 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%B5 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%B6 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%B7 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%B8 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%B9 alphabet-quotient +dtd:enum/VariableFeature/name/%CE%BA alphabet-quotient +dtd:enum/VariableFeature/name/%CE%BB alphabet-quotient +dtd:enum/VariableFeature/name/%CE%BC alphabet-quotient +dtd:enum/VariableFeature/name/%CE%BD alphabet-quotient +dtd:enum/VariableFeature/name/%CE%BE alphabet-quotient +dtd:enum/VariableFeature/name/%CE%BF alphabet-quotient +dtd:enum/VariableFeature/name/%CF%80 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%81 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%83 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%84 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%85 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%86 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%87 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%88 alphabet-quotient +dtd:enum/VariableFeature/name/%CF%89 alphabet-quotient diff --git a/conformance/semantic-coverage-counterfactuals.tsv b/conformance/semantic-coverage-counterfactuals.tsv new file mode 100644 index 000000000..5ae07c9b4 --- /dev/null +++ b/conformance/semantic-coverage-counterfactuals.tsv @@ -0,0 +1,217 @@ +# GENERATED by hc-conformance --write-counterfactual. One line per grammar-observable +# surface a fixture contains: the verdict, the fixture, what was neutralized, the +# observed delta, and the structural counter-example fields CoverageEvidencePipeline +# joins into an Evidence record (never re-derived from delta's free text). Absent +# fields are "-". +# Evidenced neutralizing it changed a result +# RequiredByLoader the mutant would not load: HermitCrab's own loader threw (an +# IDREF/lookup/coercion failure) after passing DTD validation -- +# a real engine-semantic witness, though not a word-level delta +# EvidencedJointly only a joint mutation with an independent partner changed a result; +# weaker than Evidenced/RequiredByLoader, see CounterfactualGate.EvaluateJointly +# RequiredByDtd the mutant would not load: it failed generic DTD content-model +# validation before HermitCrab's loader ran at all -- this only +# re-derives Level 1's static DTD enumeration and is NOT equally +# conclusive with Evidenced; there is no parse-time witness +# Timeout the mutant did not finish in time, which is not evidence +# Unobservable neutralizing it changed nothing, which is not evidence +# fixture is the first-discovered fixture reaching verdict (its run is what mutation/ +# delta/example describe); witnessed_by is EVERY fixture that reached the identical +# verdict, comma-separated, ALWAYS including fixture -- a tie is not a loss, see +# CounterfactualLedger.Sweep. FoldInCandidateLedger reads this to tell 'only an edge +# case witnesses this' from 'an edge case was merely recorded first'. +surface verdict fixture mutation delta example_word example_outcome counterexample_kind counterexample_outcome witnessed_by +dtd:element/AffixTemplate RequiredByDtd edge-cases/diacritic-segments removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AffixTemplates' has incomplete content... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AffixTemplates' has incomplete content... edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony +dtd:element/AffixTemplates Evidenced edge-cases/loader-isactive-breadth removed 1 element(s) 'takul': ok::TA+KUL|takul -> ok::- takul ok::TA+KUL|takul Word ok::- edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering +dtd:element/Allomorph RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Allomorphs' has incomplete content. Li... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Allomorphs' has incomplete content. Li... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/AllomorphCoOccurrenceRule RequiredByDtd edge-cases/morphotactic-attribute-breadth removed 6 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AllomorphCoOccurrenceRules' has incomp... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AllomorphCoOccurrenceRules' has incomp... edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain +dtd:element/AllomorphCoOccurrenceRules Evidenced edge-cases/morphotactic-attribute-breadth removed 1 element(s) 'sol': ok::- -> ok::SOL|sol sol ok::- Word ok::SOL|sol edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain +dtd:element/Allomorphs RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LexicalEntry' has invalid child elemen... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LexicalEntry' has invalid child elemen... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/AlphaVariable RequiredByDtd edge-cases/alpha-variable-name-collision removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AlphaVariables' has incomplete content... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AlphaVariables' has incomplete content... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,languages/suffixing-vowel-harmony +dtd:element/AlphaVariables Evidenced edge-cases/alpha-variable-name-collision removed 4 element(s) 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,languages/suffixing-vowel-harmony +dtd:element/AssignedFootFeatures Evidenced edge-cases/compounding-breadth removed 6 element(s) 'kati': ok::- -> ok::KA+TI|kati kati ok::- Word ok::KA+TI|kati edge-cases/compounding-breadth,edge-cases/feature-gating-breadth +dtd:element/AssignedHeadFeatures Evidenced edge-cases/compounding-breadth removed 6 element(s) 'kaki': ok::- -> ok::KA+KI|kaki kaki ok::- Word ok::KA+KI|kaki edge-cases/compounding-breadth,edge-cases/feature-gating-breadth,edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/templatic-root-modification +dtd:element/BoundaryDefinition RequiredByDtd edge-cases/loader-isactive removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'BoundaryDefinitions' has incomplete co... kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'BoundaryDefinitions' has incomplete co... edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/strrep-identity,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain +dtd:element/BoundaryDefinitions RequiredByDtd edge-cases/loader-isactive-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, +, contains an undefined phonem... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, +, contains an undefined phonem... edge-cases/loader-isactive-breadth,edge-cases/strrep-identity,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain +dtd:element/BoundaryMarker Unobservable languages/metathesis-phase-isolation removed 1 element(s) all 19 word(s) unchanged - - None - languages/metathesis-phase-isolation +dtd:element/CharacterDefinitionTable RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'N... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'N... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/ComplexFeature RequiredByDtd edge-cases/feature-system-breadth removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'cfDecoy'. at System.Xml.Xml... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'cfDecoy'. at System.Xml.Xml... edge-cases/feature-system-breadth +dtd:element/CompoundingRule RequiredByDtd edge-cases/compounding-breadth removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'crDecoy'. at System.Xml.Xml... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'crDecoy'. at System.Xml.Xml... edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +dtd:element/CompoundingSubrule RequiredByDtd edge-cases/compounding-breadth removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrules' has incomplete co... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrules' has incomplete co... edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +dtd:element/CompoundingSubrules RequiredByDtd edge-cases/compounding-breadth removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingRule' has invalid child ele... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingRule' has invalid child ele... edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +dtd:element/CopyFromInput Evidenced edge-cases/compounding-breadth removed 8 element(s) 'katu': ok::KA+TU|katu -> ok::- katu ok::KA+TU|katu Word ok::- edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Environment Evidenced edge-cases/mpr-gated-exception removed 3 element(s) 'tulik': ok::TULIK|tulik -> ok::- tulik ok::TULIK|tulik Word ok::- edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/templatic-root-modification +dtd:element/ExcludedEnvironments Evidenced edge-cases/feature-system-breadth removed 1 element(s) 'salk': ok::- -> ok::SAL+SUF|salk salk ok::- Word ok::SAL+SUF|salk edge-cases/feature-system-breadth +dtd:element/Families RequiredByDtd edge-cases/loader-isactive-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'famDecoy'. at System.Xml.Xm... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'famDecoy'. at System.Xml.Xm... edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:element/Family RequiredByDtd edge-cases/loader-isactive-breadth removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'famDecoy'. at System.Xml.Xm... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'famDecoy'. at System.Xml.Xm... edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:element/FeatureNaturalClass RequiredByDtd edge-cases/compounding-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'NaturalClasses' has incomplete content... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'NaturalClasses' has incomplete content... edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/FeatureValue Evidenced edge-cases/alpha-variable-name-collision removed 8 element(s) 'au': ok::- -> ok::AU|[iyau][iyau] au ok::- Word ok::AU|[iyau][iyau] edge-cases/alpha-variable-name-collision,edge-cases/disjunctive-recheck,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain +dtd:element/FootFeatures RequiredByDtd edge-cases/compounding-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'clsB'. at System.Xml.XmlVal... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'clsB'. at System.Xml.XmlVal... edge-cases/compounding-breadth,edge-cases/feature-gating-breadth,languages/suffixing-extension-slot-ordering +dtd:element/Gloss Unobservable edge-cases/alpha-variable-name-collision removed 1 element(s) all 2 word(s) unchanged - - None - edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/HeadFeatures RequiredByDtd edge-cases/compounding-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'numSg'. at System.Xml.XmlVa... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'numSg'. at System.Xml.XmlVa... edge-cases/compounding-breadth,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +dtd:element/HeadMorphologicalInput RequiredByDtd edge-cases/compounding-breadth removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has invalid child ... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has invalid child ... edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +dtd:element/HeadRequiredFootFeatures Evidenced edge-cases/compounding-breadth removed 2 element(s) 'patu': ok::- -> ok::PA+TU|patu patu ok::- Word ok::PA+TU|patu edge-cases/compounding-breadth +dtd:element/HeadRequiredHeadFeatures Evidenced edge-cases/compounding-breadth removed 2 element(s) 'kutu': ok::- -> ok::KU+TU|kutu kutu ok::- Word ok::KU+TU|kutu edge-cases/compounding-breadth +dtd:element/HermitCrabInput RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Token EndDocument in state Document would result in an invalid XML document. au ok::- LoadFailure InvalidOperationException: Token EndDocument in state Document would result in an invalid XML document. edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/InsertSegments Evidenced edge-cases/diacritic-segments removed 2 element(s) 'año': ok::YEAR|año -> ok::YEAR+DIM|año;YEAR+PL|año;YEAR|año año ok::YEAR|año Word ok::YEAR+DIM|año;YEAR+PL|año;YEAR|año edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/truncate-morphotactic,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/InsertSimpleContext Evidenced languages/templatic-root-modification removed 1 element(s) 'spr': ok::SPR|spr -> ok::SPR+FORMII|spr;SPR|spr spr ok::SPR|spr Word ok::SPR+FORMII|spr;SPR|spr languages/templatic-root-modification +dtd:element/Language RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'HermitCrabInput' has incomplete conten... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'HermitCrabInput' has incomplete conten... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/LeftEnvironment Evidenced edge-cases/diacritic-segments removed 1 element(s) 'añota': ok::- -> ok::YEAR+DIM|añota añota ok::- Word ok::YEAR+DIM|añota edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-system-breadth,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-evidential-adjacency-chain,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/LexicalEntries Evidenced edge-cases/alpha-variable-name-collision removed 1 element(s) 'ia': ok::AU|ia -> ok::- ia ok::AU|ia Word ok::- edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony +dtd:element/LexicalEntry RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LexicalEntries' has incomplete content... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LexicalEntries' has incomplete content... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MetathesisRule RequiredByDtd edge-cases/feature-system-breadth removed 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'mtDecoy'. at System.Xml.Xml... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'mtDecoy'. at System.Xml.Xml... edge-cases/feature-system-breadth,languages/metathesis-phase-isolation +dtd:element/ModifyFromInput Evidenced edge-cases/process-morphology-in-place-mutation removed 1 element(s) 'a': ok::AROOT|a;ROOT+ABLAUT|a -> ok::AROOT|a a ok::AROOT|a;ROOT+ABLAUT|a Word ok::AROOT|a edge-cases/process-morphology-in-place-mutation,languages/fusional-realizational-morphology,languages/templatic-root-modification +dtd:element/MorphemeCoOccurrenceRule RequiredByDtd edge-cases/morphotactic-attribute-breadth removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphemeCoOccurrenceRules' has incompl... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphemeCoOccurrenceRules' has incompl... edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +dtd:element/MorphemeCoOccurrenceRules Evidenced languages/suffixing-evidential-adjacency-chain removed 1 element(s) 'walakntan': ok::- -> ok::WALAK+3SG+ASSUM|walakntan walakntan ok::- Word ok::WALAK+3SG+ASSUM|walakntan languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +dtd:element/MorphemeId Evidenced edge-cases/alpha-variable-name-collision removed 1 element(s) 'ia': ok::AU|ia -> ok::|ia ia ok::AU|ia Word ok::|ia edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/subrule-morphosyntactic-gating,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MorphologicalInput RequiredByDtd edge-cases/diacritic-segments removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalSubrule' has invalid chil... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalSubrule' has invalid chil... edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MorphologicalOutput RequiredByDtd edge-cases/compounding-breadth removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has incomplete con... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has incomplete con... edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MorphologicalPhonologicalRuleFeature RequiredByDtd edge-cases/loader-isactive-breadth removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalPhonologicalRuleFeatures'... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalPhonologicalRuleFeatures'... edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering +dtd:element/MorphologicalPhonologicalRuleFeatureGroup Evidenced edge-cases/mpr-group-overwrite-without-realizational removed 1 element(s) 'wudofq': ok::- -> ok::THEMEB+THEMEA+DOF+ENDC|wudofq wudofq ok::- Word ok::THEMEB+THEMEA+DOF+ENDC|wudofq edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:element/MorphologicalPhonologicalRuleFeatures RequiredByDtd edge-cases/loader-isactive-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'mprDecoy'. at System.Xml.Xm... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'mprDecoy'. at System.Xml.Xm... edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-extension-slot-ordering +dtd:element/MorphologicalRule RequiredByDtd edge-cases/diacritic-segments removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'rDim'. at System.Xml.XmlVal... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'rDim'. at System.Xml.XmlVal... edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MorphologicalRuleDefinitions RequiredByDtd edge-cases/compounding-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'crDecoy'. at System.Xml.Xml... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'crDecoy'. at System.Xml.Xml... edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MorphologicalSubrule RequiredByDtd edge-cases/diacritic-segments removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalSubrules' has incomplete ... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalSubrules' has incomplete ... edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/MorphologicalSubrules RequiredByDtd edge-cases/diacritic-segments removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalRule' has invalid child e... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalRule' has invalid child e... edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Name RequiredByDtd edge-cases/alpha-variable-name-collision removed 8 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'P... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'P... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/NaturalClasses RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'ncVowel'. at System.Xml.Xml... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'ncVowel'. at System.Xml.Xml... edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/NonHeadMorphologicalInput RequiredByDtd edge-cases/compounding-breadth removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has invalid child ... ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has invalid child ... edge-cases/compounding-breadth,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +dtd:element/NonHeadRequiredFootFeatures Evidenced edge-cases/compounding-breadth removed 2 element(s) 'kati': ok::- -> ok::KA+TI|kati kati ok::- Word ok::KA+TI|kati edge-cases/compounding-breadth +dtd:element/NonHeadRequiredHeadFeatures Evidenced edge-cases/compounding-breadth removed 2 element(s) 'kaki': ok::- -> ok::KA+KI|kaki kaki ok::- Word ok::KA+KI|kaki edge-cases/compounding-breadth +dtd:element/OptionalSegmentSequence Evidenced edge-cases/compounding-breadth removed 4 element(s) 'katu': ok::KA+TU|katu -> ok::- katu ok::KA+TU|katu Word ok::- edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/OutputFootFeatures Evidenced edge-cases/feature-gating-breadth removed 2 element(s) 'nalnomu': ok::NAL+LOUD+EMPH|nalnomu -> ok::- nalnomu ok::NAL+LOUD+EMPH|nalnomu Word ok::- edge-cases/feature-gating-breadth,languages/suffixing-extension-slot-ordering +dtd:element/OutputHeadFeatures Evidenced edge-cases/stem-name-restricted-root-allomorph removed 2 element(s) 'kapom': ok::ROOT+PERS1|kapom -> ok::- kapom ok::ROOT+PERS1|kapom Word ok::- edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +dtd:element/PartOfSpeech RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PartsOfSpeech' has incomplete content.... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PartsOfSpeech' has incomplete content.... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PartsOfSpeech RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'P... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'P... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhoneticInput RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalRule' has invalid child el... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalRule' has invalid child el... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhoneticOutput RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalSubrule' has incomplete co... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalSubrule' has incomplete co... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhoneticSequence Evidenced edge-cases/alpha-variable-name-collision removed 2 element(s) 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision,edge-cases/loader-default-symbol +dtd:element/PhoneticShape RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Allomorph' has incomplete content. Lis... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Allomorph' has incomplete content. Lis... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhoneticTemplate RequiredByDtd edge-cases/diacritic-segments removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LeftEnvironment' has incomplete conten... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LeftEnvironment' has incomplete conten... edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhonologicalFeatureSystem RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'featRound'. at System.Xml.X... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'featRound'. at System.Xml.X... edge-cases/alpha-variable-name-collision,edge-cases/disjunctive-recheck,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/mpr-gated-exception,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhonologicalRule RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'prDoubleAlpha'. at System.X... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'prDoubleAlpha'. at System.X... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhonologicalRuleDefinitions RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'prDoubleAlpha'. at System.X... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'prDoubleAlpha'. at System.X... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhonologicalSubrule RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalSubrules' has incomplete c... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalSubrules' has incomplete c... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/PhonologicalSubrules RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalRule' has incomplete conte... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalRule' has incomplete conte... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,edge-cases/loader-default-symbol,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Properties Unobservable edge-cases/feature-gating-breadth removed 1 element(s) all 15 word(s) unchanged - - None - edge-cases/feature-gating-breadth,edge-cases/loader-isactive-breadth +dtd:element/Property RequiredByDtd edge-cases/feature-gating-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Properties' has incomplete content. Li... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Properties' has incomplete content. Li... edge-cases/feature-gating-breadth,edge-cases/loader-isactive-breadth +dtd:element/RealizationalFeatures RequiredByDtd edge-cases/feature-gating-breadth emptied 1 element(s) (1 child node(s) removed) rather than deleting them, in place of a deletion that did not terminate InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'RealizationalFeatures' has incomplete ... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'RealizationalFeatures' has incomplete ... edge-cases/feature-gating-breadth,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:element/RealizationalRule RequiredByDtd edge-cases/feature-gating-breadth removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'rrPast'. at System.Xml.XmlV... kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'rrPast'. at System.Xml.XmlV... edge-cases/feature-gating-breadth,edge-cases/morphotactic-attribute-breadth,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:element/Region RequiredByDtd edge-cases/stem-name-restricted-root-allomorph removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Regions' has incomplete content. List ... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Regions' has incomplete content. List ... edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +dtd:element/Regions RequiredByDtd edge-cases/stem-name-restricted-root-allomorph removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'StemName' has incomplete content. List... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'StemName' has incomplete content. List... edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +dtd:element/Representation RequiredByDtd edge-cases/alpha-variable-name-collision removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Representations' has incomplete conten... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Representations' has incomplete conten... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Representations RequiredByDtd edge-cases/alpha-variable-name-collision removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SegmentDefinition' has invalid child e... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SegmentDefinition' has invalid child e... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/RequiredEnvironments Evidenced edge-cases/diacritic-segments removed 1 element(s) 'añota': ok::- -> ok::YEAR+DIM|añota añota ok::- Word ok::YEAR+DIM|añota edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/free-fluctuating-allomorph-pair,edge-cases/strrep-identity,languages/suffixing-evidential-adjacency-chain +dtd:element/RequiredFootFeatures Evidenced edge-cases/feature-gating-breadth removed 2 element(s) 'molka': ok::- -> ok::MOL+AGR|molka molka ok::- Word ok::MOL+AGR|molka edge-cases/feature-gating-breadth +dtd:element/RequiredHeadFeatures Evidenced edge-cases/feature-gating-breadth removed 1 element(s) 'tunka': ok::- -> ok::TUN+AGR|tunka tunka ok::- Word ok::TUN+AGR|tunka edge-cases/feature-gating-breadth +dtd:element/RightEnvironment Evidenced edge-cases/disjunctive-recheck removed 1 element(s) 'wak': ok::|wak -> ok::- wak ok::|wak Word ok::- edge-cases/disjunctive-recheck,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/strrep-identity,languages/metathesis-phase-isolation,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Segment Evidenced edge-cases/diacritic-segments removed 4 element(s) 'añota': ok::- -> ok::YEAR+DIM|añota añota ok::- Word ok::YEAR+DIM|añota edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/free-fluctuating-allomorph-pair,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-evidential-adjacency-chain,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/SegmentDefinition RequiredByDtd edge-cases/alpha-variable-name-collision removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SegmentDefinitions' has incomplete con... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SegmentDefinitions' has incomplete con... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/SegmentDefinitions RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CharacterDefinitionTable' has incomple... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CharacterDefinitionTable' has incomple... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/SegmentNaturalClass RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'NaturalClasses' has incomplete content... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'NaturalClasses' has incomplete content... edge-cases/alpha-variable-name-collision,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-pattern-shapes,edge-cases/mpr-gated-exception,edge-cases/right-to-left-anchor-environment,edge-cases/strrep-identity,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-evidential-adjacency-chain,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Segments Evidenced edge-cases/strrep-identity removed 1 element(s) 'ndpat': ok::++|[(^0)∅]?+?nd+?pat;++|nd+?[(^0)∅]?+?pat;+|nd+?pat -> ok::- ndpat ok::++|[(^0)∅]?+?nd+?pat;++|nd+?[(^0)∅]?+?pat;+|nd+?pat Word ok::- edge-cases/strrep-identity +dtd:element/SimpleContext Evidenced edge-cases/alpha-variable-name-collision removed 4 element(s) 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision,edge-cases/loader-default-symbol,edge-cases/right-to-left-anchor-environment +dtd:element/Slot RequiredByDtd edge-cases/diacritic-segments removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AffixTemplate' has incomplete content.... año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AffixTemplate' has incomplete content.... edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony +dtd:element/StemName RequiredByDtd edge-cases/stem-name-restricted-root-allomorph removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'StemNames' has incomplete content. Lis... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'StemNames' has incomplete content. Lis... edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +dtd:element/StemNames RequiredByDtd edge-cases/stem-name-restricted-root-allomorph removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'snP1'. at System.Xml.XmlVal... tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'snP1'. at System.Xml.XmlVal... edge-cases/stem-name-restricted-root-allomorph,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering,languages/templatic-root-modification +dtd:element/Strata RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has incomplete content. List... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has incomplete content. List... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Stratum RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Strata' has incomplete content. List o... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Strata' has incomplete content. List o... edge-cases/alpha-variable-name-collision,edge-cases/bistratal-overlapping-segment-representation,edge-cases/compounding-breadth,edge-cases/diacritic-segments,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/loader-isactive-breadth,edge-cases/loader-pattern-shapes,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/strrep-identity,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/StructuralDescription RequiredByDtd edge-cases/feature-system-breadth removed 3 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MetathesisRule' has incomplete content... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MetathesisRule' has incomplete content... edge-cases/feature-system-breadth,languages/metathesis-phase-isolation +dtd:element/Symbol RequiredByDtd edge-cases/alpha-variable-name-collision removed 4 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Symbols' has incomplete content. List ... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Symbols' has incomplete content. List ... edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/SymbolicFeature RequiredByDtd edge-cases/alpha-variable-name-collision removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'featRound'. at System.Xml.X... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'featRound'. at System.Xml.X... edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/Symbols RequiredByDtd edge-cases/alpha-variable-name-collision removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SymbolicFeature' has incomplete conten... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SymbolicFeature' has incomplete conten... edge-cases/alpha-variable-name-collision,edge-cases/compounding-breadth,edge-cases/disjunctive-recheck,edge-cases/feature-gating-breadth,edge-cases/feature-system-breadth,edge-cases/free-fluctuating-allomorph-pair,edge-cases/loader-default-symbol,edge-cases/loader-isactive,edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-gated-exception,edge-cases/process-morphology-in-place-mutation,edge-cases/right-to-left-anchor-environment,edge-cases/stem-name-restricted-root-allomorph,edge-cases/subrule-morphosyntactic-gating,edge-cases/truncate-morphotactic,languages/fusional-realizational-morphology,languages/metathesis-phase-isolation,languages/polysynthetic-stratal-derivation-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:element/VariableFeature RequiredByDtd edge-cases/alpha-variable-name-collision removed 2 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'VariableFeatures' has incomplete conte... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'VariableFeatures' has incomplete conte... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,languages/suffixing-vowel-harmony +dtd:element/VariableFeatures RequiredByDtd edge-cases/alpha-variable-name-collision removed 1 element(s) InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'varRound'. at System.Xml.Xm... au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'varRound'. at System.Xml.Xm... edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth,languages/suffixing-vowel-harmony +dtd:enum/AffixTemplate/final/false Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 AffixTemplate@final from "false" to "true" sibling "true" of 1 tried: 'kulpu': ok::- -> ok::KUL+NF|kulpu kulpu ok::- Word ok::KUL+NF|kulpu edge-cases/morphotactic-attribute-breadth +dtd:enum/AffixTemplate/final/true Evidenced edge-cases/loader-isactive-breadth rewrote 1 AffixTemplate@final from "true" to "false" sibling "false" of 1 tried: 'kul': ok::KUL|kul -> ok::- kul ok::KUL|kul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/AffixTemplate/isActive/no Evidenced edge-cases/loader-isactive-breadth rewrote 1 AffixTemplate@isActive from "no" to "yes" sibling "yes" of 1 tried: 'qukul': ok::- -> ok::QU+KUL|qukul qukul ok::- Word ok::QU+KUL|qukul edge-cases/loader-isactive-breadth +dtd:enum/AffixTemplate/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 1 AffixTemplate@isActive from "yes" to "no" sibling "no" of 1 tried: 'takul': ok::TA+KUL|takul -> ok::- takul ok::TA+KUL|takul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/Allomorph/isActive/no Evidenced edge-cases/loader-isactive-breadth rewrote 1 Allomorph@isActive from "no" to "yes" sibling "yes" of 1 tried: 'kol': ok::- -> ok::KUL|kol kol ok::- Word ok::KUL|kol edge-cases/loader-isactive-breadth +dtd:enum/Allomorph/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 1 Allomorph@isActive from "yes" to "no" sibling "no" of 1 tried: 'kul': ok::KUL|kul -> ok::- kul ok::KUL|kul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/Allomorph/isBound/false Evidenced edge-cases/loader-isactive-breadth rewrote 1 Allomorph@isBound from "false" to "true" sibling "true" of 1 tried: 'kul': ok::KUL|kul -> ok::- kul ok::KUL|kul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/Allomorph/isBound/true Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 Allomorph@isBound from "true" to "false" sibling "false" of 1 tried: 'kur': ok::- -> ok::KUL|kur kur ok::- Word ok::KUL|kur edge-cases/morphotactic-attribute-breadth +dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToLeft Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 AllomorphCoOccurrenceRule@adjacency from "adjacentToLeft" to "adjacentToRight" sibling "adjacentToRight" of 4 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToRight Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 AllomorphCoOccurrenceRule@adjacency from "adjacentToRight" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/AllomorphCoOccurrenceRule/adjacency/anywhere Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 AllomorphCoOccurrenceRule@adjacency from "anywhere" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'kantancha': ok::- -> ok::SING+3SG+CONJ|kantan(ch)a kantancha ok::- Word ok::SING+3SG+CONJ|kantan(ch)a languages/suffixing-evidential-adjacency-chain +dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToLeft Evidenced edge-cases/morphotactic-attribute-breadth rewrote 2 AllomorphCoOccurrenceRule@adjacency from "somewhereToLeft" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToRight Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 AllomorphCoOccurrenceRule@adjacency from "somewhereToRight" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/AllomorphCoOccurrenceRule/isActive/no Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 AllomorphCoOccurrenceRule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/AllomorphCoOccurrenceRule/isActive/yes Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 AllomorphCoOccurrenceRule@isActive from "yes" to "no" sibling "no" of 1 tried: 'kantancha': ok::- -> ok::SING+3SG+CONJ|kantan(ch)a kantancha ok::- Word ok::SING+3SG+CONJ|kantan(ch)a languages/suffixing-evidential-adjacency-chain +dtd:enum/AllomorphCoOccurrenceRule/type/exclude Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 AllomorphCoOccurrenceRule@type from "exclude" to "require" sibling "require" of 1 tried: 'kantay': ok::SING+1SG|kantay -> ok::- kantay ok::SING+1SG|kantay Word ok::- languages/suffixing-evidential-adjacency-chain +dtd:enum/AllomorphCoOccurrenceRule/type/require Evidenced edge-cases/morphotactic-attribute-breadth rewrote 5 AllomorphCoOccurrenceRule@type from "require" to "exclude" sibling "exclude" of 1 tried: 'sol': ok::- -> ok::SOL|sol sol ok::- Word ok::SOL|sol edge-cases/morphotactic-attribute-breadth +dtd:enum/AlphaVariable/polarity/minus Evidenced edge-cases/alpha-variable-name-collision rewrote 2 AlphaVariable@polarity from "minus" to "plus" sibling "plus" of 1 tried: 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth +dtd:enum/AlphaVariable/polarity/plus Evidenced edge-cases/alpha-variable-name-collision rewrote 2 AlphaVariable@polarity from "plus" to "minus" sibling "minus" of 1 tried: 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision,edge-cases/feature-system-breadth +dtd:enum/BoundaryDefinition/isActive/no Evidenced edge-cases/loader-isactive-breadth rewrote 1 BoundaryDefinition@isActive from "no" to "yes" sibling "yes" of 1 tried: 'kul=': SKIPPED::- -> ok::- kul= SKIPPED::- Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/BoundaryDefinition/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 BoundaryDefinition@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, +, contains an undefined phonem... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, +, contains an undefined phonem... edge-cases/loader-isactive-breadth +dtd:enum/CharacterDefinitionTable/isActive/no EvidencedJointly edge-cases/loader-isactive-breadth rewrote 1 CharacterDefinitionTable@isActive from "no" to "yes"; jointly activated its sole referencing (TableDecoyStratum) via characterDefinitionTable="tableDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 CharacterDefinitionTable@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (TableDecoyStratum) via characterDefinitionTable="tableDecoy", while CharacterDefinitionTable@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableDecoy' was not present in the ...); both jointly (rewrote 1 CharacterDefinitionTable@isActive from "no" to "yes"; jointly activated its sole referencing (TableDecoyStratum) via characterDefinitionTable="tableDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('kul': ok::KUL|kul -> SKIPPED::-) kul ok::KUL|kul Word SKIPPED::- edge-cases/loader-isactive-breadth +dtd:enum/CharacterDefinitionTable/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 CharacterDefinitionTable@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableLive' was not present in the d... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableLive' was not present in the d... edge-cases/loader-isactive-breadth +dtd:enum/ComplexFeature/isActive/no EvidencedJointly edge-cases/feature-system-breadth rewrote 1 ComplexFeature@isActive from "no" to "yes"; jointly activated its sole referencing (eDecCf) via feature="cfDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 ComplexFeature@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (eDecCf) via feature="cfDecoy", while ComplexFeature@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'cfDecoy' could not be found. (Parameter 'id') at SIL.Mach...); both jointly (rewrote 1 ComplexFeature@isActive from "no" to "yes"; jointly activated its sole referencing (eDecCf) via feature="cfDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('tal': ok::- -> ok::TAL|tal) tal ok::- Word ok::TAL|tal edge-cases/feature-system-breadth +dtd:enum/CompoundingRule/blockable/false Evidenced languages/fusional-realizational-morphology rewrote 2 CompoundingRule@blockable from "false" to "true" sibling "true" of 1 tried: 'corriv': ok::BLOCKHEAD+BLOCKNON|cor+?riv -> ok::- corriv ok::BLOCKHEAD+BLOCKNON|cor+?riv Word ok::- languages/fusional-realizational-morphology +dtd:enum/CompoundingRule/blockable/true Evidenced languages/fusional-realizational-morphology rewrote 1 CompoundingRule@blockable from "true" to "false" sibling "false" of 1 tried: 'genlav': ok::- -> ok::GEN+LAV|gen+?lav genlav ok::- Word ok::GEN+LAV|gen+?lav languages/fusional-realizational-morphology +dtd:enum/CompoundingRule/isActive/no Evidenced edge-cases/compounding-breadth rewrote 1 CompoundingRule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'kaptu': ok::- -> ok::KA+TU|kaptu kaptu ok::- Word ok::KA+TU|kaptu edge-cases/compounding-breadth +dtd:enum/CompoundingRule/multipleApplication/0 Evidenced edge-cases/compounding-breadth rewrote 1 CompoundingRule@multipleApplication from "0" to "1" sibling "1" of 9 tried: 'kamtu': ok::- -> ok::KA+TU|kamtu kamtu ok::- Word ok::KA+TU|kamtu edge-cases/compounding-breadth +dtd:enum/CompoundingSubrule/isActive/no Evidenced edge-cases/compounding-breadth rewrote 1 CompoundingSubrule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'kaitu': ok::- -> ok::KA+TU|kaitu kaitu ok::- Word ok::KA+TU|kaitu edge-cases/compounding-breadth +dtd:enum/Family/isActive/no EvidencedJointly edge-cases/loader-isactive-breadth rewrote 1 Family@isActive from "no" to "yes"; jointly activated its sole referencing (eTupDecoy) via family="famDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 Family@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (eTupDecoy) via family="famDecoy", while Family@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'famDecoy' was not present in the di...); both jointly (rewrote 1 Family@isActive from "no" to "yes"; jointly activated its sole referencing (eTupDecoy) via family="famDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('tup': ok::- -> ok::TUP|tup) tup ok::- Word ok::TUP|tup edge-cases/loader-isactive-breadth +dtd:enum/Family/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 Family@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'famLive' was not present in the dic... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'famLive' was not present in the dic... edge-cases/loader-isactive-breadth +dtd:enum/FeatureNaturalClass/isActive/no EvidencedJointly edge-cases/feature-system-breadth rewrote 1 FeatureNaturalClass@isActive from "no" to "yes"; jointly activated its sole referencing (prDecFnc) via naturalClass="ncFDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 FeatureNaturalClass@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (prDecFnc) via naturalClass="ncFDecoy", while FeatureNaturalClass@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncFDecoy' was not present in the di...); both jointly (rewrote 1 FeatureNaturalClass@isActive from "no" to "yes"; jointly activated its sole referencing (prDecFnc) via naturalClass="ncFDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('ik': ok::AK|ik -> ok::-) ik ok::AK|ik Word ok::- edge-cases/feature-system-breadth,edge-cases/loader-isactive-breadth +dtd:enum/FeatureNaturalClass/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 FeatureNaturalClass@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncAny' was not present in the dicti... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncAny' was not present in the dicti... edge-cases/loader-isactive-breadth +dtd:enum/FeatureValue/isActive/no Evidenced edge-cases/feature-system-breadth rewrote 1 FeatureValue@isActive from "no" to "yes" sibling "yes" of 1 tried: 'ts': ok::TS|ts -> ok::- ts ok::TS|ts Word ok::- edge-cases/feature-system-breadth +dtd:enum/Language/isActive/no RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 Language@isActive from "no" to "yes" sibling "yes" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element at System.Lin... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element at System.Lin... edge-cases/loader-isactive-breadth +dtd:enum/Language/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 Language@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains no matching element at System.Linq.ThrowHelp... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains no matching element at System.Linq.ThrowHelp... edge-cases/loader-isactive-breadth +dtd:enum/LexicalEntry/isActive/no RequiredByLoader edge-cases/feature-system-breadth rewrote 1 LexicalEntry@isActive from "no" to "yes" sibling "yes" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'cfDecoy' could not be found. (Parameter 'id') at SIL.Mach... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'cfDecoy' could not be found. (Parameter 'id') at SIL.Mach... edge-cases/feature-system-breadth,edge-cases/loader-isactive-breadth +dtd:enum/LexicalEntry/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 1 LexicalEntry@isActive from "yes" to "no" sibling "no" of 1 tried: 'kul': ok::KUL|kul -> ok::- kul ok::KUL|kul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/LexicalEntry/partial/false Evidenced edge-cases/loader-isactive-breadth rewrote 1 LexicalEntry@partial from "false" to "true" sibling "true" of 1 tried: 'takul': ok::TA+KUL|takul -> ok::- takul ok::TA+KUL|takul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/LexicalEntry/partial/true Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 LexicalEntry@partial from "true" to "false" sibling "false" of 1 tried: 'napmo': ok::- -> ok::NAP+PART|napmo napmo ok::- Word ok::NAP+PART|napmo edge-cases/morphotactic-attribute-breadth +dtd:enum/MetathesisRule/isActive/no Evidenced edge-cases/feature-system-breadth rewrote 1 MetathesisRule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'ka': ok::KA|ka -> threw::InvalidOperationException ka ok::KA|ka Word threw::InvalidOperationException edge-cases/feature-system-breadth +dtd:enum/MetathesisRule/multipleApplicationOrder/rightToLeftIterative Evidenced edge-cases/feature-system-breadth rewrote 2 MetathesisRule@multipleApplicationOrder from "rightToLeftIterative" to "leftToRightIterative" sibling "leftToRightIterative" of 1 tried: 'tlk': ok::TKL|tlk -> ok::- tlk ok::TKL|tlk Word ok::- edge-cases/feature-system-breadth +dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToLeft Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 MorphemeCoOccurrenceRule@adjacency from "adjacentToLeft" to "adjacentToRight" sibling "adjacentToRight" of 4 tried: 'walakniwas': ok::WALAK+1SG+MIR|walakniwas -> ok::- walakniwas ok::WALAK+1SG+MIR|walakniwas Word ok::- languages/suffixing-evidential-adjacency-chain +dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToRight Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 MorphemeCoOccurrenceRule@adjacency from "adjacentToRight" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'sipulupami': ok::SIPU+2PL+DIR|sipulupami -> ok::- sipulupami ok::SIPU+2PL+DIR|sipulupami Word ok::- languages/suffixing-evidential-adjacency-chain +dtd:enum/MorphemeCoOccurrenceRule/adjacency/anywhere Evidenced edge-cases/morphotactic-attribute-breadth rewrote 2 MorphemeCoOccurrenceRule@adjacency from "anywhere" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToLeft Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 MorphemeCoOccurrenceRule@adjacency from "somewhereToLeft" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'walaknichiktan': ok::WALAK+1SG+PL+ASSUM|walakni(ch)iktan -> ok::- walaknichiktan ok::WALAK+1SG+PL+ASSUM|walakni(ch)iktan Word ok::- languages/suffixing-evidential-adjacency-chain +dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToRight Evidenced languages/suffixing-evidential-adjacency-chain rewrote 1 MorphemeCoOccurrenceRule@adjacency from "somewhereToRight" to "adjacentToLeft" sibling "adjacentToLeft" of 4 tried: 'siputukumi': ok::SIPU+1PL.INCL+DIR|siputukumi -> ok::- siputukumi ok::SIPU+1PL.INCL+DIR|siputukumi Word ok::- languages/suffixing-evidential-adjacency-chain +dtd:enum/MorphemeCoOccurrenceRule/isActive/no Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphemeCoOccurrenceRule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/MorphemeCoOccurrenceRule/isActive/yes Evidenced languages/suffixing-evidential-adjacency-chain rewrote 6 MorphemeCoOccurrenceRule@isActive from "yes" to "no" sibling "no" of 1 tried: 'walakntan': ok::- -> ok::WALAK+3SG+ASSUM|walakntan walakntan ok::- Word ok::WALAK+3SG+ASSUM|walakntan languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +dtd:enum/MorphemeCoOccurrenceRule/type/exclude Evidenced languages/suffixing-evidential-adjacency-chain rewrote 2 MorphemeCoOccurrenceRule@type from "exclude" to "require" sibling "require" of 1 tried: 'sipuncha': ok::SIPU+3SG+CONJ|sipun(ch)a -> ok::- sipuncha ok::SIPU+3SG+CONJ|sipun(ch)a Word ok::- languages/suffixing-evidential-adjacency-chain,languages/templatic-root-modification +dtd:enum/MorphemeCoOccurrenceRule/type/require Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphemeCoOccurrenceRule@type from "require" to "exclude" sibling "exclude" of 1 tried: 'topsakatana': ok::TOP+COA+COB+COC+COD|topsakatana -> ok::- topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- edge-cases/morphotactic-attribute-breadth,languages/suffixing-evidential-adjacency-chain +dtd:enum/MorphologicalOutput/redupMorphType/prefix Evidenced languages/metathesis-phase-isolation rewrote 2 MorphologicalOutput@redupMorphType from "prefix" to "implicit" sibling "implicit" of 2 tried: 'tulatula': ok::RDPL+TULA|tulatula -> ok::TULA+RDPL|tulatula tulatula ok::RDPL+TULA|tulatula Word ok::TULA+RDPL|tulatula languages/metathesis-phase-isolation +dtd:enum/MorphologicalOutput/redupMorphType/suffix Evidenced languages/suffixing-extension-slot-ordering rewrote 1 MorphologicalOutput@redupMorphType from "suffix" to "prefix" sibling "prefix" of 2 tried: 'kimbiakimbia': ok::KIMB+RED|kimbiakimbia -> ok::RED+KIMB|kimbiakimbia kimbiakimbia ok::KIMB+RED|kimbiakimbia Word ok::RED+KIMB|kimbiakimbia languages/suffixing-extension-slot-ordering +dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/no EvidencedJointly edge-cases/loader-isactive-breadth rewrote 1 MorphologicalPhonologicalRuleFeature@isActive from "no" to "yes"; jointly activated its sole referencing (ePutDecoy) via ruleFeatures="mprDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 MorphologicalPhonologicalRuleFeature@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (ePutDecoy) via ruleFeatures="mprDecoy", while MorphologicalPhonologicalRuleFeature@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'mprDecoy' was not present in the di...); both jointly (rewrote 1 MorphologicalPhonologicalRuleFeature@isActive from "no" to "yes"; jointly activated its sole referencing (ePutDecoy) via ruleFeatures="mprDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('put': ok::- -> ok::PUT|put) put ok::- Word ok::PUT|put edge-cases/loader-isactive-breadth +dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 1 MorphologicalPhonologicalRuleFeature@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'mprLive' was not present in the dic... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'mprLive' was not present in the dic... edge-cases/loader-isactive-breadth +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/no Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@isActive from "no" to "yes" sibling "yes" of 1 tried: 'kulbubidu': ok::KUL+MB+MA+MREQ|kulbubidu -> ok::- kulbubidu ok::KUL+MB+MA+MREQ|kulbubidu Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/yes Evidenced languages/fusional-realizational-morphology rewrote 3 MorphologicalPhonologicalRuleFeatureGroup@isActive from "yes" to "no" sibling "no" of 1 tried: 'yxpedz': ok::- -> ok::THEMEY+THEMEX+PED+ENDZ|yxpedz yxpedz ok::- Word ok::THEMEY+THEMEX+PED+ENDZ|yxpedz languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/all Evidenced languages/fusional-realizational-morphology rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@matchType from "all" to "any" sibling "any" of 1 tried: 'sodw': ok::- -> ok::SOD+ENDW|sodw sodw ok::- Word ok::SOD+ENDW|sodw languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/any Evidenced languages/fusional-realizational-morphology rewrote 2 MorphologicalPhonologicalRuleFeatureGroup@matchType from "any" to "all" sibling "all" of 1 tried: 'sodh': ok::SOD+ENDH|sodh -> ok::- sodh ok::SOD+ENDH|sodh Word ok::- languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/append Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@outputType from "append" to "overwrite" sibling "overwrite" of 1 tried: 'kulbubidu': ok::KUL+MB+MA+MREQ|kulbubidu -> ok::- kulbubidu ok::KUL+MB+MA+MREQ|kulbubidu Word ok::- edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-overwrite-order-dependence +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/overwrite Evidenced edge-cases/mpr-group-overwrite-without-realizational rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@outputType from "overwrite" to "append" sibling "append" of 1 tried: 'wudofq': ok::- -> ok::THEMEB+THEMEA+DOF+ENDC|wudofq wudofq ok::- Word ok::THEMEB+THEMEA+DOF+ENDC|wudofq edge-cases/mpr-group-overwrite-without-realizational,edge-cases/mpr-overwrite-order-dependence,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:enum/MorphologicalRule/blockable/false Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphologicalRule@blockable from "false" to "true" sibling "true" of 1 tried: 'bakgi': ok::VAK+UNBLK|bakgi -> ok::- bakgi ok::VAK+UNBLK|bakgi Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/MorphologicalRule/isActive/no Evidenced edge-cases/loader-isactive-breadth rewrote 2 MorphologicalRule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'qokul': ok::- -> ok::QO+KUL|qokul qokul ok::- Word ok::QO+KUL|qokul edge-cases/loader-isactive-breadth +dtd:enum/MorphologicalRule/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 3 MorphologicalRule@isActive from "yes" to "no" sibling "no" of 1 tried: 'takul': ok::TA+KUL|takul -> ok::- takul ok::TA+KUL|takul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/MorphologicalRule/multipleApplication/0 Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphologicalRule@multipleApplication from "0" to "1" sibling "1" of 9 tried: 'kulba': ok::- -> ok::KUL+NEVER|kulba kulba ok::- Word ok::KUL+NEVER|kulba edge-cases/morphotactic-attribute-breadth +dtd:enum/MorphologicalRule/multipleApplication/2 Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 MorphologicalRule@multipleApplication from "2" to "0" sibling "0" of 9 tried: 'kulde': ok::KUL+TWICE|kulde -> ok::- kulde ok::KUL+TWICE|kulde Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/MorphologicalRule/partial/true Evidenced edge-cases/morphotactic-attribute-breadth rewrote 2 MorphologicalRule@partial from "true" to "false" sibling "false" of 1 tried: 'pogliti': ok::POG+POGAFX+PO|pogliti -> ok::- pogliti ok::POG+POGAFX+PO|pogliti Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/MorphologicalSubrule/isActive/no RequiredByLoader edge-cases/loader-isactive-breadth rewrote 2 MorphologicalSubrule@isActive from "no" to "yes" sibling "yes" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncDecoy' was not present in the dic... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncDecoy' was not present in the dic... edge-cases/loader-isactive-breadth +dtd:enum/MorphologicalSubrule/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 1 MorphologicalSubrule@isActive from "yes" to "no" sibling "no" of 1 tried: 'takul': ok::TA+KUL|takul -> ok::- takul ok::TA+KUL|takul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/PhoneticTemplate/finalBoundaryCondition/true Evidenced edge-cases/right-to-left-anchor-environment rewrote 1 PhoneticTemplate@finalBoundaryCondition from "true" to "false" sibling "false" of 1 tried: 'aae': ok::ROOT1|aae -> ok::- aae ok::ROOT1|aae Word ok::- edge-cases/right-to-left-anchor-environment +dtd:enum/PhoneticTemplate/initialBoundaryCondition/true Evidenced languages/suffixing-vowel-harmony rewrote 1 PhoneticTemplate@initialBoundaryCondition from "true" to "false" sibling "false" of 1 tried: 'kutagida': ok::KUTAK+PAST|kutagida -> ok::- kutagida ok::KUTAK+PAST|kutagida Word ok::- languages/suffixing-vowel-harmony,languages/templatic-root-modification +dtd:enum/PhonologicalFeatureSystem/isActive/no RequiredByLoader edge-cases/loader-isactive rewrote 1 PhonologicalFeatureSystem@isActive from "no" to "yes" sibling "yes" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element at System.Lin... kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element at System.Lin... edge-cases/loader-isactive +dtd:enum/PhonologicalRule/isActive/no RequiredByLoader edge-cases/feature-system-breadth rewrote 4 PhonologicalRule@isActive from "no" to "yes" sibling "yes" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'featDecoy' could not be found. (Parameter 'id') at SIL.Ma... ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'featDecoy' could not be found. (Parameter 'id') at SIL.Ma... edge-cases/feature-system-breadth +dtd:enum/PhonologicalRule/multipleApplicationOrder/rightToLeftIterative Evidenced edge-cases/right-to-left-anchor-environment rewrote 2 PhonologicalRule@multipleApplicationOrder from "rightToLeftIterative" to "leftToRightIterative" sibling "leftToRightIterative" of 2 tried: 'eeae': ok::ROOT3|eeae -> ok::- eeae ok::ROOT3|eeae Word ok::- edge-cases/right-to-left-anchor-environment +dtd:enum/PhonologicalRule/multipleApplicationOrder/simultaneous Evidenced languages/templatic-root-modification rewrote 2 PhonologicalRule@multipleApplicationOrder from "simultaneous" to "leftToRightIterative" sibling "leftToRightIterative" of 2 tried: 'gigugu': ok::FEEDSIM|gigugu -> ok::- gigugu ok::FEEDSIM|gigugu Word ok::- languages/templatic-root-modification +dtd:enum/PhonologicalSubrule/isActive/no Evidenced edge-cases/feature-system-breadth rewrote 1 PhonologicalSubrule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'at': ok::AT|at -> ok::- at ok::AT|at Word ok::- edge-cases/feature-system-breadth +dtd:enum/RealizationalRule/blockable/false Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 RealizationalRule@blockable from "false" to "true" sibling "true" of 1 tried: 'simru': ok::SIM+REAL|simru -> ok::- simru ok::SIM+REAL|simru Word ok::- edge-cases/morphotactic-attribute-breadth +dtd:enum/RealizationalRule/isActive/no Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 RealizationalRule@isActive from "no" to "yes" sibling "yes" of 1 tried: 'kulsi': ok::- -> ok::KUL+RDEC|kulsi kulsi ok::- Word ok::KUL+RDEC|kulsi edge-cases/morphotactic-attribute-breadth +dtd:enum/SegmentDefinition/isActive/no Evidenced edge-cases/loader-isactive-breadth rewrote 1 SegmentDefinition@isActive from "no" to "yes" sibling "yes" of 1 tried: 'zal': SKIPPED::- -> ok::- zal SKIPPED::- Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/SegmentDefinition/isActive/yes RequiredByLoader edge-cases/loader-isactive-breadth rewrote 10 SegmentDefinition@isActive from "yes" to "no" sibling "no" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, ta, contains an undefined phone... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, ta, contains an undefined phone... edge-cases/loader-isactive-breadth +dtd:enum/SegmentNaturalClass/isActive/no EvidencedJointly edge-cases/feature-system-breadth rewrote 1 SegmentNaturalClass@isActive from "no" to "yes"; jointly activated its sole referencing (prDecNc) via naturalClass="ncDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 SegmentNaturalClass@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (prDecNc) via naturalClass="ncDecoy", while SegmentNaturalClass@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncDecoy' was not present in the dic...); both jointly (rewrote 1 SegmentNaturalClass@isActive from "no" to "yes"; jointly activated its sole referencing (prDecNc) via naturalClass="ncDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('sal': ok::SAL|sal -> ok::-) sal ok::SAL|sal Word ok::- edge-cases/feature-system-breadth +dtd:enum/Slot/isActive/no Evidenced edge-cases/loader-isactive-breadth rewrote 2 Slot@isActive from "no" to "yes" sibling "yes" of 1 tried: 'qekul': ok::- -> ok::QE+KUL|qekul qekul ok::- Word ok::QE+KUL|qekul edge-cases/loader-isactive-breadth +dtd:enum/Slot/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 3 Slot@isActive from "yes" to "no" sibling "no" of 1 tried: 'takul': ok::TA+KUL|takul -> ok::- takul ok::TA+KUL|takul Word ok::- edge-cases/loader-isactive-breadth +dtd:enum/Slot/optional/true Evidenced edge-cases/diacritic-segments rewrote 1 Slot@optional from "true" to "false" sibling "false" of 1 tried: 'año': ok::YEAR|año -> ok::- año ok::YEAR|año Word ok::- edge-cases/diacritic-segments,edge-cases/loader-isactive-breadth,edge-cases/morphotactic-attribute-breadth,languages/prefixal-discontinuous-slot-dependency,languages/suffixing-evidential-adjacency-chain,languages/suffixing-extension-slot-ordering,languages/suffixing-vowel-harmony +dtd:enum/Stratum/cyclicity/cyclic Unobservable edge-cases/morphotactic-attribute-breadth tried 1 declared sibling(s): "noncyclic" none produced a delta: "noncyclic" (Unobservable) - - None - edge-cases/morphotactic-attribute-breadth +dtd:enum/Stratum/isActive/no RequiredByLoader edge-cases/loader-isactive-breadth rewrote 2 Stratum@isActive from "no" to "yes" sibling "yes" of 1 tried (RequiredByLoader; no sibling produced word-level evidence): InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableDecoy' was not present in the ... kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableDecoy' was not present in the ... edge-cases/loader-isactive-breadth +dtd:enum/Stratum/isActive/yes Evidenced edge-cases/loader-isactive-breadth rewrote 1 Stratum@isActive from "yes" to "no" sibling "no" of 1 tried: 'kul': ok::KUL|kul -> threw::NullReferenceException kul ok::KUL|kul Word threw::NullReferenceException edge-cases/loader-isactive-breadth +dtd:enum/Stratum/morphologicalRuleOrder/linear Evidenced edge-cases/feature-gating-breadth rewrote 1 Stratum@morphologicalRuleOrder from "linear" to "unordered" sibling "unordered" of 1 tried: 'kalidka': ok::- -> ok::KAL+PAST+AGR|kalidka kalidka ok::- Word ok::KAL+PAST+AGR|kalidka edge-cases/feature-gating-breadth,edge-cases/mpr-group-overwrite-without-realizational,languages/fusional-realizational-morphology,languages/suffixing-extension-slot-ordering +dtd:enum/Stratum/morphologicalRuleOrder/unordered Evidenced edge-cases/morphotactic-attribute-breadth rewrote 1 Stratum@morphologicalRuleOrder from "unordered" to "linear" sibling "linear" of 1 tried: 'pogliti': ok::POG+POGAFX+PO|pogliti -> ok::- pogliti ok::POG+POGAFX+PO|pogliti Word ok::- edge-cases/morphotactic-attribute-breadth,edge-cases/mpr-overwrite-order-dependence,edge-cases/strrep-identity,languages/fusional-realizational-morphology,languages/polysynthetic-stratal-derivation-chain +dtd:enum/Stratum/phonologicalRuleOrder/simultaneous Unobservable edge-cases/morphotactic-attribute-breadth tried 1 declared sibling(s): "linear" none produced a delta: "linear" (Unobservable) - - None - edge-cases/morphotactic-attribute-breadth +dtd:enum/SymbolicFeature/isActive/no EvidencedJointly edge-cases/feature-system-breadth rewrote 1 SymbolicFeature@isActive from "no" to "yes"; jointly activated its sole referencing (prDecFeat) via phonologicalFeature="featDecoy", itself rewritten from isActive="no" to "yes" three-run: target alone (rewrote 1 SymbolicFeature@isActive from "no" to "yes") -> Unobservable (all 18 word(s) unchanged); partner alone (activated only its referencing (prDecFeat) via phonologicalFeature="featDecoy", while SymbolicFeature@isActive stayed "no") -> RequiredByLoader (InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'featDecoy' could not be found. (Parameter 'id') at SIL.Ma...); both jointly (rewrote 1 SymbolicFeature@isActive from "no" to "yes"; jointly activated its sole referencing (prDecFeat) via phonologicalFeature="featDecoy", itself rewritten from isActive="no" to "yes") -> Evidenced ('ik': ok::AK|ik -> ok::-) ik ok::AK|ik Word ok::- edge-cases/feature-system-breadth +dtd:enum/VariableFeature/name/%CE%B1 Evidenced edge-cases/alpha-variable-name-collision rewrote 1 VariableFeature@name from "α" to "β" sibling "β" of 23 tried: 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision +dtd:enum/VariableFeature/name/%CE%B2 Evidenced edge-cases/alpha-variable-name-collision rewrote 1 VariableFeature@name from "β" to "α" sibling "α" of 23 tried: 'au': ok::- -> ok::AU|au au ok::- Word ok::AU|au edge-cases/alpha-variable-name-collision diff --git a/conformance/semantic-coverage-evidence.tsv b/conformance/semantic-coverage-evidence.tsv new file mode 100644 index 000000000..3b291d64f --- /dev/null +++ b/conformance/semantic-coverage-evidence.tsv @@ -0,0 +1,241 @@ +# GENERATED. One line per coverage item resolved by evidence -- an item resolved by +# proof instead lives in semantic-coverage-proofs.tsv, never here. Columns are +# explicit so CoverageCompletenessGate reads structure, never Delta's free-text prose. +# counterexample_kind is Word or LoadFailure and the two are never summed into one +# count -- see CoverageCompletenessGate. Absent fields are "-". +item_id kind fixture example_word example_outcome counterexample_kind counterexample_outcome mutation verdict +dtd:element/AffixTemplate Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AffixTemplates' has incomplete content... removed 1 element(s) RequiredByDtd +dtd:element/AffixTemplates Surface edge-cases/loader-isactive-breadth takul ok::TA+KUL|takul Word ok::- removed 1 element(s) Evidenced +dtd:element/Allomorph Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Allomorphs' has incomplete content. Li... removed 1 element(s) RequiredByDtd +dtd:element/AllomorphCoOccurrenceRule Surface edge-cases/morphotactic-attribute-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AllomorphCoOccurrenceRules' has incomp... removed 6 element(s) RequiredByDtd +dtd:element/AllomorphCoOccurrenceRules Surface edge-cases/morphotactic-attribute-breadth sol ok::- Word ok::SOL|sol removed 1 element(s) Evidenced +dtd:element/Allomorphs Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LexicalEntry' has invalid child elemen... removed 1 element(s) RequiredByDtd +dtd:element/AlphaVariable Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AlphaVariables' has incomplete content... removed 4 element(s) RequiredByDtd +dtd:element/AlphaVariables Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au removed 4 element(s) Evidenced +dtd:element/AssignedFootFeatures Surface edge-cases/compounding-breadth kati ok::- Word ok::KA+TI|kati removed 6 element(s) Evidenced +dtd:element/AssignedHeadFeatures Surface edge-cases/compounding-breadth kaki ok::- Word ok::KA+KI|kaki removed 6 element(s) Evidenced +dtd:element/BoundaryDefinition Surface edge-cases/loader-isactive kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'BoundaryDefinitions' has incomplete co... removed 1 element(s) RequiredByDtd +dtd:element/BoundaryDefinitions Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, +, contains an undefined phonem... removed 1 element(s) RequiredByDtd +dtd:element/CharacterDefinitionTable Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'N... removed 1 element(s) RequiredByDtd +dtd:element/ComplexFeature Surface edge-cases/feature-system-breadth ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'cfDecoy'. at System.Xml.Xml... removed 2 element(s) RequiredByDtd +dtd:element/CompoundingRule Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'crDecoy'. at System.Xml.Xml... removed 4 element(s) RequiredByDtd +dtd:element/CompoundingSubrule Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrules' has incomplete co... removed 4 element(s) RequiredByDtd +dtd:element/CompoundingSubrules Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingRule' has invalid child ele... removed 4 element(s) RequiredByDtd +dtd:element/CopyFromInput Surface edge-cases/compounding-breadth katu ok::KA+TU|katu Word ok::- removed 8 element(s) Evidenced +dtd:element/Environment Surface edge-cases/mpr-gated-exception tulik ok::TULIK|tulik Word ok::- removed 3 element(s) Evidenced +dtd:element/ExcludedEnvironments Surface edge-cases/feature-system-breadth salk ok::- Word ok::SAL+SUF|salk removed 1 element(s) Evidenced +dtd:element/Families Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'famDecoy'. at System.Xml.Xm... removed 1 element(s) RequiredByDtd +dtd:element/Family Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'famDecoy'. at System.Xml.Xm... removed 2 element(s) RequiredByDtd +dtd:element/FeatureNaturalClass Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'NaturalClasses' has incomplete content... removed 1 element(s) RequiredByDtd +dtd:element/FeatureValue Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|[iyau][iyau] removed 8 element(s) Evidenced +dtd:element/FootFeatures Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'clsB'. at System.Xml.XmlVal... removed 1 element(s) RequiredByDtd +dtd:element/HeadFeatures Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'numSg'. at System.Xml.XmlVa... removed 1 element(s) RequiredByDtd +dtd:element/HeadMorphologicalInput Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has invalid child ... removed 4 element(s) RequiredByDtd +dtd:element/HeadRequiredFootFeatures Surface edge-cases/compounding-breadth patu ok::- Word ok::PA+TU|patu removed 2 element(s) Evidenced +dtd:element/HeadRequiredHeadFeatures Surface edge-cases/compounding-breadth kutu ok::- Word ok::KU+TU|kutu removed 2 element(s) Evidenced +dtd:element/HermitCrabInput Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Token EndDocument in state Document would result in an invalid XML document. removed 1 element(s) RequiredByDtd +dtd:element/InsertSegments Surface edge-cases/diacritic-segments año ok::YEAR|año Word ok::YEAR+DIM|año;YEAR+PL|año;YEAR|año removed 2 element(s) Evidenced +dtd:element/InsertSimpleContext Surface languages/templatic-root-modification spr ok::SPR|spr Word ok::SPR+FORMII|spr;SPR|spr removed 1 element(s) Evidenced +dtd:element/Language Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'HermitCrabInput' has incomplete conten... removed 1 element(s) RequiredByDtd +dtd:element/LeftEnvironment Surface edge-cases/diacritic-segments añota ok::- Word ok::YEAR+DIM|añota removed 1 element(s) Evidenced +dtd:element/LexicalEntries Surface edge-cases/alpha-variable-name-collision ia ok::AU|ia Word ok::- removed 1 element(s) Evidenced +dtd:element/LexicalEntry Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LexicalEntries' has incomplete content... removed 1 element(s) RequiredByDtd +dtd:element/MetathesisRule Surface edge-cases/feature-system-breadth ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'mtDecoy'. at System.Xml.Xml... removed 3 element(s) RequiredByDtd +dtd:element/ModifyFromInput Surface edge-cases/process-morphology-in-place-mutation a ok::AROOT|a;ROOT+ABLAUT|a Word ok::AROOT|a removed 1 element(s) Evidenced +dtd:element/MorphemeCoOccurrenceRule Surface edge-cases/morphotactic-attribute-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphemeCoOccurrenceRules' has incompl... removed 2 element(s) RequiredByDtd +dtd:element/MorphemeCoOccurrenceRules Surface languages/suffixing-evidential-adjacency-chain walakntan ok::- Word ok::WALAK+3SG+ASSUM|walakntan removed 1 element(s) Evidenced +dtd:element/MorphemeId Surface edge-cases/alpha-variable-name-collision ia ok::AU|ia Word ok::|ia removed 1 element(s) Evidenced +dtd:element/MorphologicalInput Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalSubrule' has invalid chil... removed 2 element(s) RequiredByDtd +dtd:element/MorphologicalOutput Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has incomplete con... removed 4 element(s) RequiredByDtd +dtd:element/MorphologicalPhonologicalRuleFeature Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalPhonologicalRuleFeatures'... removed 2 element(s) RequiredByDtd +dtd:element/MorphologicalPhonologicalRuleFeatureGroup Surface edge-cases/mpr-group-overwrite-without-realizational wudofq ok::- Word ok::THEMEB+THEMEA+DOF+ENDC|wudofq removed 1 element(s) Evidenced +dtd:element/MorphologicalPhonologicalRuleFeatures Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'mprDecoy'. at System.Xml.Xm... removed 1 element(s) RequiredByDtd +dtd:element/MorphologicalRule Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'rDim'. at System.Xml.XmlVal... removed 2 element(s) RequiredByDtd +dtd:element/MorphologicalRuleDefinitions Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'crDecoy'. at System.Xml.Xml... removed 1 element(s) RequiredByDtd +dtd:element/MorphologicalSubrule Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalSubrules' has incomplete ... removed 2 element(s) RequiredByDtd +dtd:element/MorphologicalSubrules Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MorphologicalRule' has invalid child e... removed 2 element(s) RequiredByDtd +dtd:element/Name Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'P... removed 8 element(s) RequiredByDtd +dtd:element/NaturalClasses Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'ncVowel'. at System.Xml.Xml... removed 1 element(s) RequiredByDtd +dtd:element/NonHeadMorphologicalInput Surface edge-cases/compounding-breadth ka ok::KA|ka LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CompoundingSubrule' has invalid child ... removed 4 element(s) RequiredByDtd +dtd:element/NonHeadRequiredFootFeatures Surface edge-cases/compounding-breadth kati ok::- Word ok::KA+TI|kati removed 2 element(s) Evidenced +dtd:element/NonHeadRequiredHeadFeatures Surface edge-cases/compounding-breadth kaki ok::- Word ok::KA+KI|kaki removed 2 element(s) Evidenced +dtd:element/OptionalSegmentSequence Surface edge-cases/compounding-breadth katu ok::KA+TU|katu Word ok::- removed 4 element(s) Evidenced +dtd:element/OutputFootFeatures Surface edge-cases/feature-gating-breadth nalnomu ok::NAL+LOUD+EMPH|nalnomu Word ok::- removed 2 element(s) Evidenced +dtd:element/OutputHeadFeatures Surface edge-cases/stem-name-restricted-root-allomorph kapom ok::ROOT+PERS1|kapom Word ok::- removed 2 element(s) Evidenced +dtd:element/PartOfSpeech Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PartsOfSpeech' has incomplete content.... removed 1 element(s) RequiredByDtd +dtd:element/PartsOfSpeech Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has invalid child element 'P... removed 1 element(s) RequiredByDtd +dtd:element/PhoneticInput Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalRule' has invalid child el... removed 1 element(s) RequiredByDtd +dtd:element/PhoneticOutput Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalSubrule' has incomplete co... removed 1 element(s) RequiredByDtd +dtd:element/PhoneticSequence Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au removed 2 element(s) Evidenced +dtd:element/PhoneticShape Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Allomorph' has incomplete content. Lis... removed 1 element(s) RequiredByDtd +dtd:element/PhoneticTemplate Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'LeftEnvironment' has incomplete conten... removed 1 element(s) RequiredByDtd +dtd:element/PhonologicalFeatureSystem Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'featRound'. at System.Xml.X... removed 1 element(s) RequiredByDtd +dtd:element/PhonologicalRule Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'prDoubleAlpha'. at System.X... removed 1 element(s) RequiredByDtd +dtd:element/PhonologicalRuleDefinitions Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'prDoubleAlpha'. at System.X... removed 1 element(s) RequiredByDtd +dtd:element/PhonologicalSubrule Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalSubrules' has incomplete c... removed 1 element(s) RequiredByDtd +dtd:element/PhonologicalSubrules Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'PhonologicalRule' has incomplete conte... removed 1 element(s) RequiredByDtd +dtd:element/Property Surface edge-cases/feature-gating-breadth kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Properties' has incomplete content. Li... removed 1 element(s) RequiredByDtd +dtd:element/RealizationalFeatures Surface edge-cases/feature-gating-breadth kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'RealizationalFeatures' has incomplete ... emptied 1 element(s) (1 child node(s) removed) rather than deleting them, in place of a deletion that did not terminate RequiredByDtd +dtd:element/RealizationalRule Surface edge-cases/feature-gating-breadth kal ok::KAL|kal LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'rrPast'. at System.Xml.XmlV... removed 1 element(s) RequiredByDtd +dtd:element/Region Surface edge-cases/stem-name-restricted-root-allomorph tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Regions' has incomplete content. List ... removed 1 element(s) RequiredByDtd +dtd:element/Regions Surface edge-cases/stem-name-restricted-root-allomorph tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'StemName' has incomplete content. List... removed 1 element(s) RequiredByDtd +dtd:element/Representation Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Representations' has incomplete conten... removed 4 element(s) RequiredByDtd +dtd:element/Representations Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SegmentDefinition' has invalid child e... removed 4 element(s) RequiredByDtd +dtd:element/RequiredEnvironments Surface edge-cases/diacritic-segments añota ok::- Word ok::YEAR+DIM|añota removed 1 element(s) Evidenced +dtd:element/RequiredFootFeatures Surface edge-cases/feature-gating-breadth molka ok::- Word ok::MOL+AGR|molka removed 2 element(s) Evidenced +dtd:element/RequiredHeadFeatures Surface edge-cases/feature-gating-breadth tunka ok::- Word ok::TUN+AGR|tunka removed 1 element(s) Evidenced +dtd:element/RightEnvironment Surface edge-cases/disjunctive-recheck wak ok::|wak Word ok::- removed 1 element(s) Evidenced +dtd:element/Segment Surface edge-cases/diacritic-segments añota ok::- Word ok::YEAR+DIM|añota removed 4 element(s) Evidenced +dtd:element/SegmentDefinition Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SegmentDefinitions' has incomplete con... removed 4 element(s) RequiredByDtd +dtd:element/SegmentDefinitions Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'CharacterDefinitionTable' has incomple... removed 1 element(s) RequiredByDtd +dtd:element/SegmentNaturalClass Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'NaturalClasses' has incomplete content... removed 1 element(s) RequiredByDtd +dtd:element/Segments Surface edge-cases/strrep-identity ndpat ok::++|[(^0)∅]?+?nd+?pat;++|nd+?[(^0)∅]?+?pat;+|nd+?pat Word ok::- removed 1 element(s) Evidenced +dtd:element/SimpleContext Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au removed 4 element(s) Evidenced +dtd:element/Slot Surface edge-cases/diacritic-segments año ok::YEAR|año LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'AffixTemplate' has incomplete content.... removed 1 element(s) RequiredByDtd +dtd:element/StemName Surface edge-cases/stem-name-restricted-root-allomorph tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'StemNames' has incomplete content. Lis... removed 1 element(s) RequiredByDtd +dtd:element/StemNames Surface edge-cases/stem-name-restricted-root-allomorph tam ok::ROOT|tam LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'snP1'. at System.Xml.XmlVal... removed 1 element(s) RequiredByDtd +dtd:element/Strata Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Language' has incomplete content. List... removed 1 element(s) RequiredByDtd +dtd:element/Stratum Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Strata' has incomplete content. List o... removed 1 element(s) RequiredByDtd +dtd:element/StructuralDescription Surface edge-cases/feature-system-breadth ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'MetathesisRule' has incomplete content... removed 3 element(s) RequiredByDtd +dtd:element/Symbol Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'Symbols' has incomplete content. List ... removed 4 element(s) RequiredByDtd +dtd:element/SymbolicFeature Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'featRound'. at System.Xml.X... removed 2 element(s) RequiredByDtd +dtd:element/Symbols Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'SymbolicFeature' has incomplete conten... removed 2 element(s) RequiredByDtd +dtd:element/VariableFeature Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaValidationException: The element 'VariableFeatures' has incomplete conte... removed 2 element(s) RequiredByDtd +dtd:element/VariableFeatures Surface edge-cases/alpha-variable-name-collision au ok::- LoadFailure InvalidOperationException: Unhandled exception. System.Xml.Schema.XmlSchemaException: Reference to undeclared ID is 'varRound'. at System.Xml.Xm... removed 1 element(s) RequiredByDtd +dtd:enum/AffixTemplate/final/false Surface edge-cases/morphotactic-attribute-breadth kulpu ok::- Word ok::KUL+NF|kulpu rewrote 1 AffixTemplate@final from "false" to "true" Evidenced +dtd:enum/AffixTemplate/final/true Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul Word ok::- rewrote 1 AffixTemplate@final from "true" to "false" Evidenced +dtd:enum/AffixTemplate/isActive/no Surface edge-cases/loader-isactive-breadth qukul ok::- Word ok::QU+KUL|qukul rewrote 1 AffixTemplate@isActive from "no" to "yes" Evidenced +dtd:enum/AffixTemplate/isActive/yes Surface edge-cases/loader-isactive-breadth takul ok::TA+KUL|takul Word ok::- rewrote 1 AffixTemplate@isActive from "yes" to "no" Evidenced +dtd:enum/Allomorph/isActive/no Surface edge-cases/loader-isactive-breadth kol ok::- Word ok::KUL|kol rewrote 1 Allomorph@isActive from "no" to "yes" Evidenced +dtd:enum/Allomorph/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul Word ok::- rewrote 1 Allomorph@isActive from "yes" to "no" Evidenced +dtd:enum/Allomorph/isBound/false Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul Word ok::- rewrote 1 Allomorph@isBound from "false" to "true" Evidenced +dtd:enum/Allomorph/isBound/true Surface edge-cases/morphotactic-attribute-breadth kur ok::- Word ok::KUL|kur rewrote 1 Allomorph@isBound from "true" to "false" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToLeft Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 1 AllomorphCoOccurrenceRule@adjacency from "adjacentToLeft" to "adjacentToRight" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/adjacency/adjacentToRight Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 1 AllomorphCoOccurrenceRule@adjacency from "adjacentToRight" to "adjacentToLeft" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/adjacency/anywhere Surface languages/suffixing-evidential-adjacency-chain kantancha ok::- Word ok::SING+3SG+CONJ|kantan(ch)a rewrote 1 AllomorphCoOccurrenceRule@adjacency from "anywhere" to "adjacentToLeft" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToLeft Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 2 AllomorphCoOccurrenceRule@adjacency from "somewhereToLeft" to "adjacentToLeft" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/adjacency/somewhereToRight Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 1 AllomorphCoOccurrenceRule@adjacency from "somewhereToRight" to "adjacentToLeft" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/isActive/no Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 1 AllomorphCoOccurrenceRule@isActive from "no" to "yes" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/isActive/yes Surface languages/suffixing-evidential-adjacency-chain kantancha ok::- Word ok::SING+3SG+CONJ|kantan(ch)a rewrote 1 AllomorphCoOccurrenceRule@isActive from "yes" to "no" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/type/exclude Surface languages/suffixing-evidential-adjacency-chain kantay ok::SING+1SG|kantay Word ok::- rewrote 1 AllomorphCoOccurrenceRule@type from "exclude" to "require" Evidenced +dtd:enum/AllomorphCoOccurrenceRule/type/require Surface edge-cases/morphotactic-attribute-breadth sol ok::- Word ok::SOL|sol rewrote 5 AllomorphCoOccurrenceRule@type from "require" to "exclude" Evidenced +dtd:enum/AlphaVariable/polarity/minus Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au rewrote 2 AlphaVariable@polarity from "minus" to "plus" Evidenced +dtd:enum/AlphaVariable/polarity/plus Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au rewrote 2 AlphaVariable@polarity from "plus" to "minus" Evidenced +dtd:enum/BoundaryDefinition/isActive/no Surface edge-cases/loader-isactive-breadth kul= SKIPPED::- Word ok::- rewrote 1 BoundaryDefinition@isActive from "no" to "yes" Evidenced +dtd:enum/BoundaryDefinition/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, +, contains an undefined phonem... rewrote 1 BoundaryDefinition@isActive from "yes" to "no" RequiredByLoader +dtd:enum/CharacterDefinitionTable/isActive/no Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul Word SKIPPED::- rewrote 1 CharacterDefinitionTable@isActive from "no" to "yes"; jointly activated its sole referencing (TableDecoyStratum) via characterDefinitionTable="tableDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/CharacterDefinitionTable/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableLive' was not present in the d... rewrote 1 CharacterDefinitionTable@isActive from "yes" to "no" RequiredByLoader +dtd:enum/ComplexFeature/isActive/no Surface edge-cases/feature-system-breadth tal ok::- Word ok::TAL|tal rewrote 1 ComplexFeature@isActive from "no" to "yes"; jointly activated its sole referencing (eDecCf) via feature="cfDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/CompoundingRule/blockable/false Surface languages/fusional-realizational-morphology corriv ok::BLOCKHEAD+BLOCKNON|cor+?riv Word ok::- rewrote 2 CompoundingRule@blockable from "false" to "true" Evidenced +dtd:enum/CompoundingRule/blockable/true Surface languages/fusional-realizational-morphology genlav ok::- Word ok::GEN+LAV|gen+?lav rewrote 1 CompoundingRule@blockable from "true" to "false" Evidenced +dtd:enum/CompoundingRule/isActive/no Surface edge-cases/compounding-breadth kaptu ok::- Word ok::KA+TU|kaptu rewrote 1 CompoundingRule@isActive from "no" to "yes" Evidenced +dtd:enum/CompoundingRule/multipleApplication/0 Surface edge-cases/compounding-breadth kamtu ok::- Word ok::KA+TU|kamtu rewrote 1 CompoundingRule@multipleApplication from "0" to "1" Evidenced +dtd:enum/CompoundingSubrule/isActive/no Surface edge-cases/compounding-breadth kaitu ok::- Word ok::KA+TU|kaitu rewrote 1 CompoundingSubrule@isActive from "no" to "yes" Evidenced +dtd:enum/Family/isActive/no Surface edge-cases/loader-isactive-breadth tup ok::- Word ok::TUP|tup rewrote 1 Family@isActive from "no" to "yes"; jointly activated its sole referencing (eTupDecoy) via family="famDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/Family/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'famLive' was not present in the dic... rewrote 1 Family@isActive from "yes" to "no" RequiredByLoader +dtd:enum/FeatureNaturalClass/isActive/no Surface edge-cases/feature-system-breadth ik ok::AK|ik Word ok::- rewrote 1 FeatureNaturalClass@isActive from "no" to "yes"; jointly activated its sole referencing (prDecFnc) via naturalClass="ncFDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/FeatureNaturalClass/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncAny' was not present in the dicti... rewrote 1 FeatureNaturalClass@isActive from "yes" to "no" RequiredByLoader +dtd:enum/FeatureValue/isActive/no Surface edge-cases/feature-system-breadth ts ok::TS|ts Word ok::- rewrote 1 FeatureValue@isActive from "no" to "yes" Evidenced +dtd:enum/Language/isActive/no Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element at System.Lin... rewrote 1 Language@isActive from "no" to "yes" RequiredByLoader +dtd:enum/Language/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains no matching element at System.Linq.ThrowHelp... rewrote 1 Language@isActive from "yes" to "no" RequiredByLoader +dtd:enum/LexicalEntry/isActive/no Surface edge-cases/feature-system-breadth ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'cfDecoy' could not be found. (Parameter 'id') at SIL.Mach... rewrote 1 LexicalEntry@isActive from "no" to "yes" RequiredByLoader +dtd:enum/LexicalEntry/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul Word ok::- rewrote 1 LexicalEntry@isActive from "yes" to "no" Evidenced +dtd:enum/LexicalEntry/partial/false Surface edge-cases/loader-isactive-breadth takul ok::TA+KUL|takul Word ok::- rewrote 1 LexicalEntry@partial from "false" to "true" Evidenced +dtd:enum/LexicalEntry/partial/true Surface edge-cases/morphotactic-attribute-breadth napmo ok::- Word ok::NAP+PART|napmo rewrote 1 LexicalEntry@partial from "true" to "false" Evidenced +dtd:enum/MetathesisRule/isActive/no Surface edge-cases/feature-system-breadth ka ok::KA|ka Word threw::InvalidOperationException rewrote 1 MetathesisRule@isActive from "no" to "yes" Evidenced +dtd:enum/MetathesisRule/multipleApplicationOrder/rightToLeftIterative Surface edge-cases/feature-system-breadth tlk ok::TKL|tlk Word ok::- rewrote 2 MetathesisRule@multipleApplicationOrder from "rightToLeftIterative" to "leftToRightIterative" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToLeft Surface languages/suffixing-evidential-adjacency-chain walakniwas ok::WALAK+1SG+MIR|walakniwas Word ok::- rewrote 1 MorphemeCoOccurrenceRule@adjacency from "adjacentToLeft" to "adjacentToRight" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/adjacency/adjacentToRight Surface languages/suffixing-evidential-adjacency-chain sipulupami ok::SIPU+2PL+DIR|sipulupami Word ok::- rewrote 1 MorphemeCoOccurrenceRule@adjacency from "adjacentToRight" to "adjacentToLeft" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/adjacency/anywhere Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 2 MorphemeCoOccurrenceRule@adjacency from "anywhere" to "adjacentToLeft" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToLeft Surface languages/suffixing-evidential-adjacency-chain walaknichiktan ok::WALAK+1SG+PL+ASSUM|walakni(ch)iktan Word ok::- rewrote 1 MorphemeCoOccurrenceRule@adjacency from "somewhereToLeft" to "adjacentToLeft" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/adjacency/somewhereToRight Surface languages/suffixing-evidential-adjacency-chain siputukumi ok::SIPU+1PL.INCL+DIR|siputukumi Word ok::- rewrote 1 MorphemeCoOccurrenceRule@adjacency from "somewhereToRight" to "adjacentToLeft" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/isActive/no Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 1 MorphemeCoOccurrenceRule@isActive from "no" to "yes" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/isActive/yes Surface languages/suffixing-evidential-adjacency-chain walakntan ok::- Word ok::WALAK+3SG+ASSUM|walakntan rewrote 6 MorphemeCoOccurrenceRule@isActive from "yes" to "no" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/type/exclude Surface languages/suffixing-evidential-adjacency-chain sipuncha ok::SIPU+3SG+CONJ|sipun(ch)a Word ok::- rewrote 2 MorphemeCoOccurrenceRule@type from "exclude" to "require" Evidenced +dtd:enum/MorphemeCoOccurrenceRule/type/require Surface edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- rewrote 1 MorphemeCoOccurrenceRule@type from "require" to "exclude" Evidenced +dtd:enum/MorphologicalOutput/redupMorphType/prefix Surface languages/metathesis-phase-isolation tulatula ok::RDPL+TULA|tulatula Word ok::TULA+RDPL|tulatula rewrote 2 MorphologicalOutput@redupMorphType from "prefix" to "implicit" Evidenced +dtd:enum/MorphologicalOutput/redupMorphType/suffix Surface languages/suffixing-extension-slot-ordering kimbiakimbia ok::KIMB+RED|kimbiakimbia Word ok::RED+KIMB|kimbiakimbia rewrote 1 MorphologicalOutput@redupMorphType from "suffix" to "prefix" Evidenced +dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/no Surface edge-cases/loader-isactive-breadth put ok::- Word ok::PUT|put rewrote 1 MorphologicalPhonologicalRuleFeature@isActive from "no" to "yes"; jointly activated its sole referencing (ePutDecoy) via ruleFeatures="mprDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'mprLive' was not present in the dic... rewrote 1 MorphologicalPhonologicalRuleFeature@isActive from "yes" to "no" RequiredByLoader +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/no Surface edge-cases/morphotactic-attribute-breadth kulbubidu ok::KUL+MB+MA+MREQ|kulbubidu Word ok::- rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@isActive from "no" to "yes" Evidenced +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/yes Surface languages/fusional-realizational-morphology yxpedz ok::- Word ok::THEMEY+THEMEX+PED+ENDZ|yxpedz rewrote 3 MorphologicalPhonologicalRuleFeatureGroup@isActive from "yes" to "no" Evidenced +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/all Surface languages/fusional-realizational-morphology sodw ok::- Word ok::SOD+ENDW|sodw rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@matchType from "all" to "any" Evidenced +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/matchType/any Surface languages/fusional-realizational-morphology sodh ok::SOD+ENDH|sodh Word ok::- rewrote 2 MorphologicalPhonologicalRuleFeatureGroup@matchType from "any" to "all" Evidenced +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/append Surface edge-cases/morphotactic-attribute-breadth kulbubidu ok::KUL+MB+MA+MREQ|kulbubidu Word ok::- rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@outputType from "append" to "overwrite" Evidenced +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/outputType/overwrite Surface edge-cases/mpr-group-overwrite-without-realizational wudofq ok::- Word ok::THEMEB+THEMEA+DOF+ENDC|wudofq rewrote 1 MorphologicalPhonologicalRuleFeatureGroup@outputType from "overwrite" to "append" Evidenced +dtd:enum/MorphologicalRule/blockable/false Surface edge-cases/morphotactic-attribute-breadth bakgi ok::VAK+UNBLK|bakgi Word ok::- rewrote 1 MorphologicalRule@blockable from "false" to "true" Evidenced +dtd:enum/MorphologicalRule/isActive/no Surface edge-cases/loader-isactive-breadth qokul ok::- Word ok::QO+KUL|qokul rewrote 2 MorphologicalRule@isActive from "no" to "yes" Evidenced +dtd:enum/MorphologicalRule/isActive/yes Surface edge-cases/loader-isactive-breadth takul ok::TA+KUL|takul Word ok::- rewrote 3 MorphologicalRule@isActive from "yes" to "no" Evidenced +dtd:enum/MorphologicalRule/multipleApplication/0 Surface edge-cases/morphotactic-attribute-breadth kulba ok::- Word ok::KUL+NEVER|kulba rewrote 1 MorphologicalRule@multipleApplication from "0" to "1" Evidenced +dtd:enum/MorphologicalRule/multipleApplication/2 Surface edge-cases/morphotactic-attribute-breadth kulde ok::KUL+TWICE|kulde Word ok::- rewrote 1 MorphologicalRule@multipleApplication from "2" to "0" Evidenced +dtd:enum/MorphologicalRule/partial/true Surface edge-cases/morphotactic-attribute-breadth pogliti ok::POG+POGAFX+PO|pogliti Word ok::- rewrote 2 MorphologicalRule@partial from "true" to "false" Evidenced +dtd:enum/MorphologicalSubrule/isActive/no Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'ncDecoy' was not present in the dic... rewrote 2 MorphologicalSubrule@isActive from "no" to "yes" RequiredByLoader +dtd:enum/MorphologicalSubrule/isActive/yes Surface edge-cases/loader-isactive-breadth takul ok::TA+KUL|takul Word ok::- rewrote 1 MorphologicalSubrule@isActive from "yes" to "no" Evidenced +dtd:enum/PhoneticTemplate/finalBoundaryCondition/true Surface edge-cases/right-to-left-anchor-environment aae ok::ROOT1|aae Word ok::- rewrote 1 PhoneticTemplate@finalBoundaryCondition from "true" to "false" Evidenced +dtd:enum/PhoneticTemplate/initialBoundaryCondition/true Surface languages/suffixing-vowel-harmony kutagida ok::KUTAK+PAST|kutagida Word ok::- rewrote 1 PhoneticTemplate@initialBoundaryCondition from "true" to "false" Evidenced +dtd:enum/PhonologicalFeatureSystem/isActive/no Surface edge-cases/loader-isactive kat ok::|kat LoadFailure InvalidOperationException: Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element at System.Lin... rewrote 1 PhonologicalFeatureSystem@isActive from "no" to "yes" RequiredByLoader +dtd:enum/PhonologicalRule/isActive/no Surface edge-cases/feature-system-breadth ik ok::AK|ik LoadFailure InvalidOperationException: Unhandled exception. System.ArgumentException: The feature 'featDecoy' could not be found. (Parameter 'id') at SIL.Ma... rewrote 4 PhonologicalRule@isActive from "no" to "yes" RequiredByLoader +dtd:enum/PhonologicalRule/multipleApplicationOrder/rightToLeftIterative Surface edge-cases/right-to-left-anchor-environment eeae ok::ROOT3|eeae Word ok::- rewrote 2 PhonologicalRule@multipleApplicationOrder from "rightToLeftIterative" to "leftToRightIterative" Evidenced +dtd:enum/PhonologicalRule/multipleApplicationOrder/simultaneous Surface languages/templatic-root-modification gigugu ok::FEEDSIM|gigugu Word ok::- rewrote 2 PhonologicalRule@multipleApplicationOrder from "simultaneous" to "leftToRightIterative" Evidenced +dtd:enum/PhonologicalSubrule/isActive/no Surface edge-cases/feature-system-breadth at ok::AT|at Word ok::- rewrote 1 PhonologicalSubrule@isActive from "no" to "yes" Evidenced +dtd:enum/RealizationalRule/blockable/false Surface edge-cases/morphotactic-attribute-breadth simru ok::SIM+REAL|simru Word ok::- rewrote 1 RealizationalRule@blockable from "false" to "true" Evidenced +dtd:enum/RealizationalRule/isActive/no Surface edge-cases/morphotactic-attribute-breadth kulsi ok::- Word ok::KUL+RDEC|kulsi rewrote 1 RealizationalRule@isActive from "no" to "yes" Evidenced +dtd:enum/SegmentDefinition/isActive/no Surface edge-cases/loader-isactive-breadth zal SKIPPED::- Word ok::- rewrote 1 SegmentDefinition@isActive from "no" to "yes" Evidenced +dtd:enum/SegmentDefinition/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. SIL.Machine.Morphology.HermitCrab.InvalidShapeException: The shape, ta, contains an undefined phone... rewrote 10 SegmentDefinition@isActive from "yes" to "no" RequiredByLoader +dtd:enum/SegmentNaturalClass/isActive/no Surface edge-cases/feature-system-breadth sal ok::SAL|sal Word ok::- rewrote 1 SegmentNaturalClass@isActive from "no" to "yes"; jointly activated its sole referencing (prDecNc) via naturalClass="ncDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/Slot/isActive/no Surface edge-cases/loader-isactive-breadth qekul ok::- Word ok::QE+KUL|qekul rewrote 2 Slot@isActive from "no" to "yes" Evidenced +dtd:enum/Slot/isActive/yes Surface edge-cases/loader-isactive-breadth takul ok::TA+KUL|takul Word ok::- rewrote 3 Slot@isActive from "yes" to "no" Evidenced +dtd:enum/Slot/optional/true Surface edge-cases/diacritic-segments año ok::YEAR|año Word ok::- rewrote 1 Slot@optional from "true" to "false" Evidenced +dtd:enum/Stratum/isActive/no Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul LoadFailure InvalidOperationException: Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'tableDecoy' was not present in the ... rewrote 2 Stratum@isActive from "no" to "yes" RequiredByLoader +dtd:enum/Stratum/isActive/yes Surface edge-cases/loader-isactive-breadth kul ok::KUL|kul Word threw::NullReferenceException rewrote 1 Stratum@isActive from "yes" to "no" Evidenced +dtd:enum/Stratum/morphologicalRuleOrder/linear Surface edge-cases/feature-gating-breadth kalidka ok::- Word ok::KAL+PAST+AGR|kalidka rewrote 1 Stratum@morphologicalRuleOrder from "linear" to "unordered" Evidenced +dtd:enum/Stratum/morphologicalRuleOrder/unordered Surface edge-cases/morphotactic-attribute-breadth pogliti ok::POG+POGAFX+PO|pogliti Word ok::- rewrote 1 Stratum@morphologicalRuleOrder from "unordered" to "linear" Evidenced +dtd:enum/SymbolicFeature/isActive/no Surface edge-cases/feature-system-breadth ik ok::AK|ik Word ok::- rewrote 1 SymbolicFeature@isActive from "no" to "yes"; jointly activated its sole referencing (prDecFeat) via phonologicalFeature="featDecoy", itself rewritten from isActive="no" to "yes" EvidencedJointly +dtd:enum/VariableFeature/name/%CE%B1 Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au rewrote 1 VariableFeature@name from "α" to "β" Evidenced +dtd:enum/VariableFeature/name/%CE%B2 Surface edge-cases/alpha-variable-name-collision au ok::- Word ok::AU|au rewrote 1 VariableFeature@name from "β" to "α" Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot10~slot11 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P11+P4+P3+P2+P1+K|xxxxxxk;P10+P11+P5+P3+P2+P1+K|xxxxxxk;P10+P11+P5+P4+P2+P1+K|xxxxxxk;P10+P11+P5+P4+P3+P1+K|xxxxxxk;P10+P11+P5+P4+P3+P2+K|xxxxxxk;P10+P11+P6+P3+P2+P1+K|xxxxxxk;P10+P11+P6+P4+P2+P1+K|xxxxxxk;P10+P11+P6+P4+P3+P1+K|xxxxxxk;P10+P11+P6+P4+P3+P2+K|xxxxxxk;P10+P11+P6+P5+P2+P1+K|xxxxxxk;P10+P11+P6+P5+P3+P1+K|xxxxxxk;P10+P11+P6+P5+P3+P2+K|xxxxxxk;P10+P11+P6+P5+P4+P1+K|xxxxxxk;P10+P11+P6+P5+P4+P2+K|xxxxxxk;P10+P11+P6+P5+P4+P3+K|xxxxxxk;P10+P11+P7+P3+P2+P1+K|xxxxxxk;P10+P11+P7+P4+P2+P1+K|xxxxxxk;P10+P11+P7+P4+P3+P1+K|xxxxxxk;P10+P11+P7+P4+P3+P2+K|xxxxxxk;P10+P11+P7+P5+P2+P1+K|xxxxxxk;P10+P11+P7+P5+P3+P1+K|xxxxxxk;P10+P11+P7+P5+P3+P2+K|xxxxxxk;P10+P11+P7+P5+P4+P1+K|xxxxxxk;P10+P11+P7+P5+P4+P2+K|xxxxxxk;P10+P11+P7+P5+P4+P3+K|xxxxxxk;P10+P11+P7+P6+P2+P1+K|xxxxxxk;P10+P11+P7+P6+P3+P1+K|xxxxxxk;P10+P11+P7+P6+P3+P2+K|xxxxxxk;P10+P11+P7+P6+P4+P1+K|xxxxxxk;P10+P11+P7+P6+P4+P2+K|xxxxxxk;P10+P11+P7+P6+P4+P3+K|xxxxxxk;P10+P11+P7+P6+P5+P1+K|xxxxxxk;P10+P11+P7+P6+P5+P2+K|xxxxxxk;P10+P11+P7+P6+P5+P3+K|xxxxxxk;P10+P11+P7+P6+P5+P4+K|xxxxxxk;P10+P11+P8+P3+P2+P1+K|xxxxxxk;P10+P11+P8+P4+P2+P1+K|xxxxxxk;P10+P11+P8+P4+P3+P1+K|xxxxxxk;P10+P11+P8+P4+P3+P2+K|xxxxxxk;P10+P11+P8+P5+P2+P1+K|xxxxxxk;P10+P11+P8+P5+P3+P1+K|xxxxxxk;P10+P11+P8+P5+P3+P2+K|xxxxxxk;P10+P11+P8+P5+P4+P1+K|xxxxxxk;P10+P11+P8+P5+P4+P2+K|xxxxxxk;P10+P11+P8+P5+P4+P3+K|xxxxxxk;P10+P11+P8+P6+P2+P1+K|xxxxxxk;P10+P11+P8+P6+P3+P1+K|xxxxxxk;P10+P11+P8+P6+P3+P2+K|xxxxxxk;P10+P11+P8+P6+P4+P1+K|xxxxxxk;P10+P11+P8+P6+P4+P2+K|xxxxxxk;P10+P11+P8+P6+P4+P3+K|xxxxxxk;P10+P11+P8+P6+P5+P1+K|xxxxxxk;P10+P11+P8+P6+P5+P2+K|xxxxxxk;P10+P11+P8+P6+P5+P3+K|xxxxxxk;P10+P11+P8+P6+P5+P4+K|xxxxxxk;P10+P11+P8+P7+P2+P1+K|xxxxxxk;P10+P11+P8+P7+P3+P1+K|xxxxxxk;P10+P11+P8+P7+P3+P2+K|xxxxxxk;P10+P11+P8+P7+P4+P1+K|xxxxxxk;P10+P11+P8+P7+P4+P2+K|xxxxxxk;P10+P11+P8+P7+P4+P3+K|xxxxxxk;P10+P11+P8+P7+P5+P1+K|xxxxxxk;P10+P11+P8+P7+P5+P2+K|xxxxxxk;P10+P11+P8+P7+P5+P3+K|xxxxxxk;P10+P11+P8+P7+P5+P4+K|xxxxxxk;P10+P11+P8+P7+P6+P1+K|xxxxxxk;P10+P11+P8+P7+P6+P2+K|xxxxxxk;P10+P11+P8+P7+P6+P3+K|xxxxxxk;P10+P11+P8+P7+P6+P4+K|xxxxxxk;P10+P11+P8+P7+P6+P5+K|xxxxxxk;P10+P11+P9+P3+P2+P1+K|xxxxxxk;P10+P11+P9+P4+P2+P1+K|xxxxxxk;P10+P11+P9+P4+P3+P1+K|xxxxxxk;P10+P11+P9+P4+P3+P2+K|xxxxxxk;P10+P11+P9+P5+P2+P1+K|xxxxxxk;P10+P11+P9+P5+P3+P1+K|xxxxxxk;P10+P11+P9+P5+P3+P2+K|xxxxxxk;P10+P11+P9+P5+P4+P1+K|xxxxxxk;P10+P11+P9+P5+P4+P2+K|xxxxxxk;P10+P11+P9+P5+P4+P3+K|xxxxxxk;P10+P11+P9+P6+P2+P1+K|xxxxxxk;P10+P11+P9+P6+P3+P1+K|xxxxxxk;P10+P11+P9+P6+P3+P2+K|xxxxxxk;P10+P11+P9+P6+P4+P1+K|xxxxxxk;P10+P11+P9+P6+P4+P2+K|xxxxxxk;P10+P11+P9+P6+P4+P3+K|xxxxxxk;P10+P11+P9+P6+P5+P1+K|xxxxxxk;P10+P11+P9+P6+P5+P2+K|xxxxxxk;P10+P11+P9+P6+P5+P3+K|xxxxxxk;P10+P11+P9+P6+P5+P4+K|xxxxxxk;P10+P11+P9+P7+P2+P1+K|xxxxxxk;P10+P11+P9+P7+P3+P1+K|xxxxxxk;P10+P11+P9+P7+P3+P2+K|xxxxxxk;P10+P11+P9+P7+P4+P1+K|xxxxxxk;P10+P11+P9+P7+P4+P2+K|xxxxxxk;P10+P11+P9+P7+P4+P3+K|xxxxxxk;P10+P11+P9+P7+P5+P1+K|xxxxxxk;P10+P11+P9+P7+P5+P2+K|xxxxxxk;P10+P11+P9+P7+P5+P3+K|xxxxxxk;P10+P11+P9+P7+P5+P4+K|xxxxxxk;P10+P11+P9+P7+P6+P1+K|xxxxxxk;P10+P11+P9+P7+P6+P2+K|xxxxxxk;P10+P11+P9+P7+P6+P3+K|xxxxxxk;P10+P11+P9+P7+P6+P4+K|xxxxxxk;P10+P11+P9+P7+P6+P5+K|xxxxxxk;P10+P11+P9+P8+P2+P1+K|xxxxxxk;P10+P11+P9+P8+P3+P1+K|xxxxxxk;P10+P11+P9+P8+P3+P2+K|xxxxxxk;P10+P11+P9+P8+P4+P1+K|xxxxxxk;P10+P11+P9+P8+P4+P2+K|xxxxxxk;P10+P11+P9+P8+P4+P3+K|xxxxxxk;P10+P11+P9+P8+P5+P1+K|xxxxxxk;P10+P11+P9+P8+P5+P2+K|xxxxxxk;P10+P11+P9+P8+P5+P3+K|xxxxxxk;P10+P11+P9+P8+P5+P4+K|xxxxxxk;P10+P11+P9+P8+P6+P1+K|xxxxxxk;P10+P11+P9+P8+P6+P2+K|xxxxxxk;P10+P11+P9+P8+P6+P3+K|xxxxxxk;P10+P11+P9+P8+P6+P4+K|xxxxxxk;P10+P11+P9+P8+P6+P5+K|xxxxxxk;P10+P11+P9+P8+P7+P1+K|xxxxxxk;P10+P11+P9+P8+P7+P2+K|xxxxxxk;P10+P11+P9+P8+P7+P3+K|xxxxxxk;P10+P11+P9+P8+P7+P4+K|xxxxxxk;P10+P11+P9+P8+P7+P5+K|xxxxxxk;P10+P11+P9+P8+P7+P6+K|xxxxxxk;P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P11+P3+P2+P1+K|xxxxxxk;P12+P10+P11+P4+P2+P1+K|xxxxxxk;P12+P10+P11+P4+P3+P1+K|xxxxxxk;P12+P10+P11+P4+P3+P2+K|xxxxxxk;P12+P10+P11+P5+P2+P1+K|xxxxxxk;P12+P10+P11+P5+P3+P1+K|xxxxxxk;P12+P10+P11+P5+P3+P2+K|xxxxxxk;P12+P10+P11+P5+P4+P1+K|xxxxxxk;P12+P10+P11+P5+P4+P2+K|xxxxxxk;P12+P10+P11+P5+P4+P3+K|xxxxxxk;P12+P10+P11+P6+P2+P1+K|xxxxxxk;P12+P10+P11+P6+P3+P1+K|xxxxxxk;P12+P10+P11+P6+P3+P2+K|xxxxxxk;P12+P10+P11+P6+P4+P1+K|xxxxxxk;P12+P10+P11+P6+P4+P2+K|xxxxxxk;P12+P10+P11+P6+P4+P3+K|xxxxxxk;P12+P10+P11+P6+P5+P1+K|xxxxxxk;P12+P10+P11+P6+P5+P2+K|xxxxxxk;P12+P10+P11+P6+P5+P3+K|xxxxxxk;P12+P10+P11+P6+P5+P4+K|xxxxxxk;P12+P10+P11+P7+P2+P1+K|xxxxxxk;P12+P10+P11+P7+P3+P1+K|xxxxxxk;P12+P10+P11+P7+P3+P2+K|xxxxxxk;P12+P10+P11+P7+P4+P1+K|xxxxxxk;P12+P10+P11+P7+P4+P2+K|xxxxxxk;P12+P10+P11+P7+P4+P3+K|xxxxxxk;P12+P10+P11+P7+P5+P1+K|xxxxxxk;P12+P10+P11+P7+P5+P2+K|xxxxxxk;P12+P10+P11+P7+P5+P3+K|xxxxxxk;P12+P10+P11+P7+P5+P4+K|xxxxxxk;P12+P10+P11+P7+P6+P1+K|xxxxxxk;P12+P10+P11+P7+P6+P2+K|xxxxxxk;P12+P10+P11+P7+P6+P3+K|xxxxxxk;P12+P10+P11+P7+P6+P4+K|xxxxxxk;P12+P10+P11+P7+P6+P5+K|xxxxxxk;P12+P10+P11+P8+P2+P1+K|xxxxxxk;P12+P10+P11+P8+P3+P1+K|xxxxxxk;P12+P10+P11+P8+P3+P2+K|xxxxxxk;P12+P10+P11+P8+P4+P1+K|xxxxxxk;P12+P10+P11+P8+P4+P2+K|xxxxxxk;P12+P10+P11+P8+P4+P3+K|xxxxxxk;P12+P10+P11+P8+P5+P1+K|xxxxxxk;P12+P10+P11+P8+P5+P2+K|xxxxxxk;P12+P10+P11+P8+P5+P3+K|xxxxxxk;P12+P10+P11+P8+P5+P4+K|xxxxxxk;P12+P10+P11+P8+P6+P1+K|xxxxxxk;P12+P10+P11+P8+P6+P2+K|xxxxxxk;P12+P10+P11+P8+P6+P3+K|xxxxxxk;P12+P10+P11+P8+P6+P4+K|xxxxxxk;P12+P10+P11+P8+P6+P5+K|xxxxxxk;P12+P10+P11+P8+P7+P1+K|xxxxxxk;P12+P10+P11+P8+P7+P2+K|xxxxxxk;P12+P10+P11+P8+P7+P3+K|xxxxxxk;P12+P10+P11+P8+P7+P4+K|xxxxxxk;P12+P10+P11+P8+P7+P5+K|xxxxxxk;P12+P10+P11+P8+P7+P6+K|xxxxxxk;P12+P10+P11+P9+P2+P1+K|xxxxxxk;P12+P10+P11+P9+P3+P1+K|xxxxxxk;P12+P10+P11+P9+P3+P2+K|xxxxxxk;P12+P10+P11+P9+P4+P1+K|xxxxxxk;P12+P10+P11+P9+P4+P2+K|xxxxxxk;P12+P10+P11+P9+P4+P3+K|xxxxxxk;P12+P10+P11+P9+P5+P1+K|xxxxxxk;P12+P10+P11+P9+P5+P2+K|xxxxxxk;P12+P10+P11+P9+P5+P3+K|xxxxxxk;P12+P10+P11+P9+P5+P4+K|xxxxxxk;P12+P10+P11+P9+P6+P1+K|xxxxxxk;P12+P10+P11+P9+P6+P2+K|xxxxxxk;P12+P10+P11+P9+P6+P3+K|xxxxxxk;P12+P10+P11+P9+P6+P4+K|xxxxxxk;P12+P10+P11+P9+P6+P5+K|xxxxxxk;P12+P10+P11+P9+P7+P1+K|xxxxxxk;P12+P10+P11+P9+P7+P2+K|xxxxxxk;P12+P10+P11+P9+P7+P3+K|xxxxxxk;P12+P10+P11+P9+P7+P4+K|xxxxxxk;P12+P10+P11+P9+P7+P5+K|xxxxxxk;P12+P10+P11+P9+P7+P6+K|xxxxxxk;P12+P10+P11+P9+P8+P1+K|xxxxxxk;P12+P10+P11+P9+P8+P2+K|xxxxxxk;P12+P10+P11+P9+P8+P3+K|xxxxxxk;P12+P10+P11+P9+P8+P4+K|xxxxxxk;P12+P10+P11+P9+P8+P5+K|xxxxxxk;P12+P10+P11+P9+P8+P6+K|xxxxxxk;P12+P10+P11+P9+P8+P7+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk swapped adjacent Slot elements "slot10" and "slot11" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot11~slot12 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P12+P10+P3+P2+P1+K|xxxxxxk;P11+P12+P10+P4+P2+P1+K|xxxxxxk;P11+P12+P10+P4+P3+P1+K|xxxxxxk;P11+P12+P10+P4+P3+P2+K|xxxxxxk;P11+P12+P10+P5+P2+P1+K|xxxxxxk;P11+P12+P10+P5+P3+P1+K|xxxxxxk;P11+P12+P10+P5+P3+P2+K|xxxxxxk;P11+P12+P10+P5+P4+P1+K|xxxxxxk;P11+P12+P10+P5+P4+P2+K|xxxxxxk;P11+P12+P10+P5+P4+P3+K|xxxxxxk;P11+P12+P10+P6+P2+P1+K|xxxxxxk;P11+P12+P10+P6+P3+P1+K|xxxxxxk;P11+P12+P10+P6+P3+P2+K|xxxxxxk;P11+P12+P10+P6+P4+P1+K|xxxxxxk;P11+P12+P10+P6+P4+P2+K|xxxxxxk;P11+P12+P10+P6+P4+P3+K|xxxxxxk;P11+P12+P10+P6+P5+P1+K|xxxxxxk;P11+P12+P10+P6+P5+P2+K|xxxxxxk;P11+P12+P10+P6+P5+P3+K|xxxxxxk;P11+P12+P10+P6+P5+P4+K|xxxxxxk;P11+P12+P10+P7+P2+P1+K|xxxxxxk;P11+P12+P10+P7+P3+P1+K|xxxxxxk;P11+P12+P10+P7+P3+P2+K|xxxxxxk;P11+P12+P10+P7+P4+P1+K|xxxxxxk;P11+P12+P10+P7+P4+P2+K|xxxxxxk;P11+P12+P10+P7+P4+P3+K|xxxxxxk;P11+P12+P10+P7+P5+P1+K|xxxxxxk;P11+P12+P10+P7+P5+P2+K|xxxxxxk;P11+P12+P10+P7+P5+P3+K|xxxxxxk;P11+P12+P10+P7+P5+P4+K|xxxxxxk;P11+P12+P10+P7+P6+P1+K|xxxxxxk;P11+P12+P10+P7+P6+P2+K|xxxxxxk;P11+P12+P10+P7+P6+P3+K|xxxxxxk;P11+P12+P10+P7+P6+P4+K|xxxxxxk;P11+P12+P10+P7+P6+P5+K|xxxxxxk;P11+P12+P10+P8+P2+P1+K|xxxxxxk;P11+P12+P10+P8+P3+P1+K|xxxxxxk;P11+P12+P10+P8+P3+P2+K|xxxxxxk;P11+P12+P10+P8+P4+P1+K|xxxxxxk;P11+P12+P10+P8+P4+P2+K|xxxxxxk;P11+P12+P10+P8+P4+P3+K|xxxxxxk;P11+P12+P10+P8+P5+P1+K|xxxxxxk;P11+P12+P10+P8+P5+P2+K|xxxxxxk;P11+P12+P10+P8+P5+P3+K|xxxxxxk;P11+P12+P10+P8+P5+P4+K|xxxxxxk;P11+P12+P10+P8+P6+P1+K|xxxxxxk;P11+P12+P10+P8+P6+P2+K|xxxxxxk;P11+P12+P10+P8+P6+P3+K|xxxxxxk;P11+P12+P10+P8+P6+P4+K|xxxxxxk;P11+P12+P10+P8+P6+P5+K|xxxxxxk;P11+P12+P10+P8+P7+P1+K|xxxxxxk;P11+P12+P10+P8+P7+P2+K|xxxxxxk;P11+P12+P10+P8+P7+P3+K|xxxxxxk;P11+P12+P10+P8+P7+P4+K|xxxxxxk;P11+P12+P10+P8+P7+P5+K|xxxxxxk;P11+P12+P10+P8+P7+P6+K|xxxxxxk;P11+P12+P10+P9+P2+P1+K|xxxxxxk;P11+P12+P10+P9+P3+P1+K|xxxxxxk;P11+P12+P10+P9+P3+P2+K|xxxxxxk;P11+P12+P10+P9+P4+P1+K|xxxxxxk;P11+P12+P10+P9+P4+P2+K|xxxxxxk;P11+P12+P10+P9+P4+P3+K|xxxxxxk;P11+P12+P10+P9+P5+P1+K|xxxxxxk;P11+P12+P10+P9+P5+P2+K|xxxxxxk;P11+P12+P10+P9+P5+P3+K|xxxxxxk;P11+P12+P10+P9+P5+P4+K|xxxxxxk;P11+P12+P10+P9+P6+P1+K|xxxxxxk;P11+P12+P10+P9+P6+P2+K|xxxxxxk;P11+P12+P10+P9+P6+P3+K|xxxxxxk;P11+P12+P10+P9+P6+P4+K|xxxxxxk;P11+P12+P10+P9+P6+P5+K|xxxxxxk;P11+P12+P10+P9+P7+P1+K|xxxxxxk;P11+P12+P10+P9+P7+P2+K|xxxxxxk;P11+P12+P10+P9+P7+P3+K|xxxxxxk;P11+P12+P10+P9+P7+P4+K|xxxxxxk;P11+P12+P10+P9+P7+P5+K|xxxxxxk;P11+P12+P10+P9+P7+P6+K|xxxxxxk;P11+P12+P10+P9+P8+P1+K|xxxxxxk;P11+P12+P10+P9+P8+P2+K|xxxxxxk;P11+P12+P10+P9+P8+P3+K|xxxxxxk;P11+P12+P10+P9+P8+P4+K|xxxxxxk;P11+P12+P10+P9+P8+P5+K|xxxxxxk;P11+P12+P10+P9+P8+P6+K|xxxxxxk;P11+P12+P10+P9+P8+P7+K|xxxxxxk;P11+P12+P4+P3+P2+P1+K|xxxxxxk;P11+P12+P5+P3+P2+P1+K|xxxxxxk;P11+P12+P5+P4+P2+P1+K|xxxxxxk;P11+P12+P5+P4+P3+P1+K|xxxxxxk;P11+P12+P5+P4+P3+P2+K|xxxxxxk;P11+P12+P6+P3+P2+P1+K|xxxxxxk;P11+P12+P6+P4+P2+P1+K|xxxxxxk;P11+P12+P6+P4+P3+P1+K|xxxxxxk;P11+P12+P6+P4+P3+P2+K|xxxxxxk;P11+P12+P6+P5+P2+P1+K|xxxxxxk;P11+P12+P6+P5+P3+P1+K|xxxxxxk;P11+P12+P6+P5+P3+P2+K|xxxxxxk;P11+P12+P6+P5+P4+P1+K|xxxxxxk;P11+P12+P6+P5+P4+P2+K|xxxxxxk;P11+P12+P6+P5+P4+P3+K|xxxxxxk;P11+P12+P7+P3+P2+P1+K|xxxxxxk;P11+P12+P7+P4+P2+P1+K|xxxxxxk;P11+P12+P7+P4+P3+P1+K|xxxxxxk;P11+P12+P7+P4+P3+P2+K|xxxxxxk;P11+P12+P7+P5+P2+P1+K|xxxxxxk;P11+P12+P7+P5+P3+P1+K|xxxxxxk;P11+P12+P7+P5+P3+P2+K|xxxxxxk;P11+P12+P7+P5+P4+P1+K|xxxxxxk;P11+P12+P7+P5+P4+P2+K|xxxxxxk;P11+P12+P7+P5+P4+P3+K|xxxxxxk;P11+P12+P7+P6+P2+P1+K|xxxxxxk;P11+P12+P7+P6+P3+P1+K|xxxxxxk;P11+P12+P7+P6+P3+P2+K|xxxxxxk;P11+P12+P7+P6+P4+P1+K|xxxxxxk;P11+P12+P7+P6+P4+P2+K|xxxxxxk;P11+P12+P7+P6+P4+P3+K|xxxxxxk;P11+P12+P7+P6+P5+P1+K|xxxxxxk;P11+P12+P7+P6+P5+P2+K|xxxxxxk;P11+P12+P7+P6+P5+P3+K|xxxxxxk;P11+P12+P7+P6+P5+P4+K|xxxxxxk;P11+P12+P8+P3+P2+P1+K|xxxxxxk;P11+P12+P8+P4+P2+P1+K|xxxxxxk;P11+P12+P8+P4+P3+P1+K|xxxxxxk;P11+P12+P8+P4+P3+P2+K|xxxxxxk;P11+P12+P8+P5+P2+P1+K|xxxxxxk;P11+P12+P8+P5+P3+P1+K|xxxxxxk;P11+P12+P8+P5+P3+P2+K|xxxxxxk;P11+P12+P8+P5+P4+P1+K|xxxxxxk;P11+P12+P8+P5+P4+P2+K|xxxxxxk;P11+P12+P8+P5+P4+P3+K|xxxxxxk;P11+P12+P8+P6+P2+P1+K|xxxxxxk;P11+P12+P8+P6+P3+P1+K|xxxxxxk;P11+P12+P8+P6+P3+P2+K|xxxxxxk;P11+P12+P8+P6+P4+P1+K|xxxxxxk;P11+P12+P8+P6+P4+P2+K|xxxxxxk;P11+P12+P8+P6+P4+P3+K|xxxxxxk;P11+P12+P8+P6+P5+P1+K|xxxxxxk;P11+P12+P8+P6+P5+P2+K|xxxxxxk;P11+P12+P8+P6+P5+P3+K|xxxxxxk;P11+P12+P8+P6+P5+P4+K|xxxxxxk;P11+P12+P8+P7+P2+P1+K|xxxxxxk;P11+P12+P8+P7+P3+P1+K|xxxxxxk;P11+P12+P8+P7+P3+P2+K|xxxxxxk;P11+P12+P8+P7+P4+P1+K|xxxxxxk;P11+P12+P8+P7+P4+P2+K|xxxxxxk;P11+P12+P8+P7+P4+P3+K|xxxxxxk;P11+P12+P8+P7+P5+P1+K|xxxxxxk;P11+P12+P8+P7+P5+P2+K|xxxxxxk;P11+P12+P8+P7+P5+P3+K|xxxxxxk;P11+P12+P8+P7+P5+P4+K|xxxxxxk;P11+P12+P8+P7+P6+P1+K|xxxxxxk;P11+P12+P8+P7+P6+P2+K|xxxxxxk;P11+P12+P8+P7+P6+P3+K|xxxxxxk;P11+P12+P8+P7+P6+P4+K|xxxxxxk;P11+P12+P8+P7+P6+P5+K|xxxxxxk;P11+P12+P9+P3+P2+P1+K|xxxxxxk;P11+P12+P9+P4+P2+P1+K|xxxxxxk;P11+P12+P9+P4+P3+P1+K|xxxxxxk;P11+P12+P9+P4+P3+P2+K|xxxxxxk;P11+P12+P9+P5+P2+P1+K|xxxxxxk;P11+P12+P9+P5+P3+P1+K|xxxxxxk;P11+P12+P9+P5+P3+P2+K|xxxxxxk;P11+P12+P9+P5+P4+P1+K|xxxxxxk;P11+P12+P9+P5+P4+P2+K|xxxxxxk;P11+P12+P9+P5+P4+P3+K|xxxxxxk;P11+P12+P9+P6+P2+P1+K|xxxxxxk;P11+P12+P9+P6+P3+P1+K|xxxxxxk;P11+P12+P9+P6+P3+P2+K|xxxxxxk;P11+P12+P9+P6+P4+P1+K|xxxxxxk;P11+P12+P9+P6+P4+P2+K|xxxxxxk;P11+P12+P9+P6+P4+P3+K|xxxxxxk;P11+P12+P9+P6+P5+P1+K|xxxxxxk;P11+P12+P9+P6+P5+P2+K|xxxxxxk;P11+P12+P9+P6+P5+P3+K|xxxxxxk;P11+P12+P9+P6+P5+P4+K|xxxxxxk;P11+P12+P9+P7+P2+P1+K|xxxxxxk;P11+P12+P9+P7+P3+P1+K|xxxxxxk;P11+P12+P9+P7+P3+P2+K|xxxxxxk;P11+P12+P9+P7+P4+P1+K|xxxxxxk;P11+P12+P9+P7+P4+P2+K|xxxxxxk;P11+P12+P9+P7+P4+P3+K|xxxxxxk;P11+P12+P9+P7+P5+P1+K|xxxxxxk;P11+P12+P9+P7+P5+P2+K|xxxxxxk;P11+P12+P9+P7+P5+P3+K|xxxxxxk;P11+P12+P9+P7+P5+P4+K|xxxxxxk;P11+P12+P9+P7+P6+P1+K|xxxxxxk;P11+P12+P9+P7+P6+P2+K|xxxxxxk;P11+P12+P9+P7+P6+P3+K|xxxxxxk;P11+P12+P9+P7+P6+P4+K|xxxxxxk;P11+P12+P9+P7+P6+P5+K|xxxxxxk;P11+P12+P9+P8+P2+P1+K|xxxxxxk;P11+P12+P9+P8+P3+P1+K|xxxxxxk;P11+P12+P9+P8+P3+P2+K|xxxxxxk;P11+P12+P9+P8+P4+P1+K|xxxxxxk;P11+P12+P9+P8+P4+P2+K|xxxxxxk;P11+P12+P9+P8+P4+P3+K|xxxxxxk;P11+P12+P9+P8+P5+P1+K|xxxxxxk;P11+P12+P9+P8+P5+P2+K|xxxxxxk;P11+P12+P9+P8+P5+P3+K|xxxxxxk;P11+P12+P9+P8+P5+P4+K|xxxxxxk;P11+P12+P9+P8+P6+P1+K|xxxxxxk;P11+P12+P9+P8+P6+P2+K|xxxxxxk;P11+P12+P9+P8+P6+P3+K|xxxxxxk;P11+P12+P9+P8+P6+P4+K|xxxxxxk;P11+P12+P9+P8+P6+P5+K|xxxxxxk;P11+P12+P9+P8+P7+P1+K|xxxxxxk;P11+P12+P9+P8+P7+P2+K|xxxxxxk;P11+P12+P9+P8+P7+P3+K|xxxxxxk;P11+P12+P9+P8+P7+P4+K|xxxxxxk;P11+P12+P9+P8+P7+P5+K|xxxxxxk;P11+P12+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk swapped adjacent Slot elements "slot11" and "slot12" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot1~slot2 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P1+P2+K|xxxxxxk;P10+P6+P4+P3+P1+P2+K|xxxxxxk;P10+P6+P5+P3+P1+P2+K|xxxxxxk;P10+P6+P5+P4+P1+P2+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P1+P2+K|xxxxxxk;P10+P7+P5+P3+P1+P2+K|xxxxxxk;P10+P7+P5+P4+P1+P2+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P1+P2+K|xxxxxxk;P10+P7+P6+P4+P1+P2+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P1+P2+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P1+P2+K|xxxxxxk;P10+P8+P5+P3+P1+P2+K|xxxxxxk;P10+P8+P5+P4+P1+P2+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P1+P2+K|xxxxxxk;P10+P8+P6+P4+P1+P2+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P1+P2+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P1+P2+K|xxxxxxk;P10+P8+P7+P4+P1+P2+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P1+P2+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P1+P2+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P1+P2+K|xxxxxxk;P10+P9+P5+P3+P1+P2+K|xxxxxxk;P10+P9+P5+P4+P1+P2+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P1+P2+K|xxxxxxk;P10+P9+P6+P4+P1+P2+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P1+P2+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P1+P2+K|xxxxxxk;P10+P9+P7+P4+P1+P2+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P1+P2+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P1+P2+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P1+P2+K|xxxxxxk;P10+P9+P8+P4+P1+P2+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P1+P2+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P1+P2+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P1+P2+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P1+P2+K|xxxxxxk;P11+P10+P5+P3+P1+P2+K|xxxxxxk;P11+P10+P5+P4+P1+P2+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P1+P2+K|xxxxxxk;P11+P10+P6+P4+P1+P2+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P1+P2+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P1+P2+K|xxxxxxk;P11+P10+P7+P4+P1+P2+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P1+P2+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P1+P2+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P1+P2+K|xxxxxxk;P11+P10+P8+P4+P1+P2+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P1+P2+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P1+P2+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P1+P2+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P1+P2+K|xxxxxxk;P11+P10+P9+P4+P1+P2+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P1+P2+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P1+P2+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P1+P2+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P1+P2+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P1+P2+K|xxxxxxk;P11+P6+P4+P3+P1+P2+K|xxxxxxk;P11+P6+P5+P3+P1+P2+K|xxxxxxk;P11+P6+P5+P4+P1+P2+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P1+P2+K|xxxxxxk;P11+P7+P5+P3+P1+P2+K|xxxxxxk;P11+P7+P5+P4+P1+P2+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P1+P2+K|xxxxxxk;P11+P7+P6+P4+P1+P2+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P1+P2+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P1+P2+K|xxxxxxk;P11+P8+P5+P3+P1+P2+K|xxxxxxk;P11+P8+P5+P4+P1+P2+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P1+P2+K|xxxxxxk;P11+P8+P6+P4+P1+P2+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P1+P2+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P1+P2+K|xxxxxxk;P11+P8+P7+P4+P1+P2+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P1+P2+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P1+P2+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P1+P2+K|xxxxxxk;P11+P9+P5+P3+P1+P2+K|xxxxxxk;P11+P9+P5+P4+P1+P2+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P1+P2+K|xxxxxxk;P11+P9+P6+P4+P1+P2+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P1+P2+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P1+P2+K|xxxxxxk;P11+P9+P7+P4+P1+P2+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P1+P2+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P1+P2+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P1+P2+K|xxxxxxk;P11+P9+P8+P4+P1+P2+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P1+P2+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P1+P2+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P1+P2+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P1+P2+K|xxxxxxk;P12+P10+P5+P3+P1+P2+K|xxxxxxk;P12+P10+P5+P4+P1+P2+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P1+P2+K|xxxxxxk;P12+P10+P6+P4+P1+P2+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P1+P2+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P1+P2+K|xxxxxxk;P12+P10+P7+P4+P1+P2+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P1+P2+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P1+P2+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P1+P2+K|xxxxxxk;P12+P10+P8+P4+P1+P2+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P1+P2+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P1+P2+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P1+P2+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P1+P2+K|xxxxxxk;P12+P10+P9+P4+P1+P2+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P1+P2+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P1+P2+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P1+P2+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P1+P2+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P1+P2+K|xxxxxxk;P12+P11+P10+P4+P1+P2+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P1+P2+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P1+P2+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P1+P2+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P1+P2+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P1+P2+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P1+P2+K|xxxxxxk;P12+P11+P5+P3+P1+P2+K|xxxxxxk;P12+P11+P5+P4+P1+P2+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P1+P2+K|xxxxxxk;P12+P11+P6+P4+P1+P2+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P1+P2+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P1+P2+K|xxxxxxk;P12+P11+P7+P4+P1+P2+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P1+P2+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P1+P2+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P1+P2+K|xxxxxxk;P12+P11+P8+P4+P1+P2+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P1+P2+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P1+P2+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P1+P2+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P1+P2+K|xxxxxxk;P12+P11+P9+P4+P1+P2+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P1+P2+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P1+P2+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P1+P2+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P1+P2+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P1+P2+K|xxxxxxk;P12+P6+P4+P3+P1+P2+K|xxxxxxk;P12+P6+P5+P3+P1+P2+K|xxxxxxk;P12+P6+P5+P4+P1+P2+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P1+P2+K|xxxxxxk;P12+P7+P5+P3+P1+P2+K|xxxxxxk;P12+P7+P5+P4+P1+P2+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P1+P2+K|xxxxxxk;P12+P7+P6+P4+P1+P2+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P1+P2+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P1+P2+K|xxxxxxk;P12+P8+P5+P3+P1+P2+K|xxxxxxk;P12+P8+P5+P4+P1+P2+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P1+P2+K|xxxxxxk;P12+P8+P6+P4+P1+P2+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P1+P2+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P1+P2+K|xxxxxxk;P12+P8+P7+P4+P1+P2+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P1+P2+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P1+P2+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P1+P2+K|xxxxxxk;P12+P9+P5+P3+P1+P2+K|xxxxxxk;P12+P9+P5+P4+P1+P2+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P1+P2+K|xxxxxxk;P12+P9+P6+P4+P1+P2+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P1+P2+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P1+P2+K|xxxxxxk;P12+P9+P7+P4+P1+P2+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P1+P2+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P1+P2+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P1+P2+K|xxxxxxk;P12+P9+P8+P4+P1+P2+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P1+P2+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P1+P2+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P1+P2+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P1+P2+K|xxxxxxk;P7+P5+P4+P3+P1+P2+K|xxxxxxk;P7+P6+P4+P3+P1+P2+K|xxxxxxk;P7+P6+P5+P3+P1+P2+K|xxxxxxk;P7+P6+P5+P4+P1+P2+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P1+P2+K|xxxxxxk;P8+P6+P4+P3+P1+P2+K|xxxxxxk;P8+P6+P5+P3+P1+P2+K|xxxxxxk;P8+P6+P5+P4+P1+P2+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P1+P2+K|xxxxxxk;P8+P7+P5+P3+P1+P2+K|xxxxxxk;P8+P7+P5+P4+P1+P2+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P1+P2+K|xxxxxxk;P8+P7+P6+P4+P1+P2+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P1+P2+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P1+P2+K|xxxxxxk;P9+P6+P4+P3+P1+P2+K|xxxxxxk;P9+P6+P5+P3+P1+P2+K|xxxxxxk;P9+P6+P5+P4+P1+P2+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P1+P2+K|xxxxxxk;P9+P7+P5+P3+P1+P2+K|xxxxxxk;P9+P7+P5+P4+P1+P2+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P1+P2+K|xxxxxxk;P9+P7+P6+P4+P1+P2+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P1+P2+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P1+P2+K|xxxxxxk;P9+P8+P5+P3+P1+P2+K|xxxxxxk;P9+P8+P5+P4+P1+P2+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P1+P2+K|xxxxxxk;P9+P8+P6+P4+P1+P2+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P1+P2+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P1+P2+K|xxxxxxk;P9+P8+P7+P4+P1+P2+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P1+P2+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P1+P2+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk swapped adjacent Slot elements "slot1" and "slot2" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot2~slot3 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P2+P3+P1+K|xxxxxxk;P10+P6+P4+P2+P3+P1+K|xxxxxxk;P10+P6+P5+P2+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P3+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P4+P2+P3+P1+K|xxxxxxk;P10+P7+P5+P2+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P3+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P2+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P3+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P2+P3+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P2+P3+P1+K|xxxxxxk;P10+P8+P5+P2+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P3+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P2+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P3+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P2+P3+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P2+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P3+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P2+P3+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P2+P3+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P2+P3+P1+K|xxxxxxk;P10+P9+P5+P2+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P3+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P2+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P3+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P2+P3+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P2+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P3+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P2+P3+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P2+P3+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P2+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P3+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P2+P3+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P2+P3+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P2+P3+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P2+P3+P1+K|xxxxxxk;P11+P10+P5+P2+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P3+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P2+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P3+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P2+P3+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P2+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P3+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P2+P3+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P2+P3+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P2+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P3+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P2+P3+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P2+P3+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P2+P3+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P2+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P3+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P2+P3+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P2+P3+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P2+P3+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P2+P3+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P2+P3+P1+K|xxxxxxk;P11+P6+P4+P2+P3+P1+K|xxxxxxk;P11+P6+P5+P2+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P3+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P4+P2+P3+P1+K|xxxxxxk;P11+P7+P5+P2+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P3+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P2+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P3+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P2+P3+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P2+P3+P1+K|xxxxxxk;P11+P8+P5+P2+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P3+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P2+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P3+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P2+P3+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P2+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P3+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P2+P3+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P2+P3+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P2+P3+P1+K|xxxxxxk;P11+P9+P5+P2+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P3+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P2+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P3+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P2+P3+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P2+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P3+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P2+P3+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P2+P3+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P2+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P3+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P2+P3+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P2+P3+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P2+P3+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P2+P3+P1+K|xxxxxxk;P12+P10+P5+P2+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P3+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P2+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P3+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P2+P3+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P2+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P3+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P2+P3+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P2+P3+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P2+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P3+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P2+P3+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P2+P3+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P2+P3+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P2+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P3+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P2+P3+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P2+P3+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P2+P3+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P2+P3+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P2+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P3+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P2+P3+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P2+P3+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P2+P3+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P2+P3+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P2+P3+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P2+P3+P1+K|xxxxxxk;P12+P11+P5+P2+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P3+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P2+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P3+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P2+P3+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P2+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P3+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P2+P3+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P2+P3+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P2+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P3+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P2+P3+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P2+P3+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P2+P3+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P2+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P3+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P2+P3+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P2+P3+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P2+P3+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P2+P3+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P2+P3+P1+K|xxxxxxk;P12+P6+P4+P2+P3+P1+K|xxxxxxk;P12+P6+P5+P2+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P3+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P4+P2+P3+P1+K|xxxxxxk;P12+P7+P5+P2+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P3+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P2+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P3+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P2+P3+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P2+P3+P1+K|xxxxxxk;P12+P8+P5+P2+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P3+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P2+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P3+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P2+P3+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P2+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P3+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P2+P3+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P2+P3+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P2+P3+P1+K|xxxxxxk;P12+P9+P5+P2+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P3+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P2+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P3+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P2+P3+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P2+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P3+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P2+P3+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P2+P3+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P2+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P3+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P2+P3+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P2+P3+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P2+P3+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P2+P3+P1+K|xxxxxxk;P7+P5+P4+P2+P3+P1+K|xxxxxxk;P7+P6+P4+P2+P3+P1+K|xxxxxxk;P7+P6+P5+P2+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P3+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P5+P4+P2+P3+P1+K|xxxxxxk;P8+P6+P4+P2+P3+P1+K|xxxxxxk;P8+P6+P5+P2+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P3+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P4+P2+P3+P1+K|xxxxxxk;P8+P7+P5+P2+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P3+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P2+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P3+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P2+P3+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P2+P3+P1+K|xxxxxxk;P9+P6+P4+P2+P3+P1+K|xxxxxxk;P9+P6+P5+P2+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P3+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P4+P2+P3+P1+K|xxxxxxk;P9+P7+P5+P2+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P3+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P2+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P3+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P2+P3+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P2+P3+P1+K|xxxxxxk;P9+P8+P5+P2+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P3+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P2+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P3+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P2+P3+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P2+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P3+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P2+P3+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P2+P3+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk swapped adjacent Slot elements "slot2" and "slot3" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot3~slot4 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P3+P4+P2+P1+K|xxxxxxk;P10+P6+P3+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P4+P1+K|xxxxxxk;P10+P6+P5+P3+P4+P2+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P3+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P4+P1+K|xxxxxxk;P10+P7+P5+P3+P4+P2+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P3+P4+P1+K|xxxxxxk;P10+P7+P6+P3+P4+P2+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P3+P4+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P3+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P4+P1+K|xxxxxxk;P10+P8+P5+P3+P4+P2+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P3+P4+P1+K|xxxxxxk;P10+P8+P6+P3+P4+P2+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P3+P4+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P3+P4+P1+K|xxxxxxk;P10+P8+P7+P3+P4+P2+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P3+P4+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P3+P4+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P3+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P4+P1+K|xxxxxxk;P10+P9+P5+P3+P4+P2+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P3+P4+P1+K|xxxxxxk;P10+P9+P6+P3+P4+P2+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P3+P4+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P3+P4+P1+K|xxxxxxk;P10+P9+P7+P3+P4+P2+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P3+P4+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P3+P4+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P3+P4+P1+K|xxxxxxk;P10+P9+P8+P3+P4+P2+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P3+P4+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P3+P4+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P3+P4+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P3+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P4+P1+K|xxxxxxk;P11+P10+P5+P3+P4+P2+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P3+P4+P1+K|xxxxxxk;P11+P10+P6+P3+P4+P2+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P3+P4+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P3+P4+P1+K|xxxxxxk;P11+P10+P7+P3+P4+P2+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P3+P4+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P3+P4+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P3+P4+P1+K|xxxxxxk;P11+P10+P8+P3+P4+P2+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P3+P4+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P3+P4+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P3+P4+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P3+P4+P1+K|xxxxxxk;P11+P10+P9+P3+P4+P2+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P3+P4+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P3+P4+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P3+P4+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P3+P4+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P3+P4+P2+P1+K|xxxxxxk;P11+P6+P3+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P4+P1+K|xxxxxxk;P11+P6+P5+P3+P4+P2+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P3+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P4+P1+K|xxxxxxk;P11+P7+P5+P3+P4+P2+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P3+P4+P1+K|xxxxxxk;P11+P7+P6+P3+P4+P2+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P3+P4+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P3+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P4+P1+K|xxxxxxk;P11+P8+P5+P3+P4+P2+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P3+P4+P1+K|xxxxxxk;P11+P8+P6+P3+P4+P2+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P3+P4+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P3+P4+P1+K|xxxxxxk;P11+P8+P7+P3+P4+P2+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P3+P4+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P3+P4+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P3+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P4+P1+K|xxxxxxk;P11+P9+P5+P3+P4+P2+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P3+P4+P1+K|xxxxxxk;P11+P9+P6+P3+P4+P2+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P3+P4+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P3+P4+P1+K|xxxxxxk;P11+P9+P7+P3+P4+P2+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P3+P4+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P3+P4+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P3+P4+P1+K|xxxxxxk;P11+P9+P8+P3+P4+P2+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P3+P4+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P3+P4+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P3+P4+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P3+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P4+P1+K|xxxxxxk;P12+P10+P5+P3+P4+P2+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P3+P4+P1+K|xxxxxxk;P12+P10+P6+P3+P4+P2+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P3+P4+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P3+P4+P1+K|xxxxxxk;P12+P10+P7+P3+P4+P2+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P3+P4+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P3+P4+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P3+P4+P1+K|xxxxxxk;P12+P10+P8+P3+P4+P2+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P3+P4+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P3+P4+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P3+P4+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P3+P4+P1+K|xxxxxxk;P12+P10+P9+P3+P4+P2+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P3+P4+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P3+P4+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P3+P4+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P3+P4+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P3+P4+P1+K|xxxxxxk;P12+P11+P10+P3+P4+P2+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P3+P4+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P3+P4+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P3+P4+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P3+P4+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P3+P4+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P3+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P4+P1+K|xxxxxxk;P12+P11+P5+P3+P4+P2+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P3+P4+P1+K|xxxxxxk;P12+P11+P6+P3+P4+P2+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P3+P4+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P3+P4+P1+K|xxxxxxk;P12+P11+P7+P3+P4+P2+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P3+P4+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P3+P4+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P3+P4+P1+K|xxxxxxk;P12+P11+P8+P3+P4+P2+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P3+P4+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P3+P4+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P3+P4+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P3+P4+P1+K|xxxxxxk;P12+P11+P9+P3+P4+P2+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P3+P4+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P3+P4+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P3+P4+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P3+P4+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P3+P4+P2+P1+K|xxxxxxk;P12+P6+P3+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P4+P1+K|xxxxxxk;P12+P6+P5+P3+P4+P2+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P3+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P4+P1+K|xxxxxxk;P12+P7+P5+P3+P4+P2+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P3+P4+P1+K|xxxxxxk;P12+P7+P6+P3+P4+P2+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P3+P4+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P3+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P4+P1+K|xxxxxxk;P12+P8+P5+P3+P4+P2+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P3+P4+P1+K|xxxxxxk;P12+P8+P6+P3+P4+P2+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P3+P4+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P3+P4+P1+K|xxxxxxk;P12+P8+P7+P3+P4+P2+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P3+P4+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P3+P4+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P3+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P4+P1+K|xxxxxxk;P12+P9+P5+P3+P4+P2+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P3+P4+P1+K|xxxxxxk;P12+P9+P6+P3+P4+P2+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P3+P4+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P3+P4+P1+K|xxxxxxk;P12+P9+P7+P3+P4+P2+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P3+P4+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P3+P4+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P3+P4+P1+K|xxxxxxk;P12+P9+P8+P3+P4+P2+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P3+P4+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P3+P4+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P3+P4+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P3+P4+P2+P1+K|xxxxxxk;P7+P5+P3+P4+P2+P1+K|xxxxxxk;P7+P6+P3+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P4+P1+K|xxxxxxk;P7+P6+P5+P3+P4+P2+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P5+P3+P4+P2+P1+K|xxxxxxk;P8+P6+P3+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P4+P1+K|xxxxxxk;P8+P6+P5+P3+P4+P2+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P3+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P4+P1+K|xxxxxxk;P8+P7+P5+P3+P4+P2+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P3+P4+P1+K|xxxxxxk;P8+P7+P6+P3+P4+P2+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P3+P4+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P5+P3+P4+P2+P1+K|xxxxxxk;P9+P6+P3+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P4+P1+K|xxxxxxk;P9+P6+P5+P3+P4+P2+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P3+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P4+P1+K|xxxxxxk;P9+P7+P5+P3+P4+P2+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P3+P4+P1+K|xxxxxxk;P9+P7+P6+P3+P4+P2+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P3+P4+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P3+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P4+P1+K|xxxxxxk;P9+P8+P5+P3+P4+P2+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P3+P4+P1+K|xxxxxxk;P9+P8+P6+P3+P4+P2+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P3+P4+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P3+P4+P1+K|xxxxxxk;P9+P8+P7+P3+P4+P2+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P3+P4+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P3+P4+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk swapped adjacent Slot elements "slot3" and "slot4" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot4~slot5 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P4+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P5+P2+P1+K|xxxxxxk;P10+P6+P4+P5+P3+P1+K|xxxxxxk;P10+P6+P4+P5+P3+P2+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P4+P5+P2+P1+K|xxxxxxk;P10+P7+P4+P5+P3+P1+K|xxxxxxk;P10+P7+P4+P5+P3+P2+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P4+P5+P1+K|xxxxxxk;P10+P7+P6+P4+P5+P2+K|xxxxxxk;P10+P7+P6+P4+P5+P3+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P4+P5+P2+P1+K|xxxxxxk;P10+P8+P4+P5+P3+P1+K|xxxxxxk;P10+P8+P4+P5+P3+P2+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P4+P5+P1+K|xxxxxxk;P10+P8+P6+P4+P5+P2+K|xxxxxxk;P10+P8+P6+P4+P5+P3+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P4+P5+P1+K|xxxxxxk;P10+P8+P7+P4+P5+P2+K|xxxxxxk;P10+P8+P7+P4+P5+P3+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P4+P5+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P4+P5+P2+P1+K|xxxxxxk;P10+P9+P4+P5+P3+P1+K|xxxxxxk;P10+P9+P4+P5+P3+P2+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P4+P5+P1+K|xxxxxxk;P10+P9+P6+P4+P5+P2+K|xxxxxxk;P10+P9+P6+P4+P5+P3+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P4+P5+P1+K|xxxxxxk;P10+P9+P7+P4+P5+P2+K|xxxxxxk;P10+P9+P7+P4+P5+P3+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P4+P5+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P4+P5+P1+K|xxxxxxk;P10+P9+P8+P4+P5+P2+K|xxxxxxk;P10+P9+P8+P4+P5+P3+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P4+P5+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P4+P5+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P4+P5+P2+P1+K|xxxxxxk;P11+P10+P4+P5+P3+P1+K|xxxxxxk;P11+P10+P4+P5+P3+P2+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P4+P5+P1+K|xxxxxxk;P11+P10+P6+P4+P5+P2+K|xxxxxxk;P11+P10+P6+P4+P5+P3+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P4+P5+P1+K|xxxxxxk;P11+P10+P7+P4+P5+P2+K|xxxxxxk;P11+P10+P7+P4+P5+P3+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P4+P5+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P4+P5+P1+K|xxxxxxk;P11+P10+P8+P4+P5+P2+K|xxxxxxk;P11+P10+P8+P4+P5+P3+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P4+P5+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P4+P5+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P4+P5+P1+K|xxxxxxk;P11+P10+P9+P4+P5+P2+K|xxxxxxk;P11+P10+P9+P4+P5+P3+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P4+P5+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P4+P5+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P4+P5+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P4+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P5+P2+P1+K|xxxxxxk;P11+P6+P4+P5+P3+P1+K|xxxxxxk;P11+P6+P4+P5+P3+P2+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P4+P5+P2+P1+K|xxxxxxk;P11+P7+P4+P5+P3+P1+K|xxxxxxk;P11+P7+P4+P5+P3+P2+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P4+P5+P1+K|xxxxxxk;P11+P7+P6+P4+P5+P2+K|xxxxxxk;P11+P7+P6+P4+P5+P3+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P4+P5+P2+P1+K|xxxxxxk;P11+P8+P4+P5+P3+P1+K|xxxxxxk;P11+P8+P4+P5+P3+P2+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P4+P5+P1+K|xxxxxxk;P11+P8+P6+P4+P5+P2+K|xxxxxxk;P11+P8+P6+P4+P5+P3+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P4+P5+P1+K|xxxxxxk;P11+P8+P7+P4+P5+P2+K|xxxxxxk;P11+P8+P7+P4+P5+P3+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P4+P5+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P4+P5+P2+P1+K|xxxxxxk;P11+P9+P4+P5+P3+P1+K|xxxxxxk;P11+P9+P4+P5+P3+P2+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P4+P5+P1+K|xxxxxxk;P11+P9+P6+P4+P5+P2+K|xxxxxxk;P11+P9+P6+P4+P5+P3+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P4+P5+P1+K|xxxxxxk;P11+P9+P7+P4+P5+P2+K|xxxxxxk;P11+P9+P7+P4+P5+P3+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P4+P5+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P4+P5+P1+K|xxxxxxk;P11+P9+P8+P4+P5+P2+K|xxxxxxk;P11+P9+P8+P4+P5+P3+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P4+P5+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P4+P5+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P4+P5+P2+P1+K|xxxxxxk;P12+P10+P4+P5+P3+P1+K|xxxxxxk;P12+P10+P4+P5+P3+P2+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P4+P5+P1+K|xxxxxxk;P12+P10+P6+P4+P5+P2+K|xxxxxxk;P12+P10+P6+P4+P5+P3+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P4+P5+P1+K|xxxxxxk;P12+P10+P7+P4+P5+P2+K|xxxxxxk;P12+P10+P7+P4+P5+P3+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P4+P5+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P4+P5+P1+K|xxxxxxk;P12+P10+P8+P4+P5+P2+K|xxxxxxk;P12+P10+P8+P4+P5+P3+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P4+P5+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P4+P5+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P4+P5+P1+K|xxxxxxk;P12+P10+P9+P4+P5+P2+K|xxxxxxk;P12+P10+P9+P4+P5+P3+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P4+P5+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P4+P5+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P4+P5+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P4+P5+P1+K|xxxxxxk;P12+P11+P10+P4+P5+P2+K|xxxxxxk;P12+P11+P10+P4+P5+P3+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P4+P5+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P4+P5+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P4+P5+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P4+P5+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P4+P5+P2+P1+K|xxxxxxk;P12+P11+P4+P5+P3+P1+K|xxxxxxk;P12+P11+P4+P5+P3+P2+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P4+P5+P1+K|xxxxxxk;P12+P11+P6+P4+P5+P2+K|xxxxxxk;P12+P11+P6+P4+P5+P3+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P4+P5+P1+K|xxxxxxk;P12+P11+P7+P4+P5+P2+K|xxxxxxk;P12+P11+P7+P4+P5+P3+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P4+P5+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P4+P5+P1+K|xxxxxxk;P12+P11+P8+P4+P5+P2+K|xxxxxxk;P12+P11+P8+P4+P5+P3+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P4+P5+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P4+P5+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P4+P5+P1+K|xxxxxxk;P12+P11+P9+P4+P5+P2+K|xxxxxxk;P12+P11+P9+P4+P5+P3+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P4+P5+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P4+P5+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P4+P5+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P4+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P5+P2+P1+K|xxxxxxk;P12+P6+P4+P5+P3+P1+K|xxxxxxk;P12+P6+P4+P5+P3+P2+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P4+P5+P2+P1+K|xxxxxxk;P12+P7+P4+P5+P3+P1+K|xxxxxxk;P12+P7+P4+P5+P3+P2+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P4+P5+P1+K|xxxxxxk;P12+P7+P6+P4+P5+P2+K|xxxxxxk;P12+P7+P6+P4+P5+P3+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P4+P5+P2+P1+K|xxxxxxk;P12+P8+P4+P5+P3+P1+K|xxxxxxk;P12+P8+P4+P5+P3+P2+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P4+P5+P1+K|xxxxxxk;P12+P8+P6+P4+P5+P2+K|xxxxxxk;P12+P8+P6+P4+P5+P3+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P4+P5+P1+K|xxxxxxk;P12+P8+P7+P4+P5+P2+K|xxxxxxk;P12+P8+P7+P4+P5+P3+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P4+P5+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P4+P5+P2+P1+K|xxxxxxk;P12+P9+P4+P5+P3+P1+K|xxxxxxk;P12+P9+P4+P5+P3+P2+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P4+P5+P1+K|xxxxxxk;P12+P9+P6+P4+P5+P2+K|xxxxxxk;P12+P9+P6+P4+P5+P3+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P4+P5+P1+K|xxxxxxk;P12+P9+P7+P4+P5+P2+K|xxxxxxk;P12+P9+P7+P4+P5+P3+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P4+P5+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P4+P5+P1+K|xxxxxxk;P12+P9+P8+P4+P5+P2+K|xxxxxxk;P12+P9+P8+P4+P5+P3+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P4+P5+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P4+P5+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P4+P5+P3+P2+P1+K|xxxxxxk;P7+P4+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P5+P2+P1+K|xxxxxxk;P7+P6+P4+P5+P3+P1+K|xxxxxxk;P7+P6+P4+P5+P3+P2+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P4+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P5+P2+P1+K|xxxxxxk;P8+P6+P4+P5+P3+P1+K|xxxxxxk;P8+P6+P4+P5+P3+P2+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P4+P5+P2+P1+K|xxxxxxk;P8+P7+P4+P5+P3+P1+K|xxxxxxk;P8+P7+P4+P5+P3+P2+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P4+P5+P1+K|xxxxxxk;P8+P7+P6+P4+P5+P2+K|xxxxxxk;P8+P7+P6+P4+P5+P3+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P4+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P5+P2+P1+K|xxxxxxk;P9+P6+P4+P5+P3+P1+K|xxxxxxk;P9+P6+P4+P5+P3+P2+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P4+P5+P2+P1+K|xxxxxxk;P9+P7+P4+P5+P3+P1+K|xxxxxxk;P9+P7+P4+P5+P3+P2+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P4+P5+P1+K|xxxxxxk;P9+P7+P6+P4+P5+P2+K|xxxxxxk;P9+P7+P6+P4+P5+P3+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P4+P5+P2+P1+K|xxxxxxk;P9+P8+P4+P5+P3+P1+K|xxxxxxk;P9+P8+P4+P5+P3+P2+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P4+P5+P1+K|xxxxxxk;P9+P8+P6+P4+P5+P2+K|xxxxxxk;P9+P8+P6+P4+P5+P3+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P4+P5+P1+K|xxxxxxk;P9+P8+P7+P4+P5+P2+K|xxxxxxk;P9+P8+P7+P4+P5+P3+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P4+P5+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk swapped adjacent Slot elements "slot4" and "slot5" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot5~slot6 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P5+P6+P3+P2+P1+K|xxxxxxk;P10+P5+P6+P4+P2+P1+K|xxxxxxk;P10+P5+P6+P4+P3+P1+K|xxxxxxk;P10+P5+P6+P4+P3+P2+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P5+P6+P2+P1+K|xxxxxxk;P10+P7+P5+P6+P3+P1+K|xxxxxxk;P10+P7+P5+P6+P3+P2+K|xxxxxxk;P10+P7+P5+P6+P4+P1+K|xxxxxxk;P10+P7+P5+P6+P4+P2+K|xxxxxxk;P10+P7+P5+P6+P4+P3+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P5+P6+P2+P1+K|xxxxxxk;P10+P8+P5+P6+P3+P1+K|xxxxxxk;P10+P8+P5+P6+P3+P2+K|xxxxxxk;P10+P8+P5+P6+P4+P1+K|xxxxxxk;P10+P8+P5+P6+P4+P2+K|xxxxxxk;P10+P8+P5+P6+P4+P3+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P5+P6+P1+K|xxxxxxk;P10+P8+P7+P5+P6+P2+K|xxxxxxk;P10+P8+P7+P5+P6+P3+K|xxxxxxk;P10+P8+P7+P5+P6+P4+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P5+P6+P2+P1+K|xxxxxxk;P10+P9+P5+P6+P3+P1+K|xxxxxxk;P10+P9+P5+P6+P3+P2+K|xxxxxxk;P10+P9+P5+P6+P4+P1+K|xxxxxxk;P10+P9+P5+P6+P4+P2+K|xxxxxxk;P10+P9+P5+P6+P4+P3+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P5+P6+P1+K|xxxxxxk;P10+P9+P7+P5+P6+P2+K|xxxxxxk;P10+P9+P7+P5+P6+P3+K|xxxxxxk;P10+P9+P7+P5+P6+P4+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P5+P6+P1+K|xxxxxxk;P10+P9+P8+P5+P6+P2+K|xxxxxxk;P10+P9+P8+P5+P6+P3+K|xxxxxxk;P10+P9+P8+P5+P6+P4+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P5+P6+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P5+P6+P2+P1+K|xxxxxxk;P11+P10+P5+P6+P3+P1+K|xxxxxxk;P11+P10+P5+P6+P3+P2+K|xxxxxxk;P11+P10+P5+P6+P4+P1+K|xxxxxxk;P11+P10+P5+P6+P4+P2+K|xxxxxxk;P11+P10+P5+P6+P4+P3+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P5+P6+P1+K|xxxxxxk;P11+P10+P7+P5+P6+P2+K|xxxxxxk;P11+P10+P7+P5+P6+P3+K|xxxxxxk;P11+P10+P7+P5+P6+P4+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P5+P6+P1+K|xxxxxxk;P11+P10+P8+P5+P6+P2+K|xxxxxxk;P11+P10+P8+P5+P6+P3+K|xxxxxxk;P11+P10+P8+P5+P6+P4+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P5+P6+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P5+P6+P1+K|xxxxxxk;P11+P10+P9+P5+P6+P2+K|xxxxxxk;P11+P10+P9+P5+P6+P3+K|xxxxxxk;P11+P10+P9+P5+P6+P4+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P5+P6+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P5+P6+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P5+P6+P3+P2+P1+K|xxxxxxk;P11+P5+P6+P4+P2+P1+K|xxxxxxk;P11+P5+P6+P4+P3+P1+K|xxxxxxk;P11+P5+P6+P4+P3+P2+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P5+P6+P2+P1+K|xxxxxxk;P11+P7+P5+P6+P3+P1+K|xxxxxxk;P11+P7+P5+P6+P3+P2+K|xxxxxxk;P11+P7+P5+P6+P4+P1+K|xxxxxxk;P11+P7+P5+P6+P4+P2+K|xxxxxxk;P11+P7+P5+P6+P4+P3+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P5+P6+P2+P1+K|xxxxxxk;P11+P8+P5+P6+P3+P1+K|xxxxxxk;P11+P8+P5+P6+P3+P2+K|xxxxxxk;P11+P8+P5+P6+P4+P1+K|xxxxxxk;P11+P8+P5+P6+P4+P2+K|xxxxxxk;P11+P8+P5+P6+P4+P3+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P5+P6+P1+K|xxxxxxk;P11+P8+P7+P5+P6+P2+K|xxxxxxk;P11+P8+P7+P5+P6+P3+K|xxxxxxk;P11+P8+P7+P5+P6+P4+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P5+P6+P2+P1+K|xxxxxxk;P11+P9+P5+P6+P3+P1+K|xxxxxxk;P11+P9+P5+P6+P3+P2+K|xxxxxxk;P11+P9+P5+P6+P4+P1+K|xxxxxxk;P11+P9+P5+P6+P4+P2+K|xxxxxxk;P11+P9+P5+P6+P4+P3+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P5+P6+P1+K|xxxxxxk;P11+P9+P7+P5+P6+P2+K|xxxxxxk;P11+P9+P7+P5+P6+P3+K|xxxxxxk;P11+P9+P7+P5+P6+P4+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P5+P6+P1+K|xxxxxxk;P11+P9+P8+P5+P6+P2+K|xxxxxxk;P11+P9+P8+P5+P6+P3+K|xxxxxxk;P11+P9+P8+P5+P6+P4+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P5+P6+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P5+P6+P2+P1+K|xxxxxxk;P12+P10+P5+P6+P3+P1+K|xxxxxxk;P12+P10+P5+P6+P3+P2+K|xxxxxxk;P12+P10+P5+P6+P4+P1+K|xxxxxxk;P12+P10+P5+P6+P4+P2+K|xxxxxxk;P12+P10+P5+P6+P4+P3+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P5+P6+P1+K|xxxxxxk;P12+P10+P7+P5+P6+P2+K|xxxxxxk;P12+P10+P7+P5+P6+P3+K|xxxxxxk;P12+P10+P7+P5+P6+P4+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P5+P6+P1+K|xxxxxxk;P12+P10+P8+P5+P6+P2+K|xxxxxxk;P12+P10+P8+P5+P6+P3+K|xxxxxxk;P12+P10+P8+P5+P6+P4+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P5+P6+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P5+P6+P1+K|xxxxxxk;P12+P10+P9+P5+P6+P2+K|xxxxxxk;P12+P10+P9+P5+P6+P3+K|xxxxxxk;P12+P10+P9+P5+P6+P4+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P5+P6+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P5+P6+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P5+P6+P1+K|xxxxxxk;P12+P11+P10+P5+P6+P2+K|xxxxxxk;P12+P11+P10+P5+P6+P3+K|xxxxxxk;P12+P11+P10+P5+P6+P4+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P5+P6+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P5+P6+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P5+P6+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P5+P6+P2+P1+K|xxxxxxk;P12+P11+P5+P6+P3+P1+K|xxxxxxk;P12+P11+P5+P6+P3+P2+K|xxxxxxk;P12+P11+P5+P6+P4+P1+K|xxxxxxk;P12+P11+P5+P6+P4+P2+K|xxxxxxk;P12+P11+P5+P6+P4+P3+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P5+P6+P1+K|xxxxxxk;P12+P11+P7+P5+P6+P2+K|xxxxxxk;P12+P11+P7+P5+P6+P3+K|xxxxxxk;P12+P11+P7+P5+P6+P4+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P5+P6+P1+K|xxxxxxk;P12+P11+P8+P5+P6+P2+K|xxxxxxk;P12+P11+P8+P5+P6+P3+K|xxxxxxk;P12+P11+P8+P5+P6+P4+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P5+P6+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P5+P6+P1+K|xxxxxxk;P12+P11+P9+P5+P6+P2+K|xxxxxxk;P12+P11+P9+P5+P6+P3+K|xxxxxxk;P12+P11+P9+P5+P6+P4+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P5+P6+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P5+P6+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P5+P6+P3+P2+P1+K|xxxxxxk;P12+P5+P6+P4+P2+P1+K|xxxxxxk;P12+P5+P6+P4+P3+P1+K|xxxxxxk;P12+P5+P6+P4+P3+P2+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P5+P6+P2+P1+K|xxxxxxk;P12+P7+P5+P6+P3+P1+K|xxxxxxk;P12+P7+P5+P6+P3+P2+K|xxxxxxk;P12+P7+P5+P6+P4+P1+K|xxxxxxk;P12+P7+P5+P6+P4+P2+K|xxxxxxk;P12+P7+P5+P6+P4+P3+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P5+P6+P2+P1+K|xxxxxxk;P12+P8+P5+P6+P3+P1+K|xxxxxxk;P12+P8+P5+P6+P3+P2+K|xxxxxxk;P12+P8+P5+P6+P4+P1+K|xxxxxxk;P12+P8+P5+P6+P4+P2+K|xxxxxxk;P12+P8+P5+P6+P4+P3+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P5+P6+P1+K|xxxxxxk;P12+P8+P7+P5+P6+P2+K|xxxxxxk;P12+P8+P7+P5+P6+P3+K|xxxxxxk;P12+P8+P7+P5+P6+P4+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P5+P6+P2+P1+K|xxxxxxk;P12+P9+P5+P6+P3+P1+K|xxxxxxk;P12+P9+P5+P6+P3+P2+K|xxxxxxk;P12+P9+P5+P6+P4+P1+K|xxxxxxk;P12+P9+P5+P6+P4+P2+K|xxxxxxk;P12+P9+P5+P6+P4+P3+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P5+P6+P1+K|xxxxxxk;P12+P9+P7+P5+P6+P2+K|xxxxxxk;P12+P9+P7+P5+P6+P3+K|xxxxxxk;P12+P9+P7+P5+P6+P4+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P5+P6+P1+K|xxxxxxk;P12+P9+P8+P5+P6+P2+K|xxxxxxk;P12+P9+P8+P5+P6+P3+K|xxxxxxk;P12+P9+P8+P5+P6+P4+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P5+P6+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P5+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P6+P3+P2+P1+K|xxxxxxk;P7+P5+P6+P4+P2+P1+K|xxxxxxk;P7+P5+P6+P4+P3+P1+K|xxxxxxk;P7+P5+P6+P4+P3+P2+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P5+P6+P3+P2+P1+K|xxxxxxk;P8+P5+P6+P4+P2+P1+K|xxxxxxk;P8+P5+P6+P4+P3+P1+K|xxxxxxk;P8+P5+P6+P4+P3+P2+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P5+P6+P2+P1+K|xxxxxxk;P8+P7+P5+P6+P3+P1+K|xxxxxxk;P8+P7+P5+P6+P3+P2+K|xxxxxxk;P8+P7+P5+P6+P4+P1+K|xxxxxxk;P8+P7+P5+P6+P4+P2+K|xxxxxxk;P8+P7+P5+P6+P4+P3+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P5+P6+P3+P2+P1+K|xxxxxxk;P9+P5+P6+P4+P2+P1+K|xxxxxxk;P9+P5+P6+P4+P3+P1+K|xxxxxxk;P9+P5+P6+P4+P3+P2+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P5+P6+P2+P1+K|xxxxxxk;P9+P7+P5+P6+P3+P1+K|xxxxxxk;P9+P7+P5+P6+P3+P2+K|xxxxxxk;P9+P7+P5+P6+P4+P1+K|xxxxxxk;P9+P7+P5+P6+P4+P2+K|xxxxxxk;P9+P7+P5+P6+P4+P3+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P5+P6+P2+P1+K|xxxxxxk;P9+P8+P5+P6+P3+P1+K|xxxxxxk;P9+P8+P5+P6+P3+P2+K|xxxxxxk;P9+P8+P5+P6+P4+P1+K|xxxxxxk;P9+P8+P5+P6+P4+P2+K|xxxxxxk;P9+P8+P5+P6+P4+P3+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P5+P6+P1+K|xxxxxxk;P9+P8+P7+P5+P6+P2+K|xxxxxxk;P9+P8+P7+P5+P6+P3+K|xxxxxxk;P9+P8+P7+P5+P6+P4+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk swapped adjacent Slot elements "slot5" and "slot6" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot6~slot7 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P6+P7+P3+P2+P1+K|xxxxxxk;P10+P6+P7+P4+P2+P1+K|xxxxxxk;P10+P6+P7+P4+P3+P1+K|xxxxxxk;P10+P6+P7+P4+P3+P2+K|xxxxxxk;P10+P6+P7+P5+P2+P1+K|xxxxxxk;P10+P6+P7+P5+P3+P1+K|xxxxxxk;P10+P6+P7+P5+P3+P2+K|xxxxxxk;P10+P6+P7+P5+P4+P1+K|xxxxxxk;P10+P6+P7+P5+P4+P2+K|xxxxxxk;P10+P6+P7+P5+P4+P3+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P6+P7+P2+P1+K|xxxxxxk;P10+P8+P6+P7+P3+P1+K|xxxxxxk;P10+P8+P6+P7+P3+P2+K|xxxxxxk;P10+P8+P6+P7+P4+P1+K|xxxxxxk;P10+P8+P6+P7+P4+P2+K|xxxxxxk;P10+P8+P6+P7+P4+P3+K|xxxxxxk;P10+P8+P6+P7+P5+P1+K|xxxxxxk;P10+P8+P6+P7+P5+P2+K|xxxxxxk;P10+P8+P6+P7+P5+P3+K|xxxxxxk;P10+P8+P6+P7+P5+P4+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P6+P7+P2+P1+K|xxxxxxk;P10+P9+P6+P7+P3+P1+K|xxxxxxk;P10+P9+P6+P7+P3+P2+K|xxxxxxk;P10+P9+P6+P7+P4+P1+K|xxxxxxk;P10+P9+P6+P7+P4+P2+K|xxxxxxk;P10+P9+P6+P7+P4+P3+K|xxxxxxk;P10+P9+P6+P7+P5+P1+K|xxxxxxk;P10+P9+P6+P7+P5+P2+K|xxxxxxk;P10+P9+P6+P7+P5+P3+K|xxxxxxk;P10+P9+P6+P7+P5+P4+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P6+P7+P1+K|xxxxxxk;P10+P9+P8+P6+P7+P2+K|xxxxxxk;P10+P9+P8+P6+P7+P3+K|xxxxxxk;P10+P9+P8+P6+P7+P4+K|xxxxxxk;P10+P9+P8+P6+P7+P5+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P6+P7+P2+P1+K|xxxxxxk;P11+P10+P6+P7+P3+P1+K|xxxxxxk;P11+P10+P6+P7+P3+P2+K|xxxxxxk;P11+P10+P6+P7+P4+P1+K|xxxxxxk;P11+P10+P6+P7+P4+P2+K|xxxxxxk;P11+P10+P6+P7+P4+P3+K|xxxxxxk;P11+P10+P6+P7+P5+P1+K|xxxxxxk;P11+P10+P6+P7+P5+P2+K|xxxxxxk;P11+P10+P6+P7+P5+P3+K|xxxxxxk;P11+P10+P6+P7+P5+P4+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P6+P7+P1+K|xxxxxxk;P11+P10+P8+P6+P7+P2+K|xxxxxxk;P11+P10+P8+P6+P7+P3+K|xxxxxxk;P11+P10+P8+P6+P7+P4+K|xxxxxxk;P11+P10+P8+P6+P7+P5+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P6+P7+P1+K|xxxxxxk;P11+P10+P9+P6+P7+P2+K|xxxxxxk;P11+P10+P9+P6+P7+P3+K|xxxxxxk;P11+P10+P9+P6+P7+P4+K|xxxxxxk;P11+P10+P9+P6+P7+P5+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P6+P7+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P6+P7+P3+P2+P1+K|xxxxxxk;P11+P6+P7+P4+P2+P1+K|xxxxxxk;P11+P6+P7+P4+P3+P1+K|xxxxxxk;P11+P6+P7+P4+P3+P2+K|xxxxxxk;P11+P6+P7+P5+P2+P1+K|xxxxxxk;P11+P6+P7+P5+P3+P1+K|xxxxxxk;P11+P6+P7+P5+P3+P2+K|xxxxxxk;P11+P6+P7+P5+P4+P1+K|xxxxxxk;P11+P6+P7+P5+P4+P2+K|xxxxxxk;P11+P6+P7+P5+P4+P3+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P6+P7+P2+P1+K|xxxxxxk;P11+P8+P6+P7+P3+P1+K|xxxxxxk;P11+P8+P6+P7+P3+P2+K|xxxxxxk;P11+P8+P6+P7+P4+P1+K|xxxxxxk;P11+P8+P6+P7+P4+P2+K|xxxxxxk;P11+P8+P6+P7+P4+P3+K|xxxxxxk;P11+P8+P6+P7+P5+P1+K|xxxxxxk;P11+P8+P6+P7+P5+P2+K|xxxxxxk;P11+P8+P6+P7+P5+P3+K|xxxxxxk;P11+P8+P6+P7+P5+P4+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P6+P7+P2+P1+K|xxxxxxk;P11+P9+P6+P7+P3+P1+K|xxxxxxk;P11+P9+P6+P7+P3+P2+K|xxxxxxk;P11+P9+P6+P7+P4+P1+K|xxxxxxk;P11+P9+P6+P7+P4+P2+K|xxxxxxk;P11+P9+P6+P7+P4+P3+K|xxxxxxk;P11+P9+P6+P7+P5+P1+K|xxxxxxk;P11+P9+P6+P7+P5+P2+K|xxxxxxk;P11+P9+P6+P7+P5+P3+K|xxxxxxk;P11+P9+P6+P7+P5+P4+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P6+P7+P1+K|xxxxxxk;P11+P9+P8+P6+P7+P2+K|xxxxxxk;P11+P9+P8+P6+P7+P3+K|xxxxxxk;P11+P9+P8+P6+P7+P4+K|xxxxxxk;P11+P9+P8+P6+P7+P5+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P6+P7+P2+P1+K|xxxxxxk;P12+P10+P6+P7+P3+P1+K|xxxxxxk;P12+P10+P6+P7+P3+P2+K|xxxxxxk;P12+P10+P6+P7+P4+P1+K|xxxxxxk;P12+P10+P6+P7+P4+P2+K|xxxxxxk;P12+P10+P6+P7+P4+P3+K|xxxxxxk;P12+P10+P6+P7+P5+P1+K|xxxxxxk;P12+P10+P6+P7+P5+P2+K|xxxxxxk;P12+P10+P6+P7+P5+P3+K|xxxxxxk;P12+P10+P6+P7+P5+P4+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P6+P7+P1+K|xxxxxxk;P12+P10+P8+P6+P7+P2+K|xxxxxxk;P12+P10+P8+P6+P7+P3+K|xxxxxxk;P12+P10+P8+P6+P7+P4+K|xxxxxxk;P12+P10+P8+P6+P7+P5+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P6+P7+P1+K|xxxxxxk;P12+P10+P9+P6+P7+P2+K|xxxxxxk;P12+P10+P9+P6+P7+P3+K|xxxxxxk;P12+P10+P9+P6+P7+P4+K|xxxxxxk;P12+P10+P9+P6+P7+P5+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P6+P7+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P6+P7+P1+K|xxxxxxk;P12+P11+P10+P6+P7+P2+K|xxxxxxk;P12+P11+P10+P6+P7+P3+K|xxxxxxk;P12+P11+P10+P6+P7+P4+K|xxxxxxk;P12+P11+P10+P6+P7+P5+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P6+P7+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P6+P7+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P6+P7+P2+P1+K|xxxxxxk;P12+P11+P6+P7+P3+P1+K|xxxxxxk;P12+P11+P6+P7+P3+P2+K|xxxxxxk;P12+P11+P6+P7+P4+P1+K|xxxxxxk;P12+P11+P6+P7+P4+P2+K|xxxxxxk;P12+P11+P6+P7+P4+P3+K|xxxxxxk;P12+P11+P6+P7+P5+P1+K|xxxxxxk;P12+P11+P6+P7+P5+P2+K|xxxxxxk;P12+P11+P6+P7+P5+P3+K|xxxxxxk;P12+P11+P6+P7+P5+P4+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P6+P7+P1+K|xxxxxxk;P12+P11+P8+P6+P7+P2+K|xxxxxxk;P12+P11+P8+P6+P7+P3+K|xxxxxxk;P12+P11+P8+P6+P7+P4+K|xxxxxxk;P12+P11+P8+P6+P7+P5+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P6+P7+P1+K|xxxxxxk;P12+P11+P9+P6+P7+P2+K|xxxxxxk;P12+P11+P9+P6+P7+P3+K|xxxxxxk;P12+P11+P9+P6+P7+P4+K|xxxxxxk;P12+P11+P9+P6+P7+P5+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P6+P7+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P6+P7+P3+P2+P1+K|xxxxxxk;P12+P6+P7+P4+P2+P1+K|xxxxxxk;P12+P6+P7+P4+P3+P1+K|xxxxxxk;P12+P6+P7+P4+P3+P2+K|xxxxxxk;P12+P6+P7+P5+P2+P1+K|xxxxxxk;P12+P6+P7+P5+P3+P1+K|xxxxxxk;P12+P6+P7+P5+P3+P2+K|xxxxxxk;P12+P6+P7+P5+P4+P1+K|xxxxxxk;P12+P6+P7+P5+P4+P2+K|xxxxxxk;P12+P6+P7+P5+P4+P3+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P6+P7+P2+P1+K|xxxxxxk;P12+P8+P6+P7+P3+P1+K|xxxxxxk;P12+P8+P6+P7+P3+P2+K|xxxxxxk;P12+P8+P6+P7+P4+P1+K|xxxxxxk;P12+P8+P6+P7+P4+P2+K|xxxxxxk;P12+P8+P6+P7+P4+P3+K|xxxxxxk;P12+P8+P6+P7+P5+P1+K|xxxxxxk;P12+P8+P6+P7+P5+P2+K|xxxxxxk;P12+P8+P6+P7+P5+P3+K|xxxxxxk;P12+P8+P6+P7+P5+P4+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P6+P7+P2+P1+K|xxxxxxk;P12+P9+P6+P7+P3+P1+K|xxxxxxk;P12+P9+P6+P7+P3+P2+K|xxxxxxk;P12+P9+P6+P7+P4+P1+K|xxxxxxk;P12+P9+P6+P7+P4+P2+K|xxxxxxk;P12+P9+P6+P7+P4+P3+K|xxxxxxk;P12+P9+P6+P7+P5+P1+K|xxxxxxk;P12+P9+P6+P7+P5+P2+K|xxxxxxk;P12+P9+P6+P7+P5+P3+K|xxxxxxk;P12+P9+P6+P7+P5+P4+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P6+P7+P1+K|xxxxxxk;P12+P9+P8+P6+P7+P2+K|xxxxxxk;P12+P9+P8+P6+P7+P3+K|xxxxxxk;P12+P9+P8+P6+P7+P4+K|xxxxxxk;P12+P9+P8+P6+P7+P5+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P6+P7+P4+P3+P2+P1+K|xxxxxxk;P6+P7+P5+P3+P2+P1+K|xxxxxxk;P6+P7+P5+P4+P2+P1+K|xxxxxxk;P6+P7+P5+P4+P3+P1+K|xxxxxxk;P6+P7+P5+P4+P3+P2+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P6+P7+P3+P2+P1+K|xxxxxxk;P8+P6+P7+P4+P2+P1+K|xxxxxxk;P8+P6+P7+P4+P3+P1+K|xxxxxxk;P8+P6+P7+P4+P3+P2+K|xxxxxxk;P8+P6+P7+P5+P2+P1+K|xxxxxxk;P8+P6+P7+P5+P3+P1+K|xxxxxxk;P8+P6+P7+P5+P3+P2+K|xxxxxxk;P8+P6+P7+P5+P4+P1+K|xxxxxxk;P8+P6+P7+P5+P4+P2+K|xxxxxxk;P8+P6+P7+P5+P4+P3+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P6+P7+P3+P2+P1+K|xxxxxxk;P9+P6+P7+P4+P2+P1+K|xxxxxxk;P9+P6+P7+P4+P3+P1+K|xxxxxxk;P9+P6+P7+P4+P3+P2+K|xxxxxxk;P9+P6+P7+P5+P2+P1+K|xxxxxxk;P9+P6+P7+P5+P3+P1+K|xxxxxxk;P9+P6+P7+P5+P3+P2+K|xxxxxxk;P9+P6+P7+P5+P4+P1+K|xxxxxxk;P9+P6+P7+P5+P4+P2+K|xxxxxxk;P9+P6+P7+P5+P4+P3+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P6+P7+P2+P1+K|xxxxxxk;P9+P8+P6+P7+P3+P1+K|xxxxxxk;P9+P8+P6+P7+P3+P2+K|xxxxxxk;P9+P8+P6+P7+P4+P1+K|xxxxxxk;P9+P8+P6+P7+P4+P2+K|xxxxxxk;P9+P8+P6+P7+P4+P3+K|xxxxxxk;P9+P8+P6+P7+P5+P1+K|xxxxxxk;P9+P8+P6+P7+P5+P2+K|xxxxxxk;P9+P8+P6+P7+P5+P3+K|xxxxxxk;P9+P8+P6+P7+P5+P4+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk swapped adjacent Slot elements "slot6" and "slot7" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot7~slot8 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P7+P8+P3+P2+P1+K|xxxxxxk;P10+P7+P8+P4+P2+P1+K|xxxxxxk;P10+P7+P8+P4+P3+P1+K|xxxxxxk;P10+P7+P8+P4+P3+P2+K|xxxxxxk;P10+P7+P8+P5+P2+P1+K|xxxxxxk;P10+P7+P8+P5+P3+P1+K|xxxxxxk;P10+P7+P8+P5+P3+P2+K|xxxxxxk;P10+P7+P8+P5+P4+P1+K|xxxxxxk;P10+P7+P8+P5+P4+P2+K|xxxxxxk;P10+P7+P8+P5+P4+P3+K|xxxxxxk;P10+P7+P8+P6+P2+P1+K|xxxxxxk;P10+P7+P8+P6+P3+P1+K|xxxxxxk;P10+P7+P8+P6+P3+P2+K|xxxxxxk;P10+P7+P8+P6+P4+P1+K|xxxxxxk;P10+P7+P8+P6+P4+P2+K|xxxxxxk;P10+P7+P8+P6+P4+P3+K|xxxxxxk;P10+P7+P8+P6+P5+P1+K|xxxxxxk;P10+P7+P8+P6+P5+P2+K|xxxxxxk;P10+P7+P8+P6+P5+P3+K|xxxxxxk;P10+P7+P8+P6+P5+P4+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P7+P8+P2+P1+K|xxxxxxk;P10+P9+P7+P8+P3+P1+K|xxxxxxk;P10+P9+P7+P8+P3+P2+K|xxxxxxk;P10+P9+P7+P8+P4+P1+K|xxxxxxk;P10+P9+P7+P8+P4+P2+K|xxxxxxk;P10+P9+P7+P8+P4+P3+K|xxxxxxk;P10+P9+P7+P8+P5+P1+K|xxxxxxk;P10+P9+P7+P8+P5+P2+K|xxxxxxk;P10+P9+P7+P8+P5+P3+K|xxxxxxk;P10+P9+P7+P8+P5+P4+K|xxxxxxk;P10+P9+P7+P8+P6+P1+K|xxxxxxk;P10+P9+P7+P8+P6+P2+K|xxxxxxk;P10+P9+P7+P8+P6+P3+K|xxxxxxk;P10+P9+P7+P8+P6+P4+K|xxxxxxk;P10+P9+P7+P8+P6+P5+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P7+P8+P2+P1+K|xxxxxxk;P11+P10+P7+P8+P3+P1+K|xxxxxxk;P11+P10+P7+P8+P3+P2+K|xxxxxxk;P11+P10+P7+P8+P4+P1+K|xxxxxxk;P11+P10+P7+P8+P4+P2+K|xxxxxxk;P11+P10+P7+P8+P4+P3+K|xxxxxxk;P11+P10+P7+P8+P5+P1+K|xxxxxxk;P11+P10+P7+P8+P5+P2+K|xxxxxxk;P11+P10+P7+P8+P5+P3+K|xxxxxxk;P11+P10+P7+P8+P5+P4+K|xxxxxxk;P11+P10+P7+P8+P6+P1+K|xxxxxxk;P11+P10+P7+P8+P6+P2+K|xxxxxxk;P11+P10+P7+P8+P6+P3+K|xxxxxxk;P11+P10+P7+P8+P6+P4+K|xxxxxxk;P11+P10+P7+P8+P6+P5+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P7+P8+P1+K|xxxxxxk;P11+P10+P9+P7+P8+P2+K|xxxxxxk;P11+P10+P9+P7+P8+P3+K|xxxxxxk;P11+P10+P9+P7+P8+P4+K|xxxxxxk;P11+P10+P9+P7+P8+P5+K|xxxxxxk;P11+P10+P9+P7+P8+P6+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P7+P8+P3+P2+P1+K|xxxxxxk;P11+P7+P8+P4+P2+P1+K|xxxxxxk;P11+P7+P8+P4+P3+P1+K|xxxxxxk;P11+P7+P8+P4+P3+P2+K|xxxxxxk;P11+P7+P8+P5+P2+P1+K|xxxxxxk;P11+P7+P8+P5+P3+P1+K|xxxxxxk;P11+P7+P8+P5+P3+P2+K|xxxxxxk;P11+P7+P8+P5+P4+P1+K|xxxxxxk;P11+P7+P8+P5+P4+P2+K|xxxxxxk;P11+P7+P8+P5+P4+P3+K|xxxxxxk;P11+P7+P8+P6+P2+P1+K|xxxxxxk;P11+P7+P8+P6+P3+P1+K|xxxxxxk;P11+P7+P8+P6+P3+P2+K|xxxxxxk;P11+P7+P8+P6+P4+P1+K|xxxxxxk;P11+P7+P8+P6+P4+P2+K|xxxxxxk;P11+P7+P8+P6+P4+P3+K|xxxxxxk;P11+P7+P8+P6+P5+P1+K|xxxxxxk;P11+P7+P8+P6+P5+P2+K|xxxxxxk;P11+P7+P8+P6+P5+P3+K|xxxxxxk;P11+P7+P8+P6+P5+P4+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P7+P8+P2+P1+K|xxxxxxk;P11+P9+P7+P8+P3+P1+K|xxxxxxk;P11+P9+P7+P8+P3+P2+K|xxxxxxk;P11+P9+P7+P8+P4+P1+K|xxxxxxk;P11+P9+P7+P8+P4+P2+K|xxxxxxk;P11+P9+P7+P8+P4+P3+K|xxxxxxk;P11+P9+P7+P8+P5+P1+K|xxxxxxk;P11+P9+P7+P8+P5+P2+K|xxxxxxk;P11+P9+P7+P8+P5+P3+K|xxxxxxk;P11+P9+P7+P8+P5+P4+K|xxxxxxk;P11+P9+P7+P8+P6+P1+K|xxxxxxk;P11+P9+P7+P8+P6+P2+K|xxxxxxk;P11+P9+P7+P8+P6+P3+K|xxxxxxk;P11+P9+P7+P8+P6+P4+K|xxxxxxk;P11+P9+P7+P8+P6+P5+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P7+P8+P2+P1+K|xxxxxxk;P12+P10+P7+P8+P3+P1+K|xxxxxxk;P12+P10+P7+P8+P3+P2+K|xxxxxxk;P12+P10+P7+P8+P4+P1+K|xxxxxxk;P12+P10+P7+P8+P4+P2+K|xxxxxxk;P12+P10+P7+P8+P4+P3+K|xxxxxxk;P12+P10+P7+P8+P5+P1+K|xxxxxxk;P12+P10+P7+P8+P5+P2+K|xxxxxxk;P12+P10+P7+P8+P5+P3+K|xxxxxxk;P12+P10+P7+P8+P5+P4+K|xxxxxxk;P12+P10+P7+P8+P6+P1+K|xxxxxxk;P12+P10+P7+P8+P6+P2+K|xxxxxxk;P12+P10+P7+P8+P6+P3+K|xxxxxxk;P12+P10+P7+P8+P6+P4+K|xxxxxxk;P12+P10+P7+P8+P6+P5+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P7+P8+P1+K|xxxxxxk;P12+P10+P9+P7+P8+P2+K|xxxxxxk;P12+P10+P9+P7+P8+P3+K|xxxxxxk;P12+P10+P9+P7+P8+P4+K|xxxxxxk;P12+P10+P9+P7+P8+P5+K|xxxxxxk;P12+P10+P9+P7+P8+P6+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P7+P8+P1+K|xxxxxxk;P12+P11+P10+P7+P8+P2+K|xxxxxxk;P12+P11+P10+P7+P8+P3+K|xxxxxxk;P12+P11+P10+P7+P8+P4+K|xxxxxxk;P12+P11+P10+P7+P8+P5+K|xxxxxxk;P12+P11+P10+P7+P8+P6+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P7+P8+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P7+P8+P2+P1+K|xxxxxxk;P12+P11+P7+P8+P3+P1+K|xxxxxxk;P12+P11+P7+P8+P3+P2+K|xxxxxxk;P12+P11+P7+P8+P4+P1+K|xxxxxxk;P12+P11+P7+P8+P4+P2+K|xxxxxxk;P12+P11+P7+P8+P4+P3+K|xxxxxxk;P12+P11+P7+P8+P5+P1+K|xxxxxxk;P12+P11+P7+P8+P5+P2+K|xxxxxxk;P12+P11+P7+P8+P5+P3+K|xxxxxxk;P12+P11+P7+P8+P5+P4+K|xxxxxxk;P12+P11+P7+P8+P6+P1+K|xxxxxxk;P12+P11+P7+P8+P6+P2+K|xxxxxxk;P12+P11+P7+P8+P6+P3+K|xxxxxxk;P12+P11+P7+P8+P6+P4+K|xxxxxxk;P12+P11+P7+P8+P6+P5+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P7+P8+P1+K|xxxxxxk;P12+P11+P9+P7+P8+P2+K|xxxxxxk;P12+P11+P9+P7+P8+P3+K|xxxxxxk;P12+P11+P9+P7+P8+P4+K|xxxxxxk;P12+P11+P9+P7+P8+P5+K|xxxxxxk;P12+P11+P9+P7+P8+P6+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P7+P8+P3+P2+P1+K|xxxxxxk;P12+P7+P8+P4+P2+P1+K|xxxxxxk;P12+P7+P8+P4+P3+P1+K|xxxxxxk;P12+P7+P8+P4+P3+P2+K|xxxxxxk;P12+P7+P8+P5+P2+P1+K|xxxxxxk;P12+P7+P8+P5+P3+P1+K|xxxxxxk;P12+P7+P8+P5+P3+P2+K|xxxxxxk;P12+P7+P8+P5+P4+P1+K|xxxxxxk;P12+P7+P8+P5+P4+P2+K|xxxxxxk;P12+P7+P8+P5+P4+P3+K|xxxxxxk;P12+P7+P8+P6+P2+P1+K|xxxxxxk;P12+P7+P8+P6+P3+P1+K|xxxxxxk;P12+P7+P8+P6+P3+P2+K|xxxxxxk;P12+P7+P8+P6+P4+P1+K|xxxxxxk;P12+P7+P8+P6+P4+P2+K|xxxxxxk;P12+P7+P8+P6+P4+P3+K|xxxxxxk;P12+P7+P8+P6+P5+P1+K|xxxxxxk;P12+P7+P8+P6+P5+P2+K|xxxxxxk;P12+P7+P8+P6+P5+P3+K|xxxxxxk;P12+P7+P8+P6+P5+P4+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P7+P8+P2+P1+K|xxxxxxk;P12+P9+P7+P8+P3+P1+K|xxxxxxk;P12+P9+P7+P8+P3+P2+K|xxxxxxk;P12+P9+P7+P8+P4+P1+K|xxxxxxk;P12+P9+P7+P8+P4+P2+K|xxxxxxk;P12+P9+P7+P8+P4+P3+K|xxxxxxk;P12+P9+P7+P8+P5+P1+K|xxxxxxk;P12+P9+P7+P8+P5+P2+K|xxxxxxk;P12+P9+P7+P8+P5+P3+K|xxxxxxk;P12+P9+P7+P8+P5+P4+K|xxxxxxk;P12+P9+P7+P8+P6+P1+K|xxxxxxk;P12+P9+P7+P8+P6+P2+K|xxxxxxk;P12+P9+P7+P8+P6+P3+K|xxxxxxk;P12+P9+P7+P8+P6+P4+K|xxxxxxk;P12+P9+P7+P8+P6+P5+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P7+P8+P4+P3+P2+P1+K|xxxxxxk;P7+P8+P5+P3+P2+P1+K|xxxxxxk;P7+P8+P5+P4+P2+P1+K|xxxxxxk;P7+P8+P5+P4+P3+P1+K|xxxxxxk;P7+P8+P5+P4+P3+P2+K|xxxxxxk;P7+P8+P6+P3+P2+P1+K|xxxxxxk;P7+P8+P6+P4+P2+P1+K|xxxxxxk;P7+P8+P6+P4+P3+P1+K|xxxxxxk;P7+P8+P6+P4+P3+P2+K|xxxxxxk;P7+P8+P6+P5+P2+P1+K|xxxxxxk;P7+P8+P6+P5+P3+P1+K|xxxxxxk;P7+P8+P6+P5+P3+P2+K|xxxxxxk;P7+P8+P6+P5+P4+P1+K|xxxxxxk;P7+P8+P6+P5+P4+P2+K|xxxxxxk;P7+P8+P6+P5+P4+P3+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P7+P8+P3+P2+P1+K|xxxxxxk;P9+P7+P8+P4+P2+P1+K|xxxxxxk;P9+P7+P8+P4+P3+P1+K|xxxxxxk;P9+P7+P8+P4+P3+P2+K|xxxxxxk;P9+P7+P8+P5+P2+P1+K|xxxxxxk;P9+P7+P8+P5+P3+P1+K|xxxxxxk;P9+P7+P8+P5+P3+P2+K|xxxxxxk;P9+P7+P8+P5+P4+P1+K|xxxxxxk;P9+P7+P8+P5+P4+P2+K|xxxxxxk;P9+P7+P8+P5+P4+P3+K|xxxxxxk;P9+P7+P8+P6+P2+P1+K|xxxxxxk;P9+P7+P8+P6+P3+P1+K|xxxxxxk;P9+P7+P8+P6+P3+P2+K|xxxxxxk;P9+P7+P8+P6+P4+P1+K|xxxxxxk;P9+P7+P8+P6+P4+P2+K|xxxxxxk;P9+P7+P8+P6+P4+P3+K|xxxxxxk;P9+P7+P8+P6+P5+P1+K|xxxxxxk;P9+P7+P8+P6+P5+P2+K|xxxxxxk;P9+P7+P8+P6+P5+P3+K|xxxxxxk;P9+P7+P8+P6+P5+P4+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk swapped adjacent Slot elements "slot7" and "slot8" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot8~slot9 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P8+P9+P3+P2+P1+K|xxxxxxk;P10+P8+P9+P4+P2+P1+K|xxxxxxk;P10+P8+P9+P4+P3+P1+K|xxxxxxk;P10+P8+P9+P4+P3+P2+K|xxxxxxk;P10+P8+P9+P5+P2+P1+K|xxxxxxk;P10+P8+P9+P5+P3+P1+K|xxxxxxk;P10+P8+P9+P5+P3+P2+K|xxxxxxk;P10+P8+P9+P5+P4+P1+K|xxxxxxk;P10+P8+P9+P5+P4+P2+K|xxxxxxk;P10+P8+P9+P5+P4+P3+K|xxxxxxk;P10+P8+P9+P6+P2+P1+K|xxxxxxk;P10+P8+P9+P6+P3+P1+K|xxxxxxk;P10+P8+P9+P6+P3+P2+K|xxxxxxk;P10+P8+P9+P6+P4+P1+K|xxxxxxk;P10+P8+P9+P6+P4+P2+K|xxxxxxk;P10+P8+P9+P6+P4+P3+K|xxxxxxk;P10+P8+P9+P6+P5+P1+K|xxxxxxk;P10+P8+P9+P6+P5+P2+K|xxxxxxk;P10+P8+P9+P6+P5+P3+K|xxxxxxk;P10+P8+P9+P6+P5+P4+K|xxxxxxk;P10+P8+P9+P7+P2+P1+K|xxxxxxk;P10+P8+P9+P7+P3+P1+K|xxxxxxk;P10+P8+P9+P7+P3+P2+K|xxxxxxk;P10+P8+P9+P7+P4+P1+K|xxxxxxk;P10+P8+P9+P7+P4+P2+K|xxxxxxk;P10+P8+P9+P7+P4+P3+K|xxxxxxk;P10+P8+P9+P7+P5+P1+K|xxxxxxk;P10+P8+P9+P7+P5+P2+K|xxxxxxk;P10+P8+P9+P7+P5+P3+K|xxxxxxk;P10+P8+P9+P7+P5+P4+K|xxxxxxk;P10+P8+P9+P7+P6+P1+K|xxxxxxk;P10+P8+P9+P7+P6+P2+K|xxxxxxk;P10+P8+P9+P7+P6+P3+K|xxxxxxk;P10+P8+P9+P7+P6+P4+K|xxxxxxk;P10+P8+P9+P7+P6+P5+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P8+P9+P2+P1+K|xxxxxxk;P11+P10+P8+P9+P3+P1+K|xxxxxxk;P11+P10+P8+P9+P3+P2+K|xxxxxxk;P11+P10+P8+P9+P4+P1+K|xxxxxxk;P11+P10+P8+P9+P4+P2+K|xxxxxxk;P11+P10+P8+P9+P4+P3+K|xxxxxxk;P11+P10+P8+P9+P5+P1+K|xxxxxxk;P11+P10+P8+P9+P5+P2+K|xxxxxxk;P11+P10+P8+P9+P5+P3+K|xxxxxxk;P11+P10+P8+P9+P5+P4+K|xxxxxxk;P11+P10+P8+P9+P6+P1+K|xxxxxxk;P11+P10+P8+P9+P6+P2+K|xxxxxxk;P11+P10+P8+P9+P6+P3+K|xxxxxxk;P11+P10+P8+P9+P6+P4+K|xxxxxxk;P11+P10+P8+P9+P6+P5+K|xxxxxxk;P11+P10+P8+P9+P7+P1+K|xxxxxxk;P11+P10+P8+P9+P7+P2+K|xxxxxxk;P11+P10+P8+P9+P7+P3+K|xxxxxxk;P11+P10+P8+P9+P7+P4+K|xxxxxxk;P11+P10+P8+P9+P7+P5+K|xxxxxxk;P11+P10+P8+P9+P7+P6+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P8+P9+P3+P2+P1+K|xxxxxxk;P11+P8+P9+P4+P2+P1+K|xxxxxxk;P11+P8+P9+P4+P3+P1+K|xxxxxxk;P11+P8+P9+P4+P3+P2+K|xxxxxxk;P11+P8+P9+P5+P2+P1+K|xxxxxxk;P11+P8+P9+P5+P3+P1+K|xxxxxxk;P11+P8+P9+P5+P3+P2+K|xxxxxxk;P11+P8+P9+P5+P4+P1+K|xxxxxxk;P11+P8+P9+P5+P4+P2+K|xxxxxxk;P11+P8+P9+P5+P4+P3+K|xxxxxxk;P11+P8+P9+P6+P2+P1+K|xxxxxxk;P11+P8+P9+P6+P3+P1+K|xxxxxxk;P11+P8+P9+P6+P3+P2+K|xxxxxxk;P11+P8+P9+P6+P4+P1+K|xxxxxxk;P11+P8+P9+P6+P4+P2+K|xxxxxxk;P11+P8+P9+P6+P4+P3+K|xxxxxxk;P11+P8+P9+P6+P5+P1+K|xxxxxxk;P11+P8+P9+P6+P5+P2+K|xxxxxxk;P11+P8+P9+P6+P5+P3+K|xxxxxxk;P11+P8+P9+P6+P5+P4+K|xxxxxxk;P11+P8+P9+P7+P2+P1+K|xxxxxxk;P11+P8+P9+P7+P3+P1+K|xxxxxxk;P11+P8+P9+P7+P3+P2+K|xxxxxxk;P11+P8+P9+P7+P4+P1+K|xxxxxxk;P11+P8+P9+P7+P4+P2+K|xxxxxxk;P11+P8+P9+P7+P4+P3+K|xxxxxxk;P11+P8+P9+P7+P5+P1+K|xxxxxxk;P11+P8+P9+P7+P5+P2+K|xxxxxxk;P11+P8+P9+P7+P5+P3+K|xxxxxxk;P11+P8+P9+P7+P5+P4+K|xxxxxxk;P11+P8+P9+P7+P6+P1+K|xxxxxxk;P11+P8+P9+P7+P6+P2+K|xxxxxxk;P11+P8+P9+P7+P6+P3+K|xxxxxxk;P11+P8+P9+P7+P6+P4+K|xxxxxxk;P11+P8+P9+P7+P6+P5+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P8+P9+P2+P1+K|xxxxxxk;P12+P10+P8+P9+P3+P1+K|xxxxxxk;P12+P10+P8+P9+P3+P2+K|xxxxxxk;P12+P10+P8+P9+P4+P1+K|xxxxxxk;P12+P10+P8+P9+P4+P2+K|xxxxxxk;P12+P10+P8+P9+P4+P3+K|xxxxxxk;P12+P10+P8+P9+P5+P1+K|xxxxxxk;P12+P10+P8+P9+P5+P2+K|xxxxxxk;P12+P10+P8+P9+P5+P3+K|xxxxxxk;P12+P10+P8+P9+P5+P4+K|xxxxxxk;P12+P10+P8+P9+P6+P1+K|xxxxxxk;P12+P10+P8+P9+P6+P2+K|xxxxxxk;P12+P10+P8+P9+P6+P3+K|xxxxxxk;P12+P10+P8+P9+P6+P4+K|xxxxxxk;P12+P10+P8+P9+P6+P5+K|xxxxxxk;P12+P10+P8+P9+P7+P1+K|xxxxxxk;P12+P10+P8+P9+P7+P2+K|xxxxxxk;P12+P10+P8+P9+P7+P3+K|xxxxxxk;P12+P10+P8+P9+P7+P4+K|xxxxxxk;P12+P10+P8+P9+P7+P5+K|xxxxxxk;P12+P10+P8+P9+P7+P6+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P8+P9+P1+K|xxxxxxk;P12+P11+P10+P8+P9+P2+K|xxxxxxk;P12+P11+P10+P8+P9+P3+K|xxxxxxk;P12+P11+P10+P8+P9+P4+K|xxxxxxk;P12+P11+P10+P8+P9+P5+K|xxxxxxk;P12+P11+P10+P8+P9+P6+K|xxxxxxk;P12+P11+P10+P8+P9+P7+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P8+P9+P2+P1+K|xxxxxxk;P12+P11+P8+P9+P3+P1+K|xxxxxxk;P12+P11+P8+P9+P3+P2+K|xxxxxxk;P12+P11+P8+P9+P4+P1+K|xxxxxxk;P12+P11+P8+P9+P4+P2+K|xxxxxxk;P12+P11+P8+P9+P4+P3+K|xxxxxxk;P12+P11+P8+P9+P5+P1+K|xxxxxxk;P12+P11+P8+P9+P5+P2+K|xxxxxxk;P12+P11+P8+P9+P5+P3+K|xxxxxxk;P12+P11+P8+P9+P5+P4+K|xxxxxxk;P12+P11+P8+P9+P6+P1+K|xxxxxxk;P12+P11+P8+P9+P6+P2+K|xxxxxxk;P12+P11+P8+P9+P6+P3+K|xxxxxxk;P12+P11+P8+P9+P6+P4+K|xxxxxxk;P12+P11+P8+P9+P6+P5+K|xxxxxxk;P12+P11+P8+P9+P7+P1+K|xxxxxxk;P12+P11+P8+P9+P7+P2+K|xxxxxxk;P12+P11+P8+P9+P7+P3+K|xxxxxxk;P12+P11+P8+P9+P7+P4+K|xxxxxxk;P12+P11+P8+P9+P7+P5+K|xxxxxxk;P12+P11+P8+P9+P7+P6+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P8+P9+P3+P2+P1+K|xxxxxxk;P12+P8+P9+P4+P2+P1+K|xxxxxxk;P12+P8+P9+P4+P3+P1+K|xxxxxxk;P12+P8+P9+P4+P3+P2+K|xxxxxxk;P12+P8+P9+P5+P2+P1+K|xxxxxxk;P12+P8+P9+P5+P3+P1+K|xxxxxxk;P12+P8+P9+P5+P3+P2+K|xxxxxxk;P12+P8+P9+P5+P4+P1+K|xxxxxxk;P12+P8+P9+P5+P4+P2+K|xxxxxxk;P12+P8+P9+P5+P4+P3+K|xxxxxxk;P12+P8+P9+P6+P2+P1+K|xxxxxxk;P12+P8+P9+P6+P3+P1+K|xxxxxxk;P12+P8+P9+P6+P3+P2+K|xxxxxxk;P12+P8+P9+P6+P4+P1+K|xxxxxxk;P12+P8+P9+P6+P4+P2+K|xxxxxxk;P12+P8+P9+P6+P4+P3+K|xxxxxxk;P12+P8+P9+P6+P5+P1+K|xxxxxxk;P12+P8+P9+P6+P5+P2+K|xxxxxxk;P12+P8+P9+P6+P5+P3+K|xxxxxxk;P12+P8+P9+P6+P5+P4+K|xxxxxxk;P12+P8+P9+P7+P2+P1+K|xxxxxxk;P12+P8+P9+P7+P3+P1+K|xxxxxxk;P12+P8+P9+P7+P3+P2+K|xxxxxxk;P12+P8+P9+P7+P4+P1+K|xxxxxxk;P12+P8+P9+P7+P4+P2+K|xxxxxxk;P12+P8+P9+P7+P4+P3+K|xxxxxxk;P12+P8+P9+P7+P5+P1+K|xxxxxxk;P12+P8+P9+P7+P5+P2+K|xxxxxxk;P12+P8+P9+P7+P5+P3+K|xxxxxxk;P12+P8+P9+P7+P5+P4+K|xxxxxxk;P12+P8+P9+P7+P6+P1+K|xxxxxxk;P12+P8+P9+P7+P6+P2+K|xxxxxxk;P12+P8+P9+P7+P6+P3+K|xxxxxxk;P12+P8+P9+P7+P6+P4+K|xxxxxxk;P12+P8+P9+P7+P6+P5+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P8+P9+P4+P3+P2+P1+K|xxxxxxk;P8+P9+P5+P3+P2+P1+K|xxxxxxk;P8+P9+P5+P4+P2+P1+K|xxxxxxk;P8+P9+P5+P4+P3+P1+K|xxxxxxk;P8+P9+P5+P4+P3+P2+K|xxxxxxk;P8+P9+P6+P3+P2+P1+K|xxxxxxk;P8+P9+P6+P4+P2+P1+K|xxxxxxk;P8+P9+P6+P4+P3+P1+K|xxxxxxk;P8+P9+P6+P4+P3+P2+K|xxxxxxk;P8+P9+P6+P5+P2+P1+K|xxxxxxk;P8+P9+P6+P5+P3+P1+K|xxxxxxk;P8+P9+P6+P5+P3+P2+K|xxxxxxk;P8+P9+P6+P5+P4+P1+K|xxxxxxk;P8+P9+P6+P5+P4+P2+K|xxxxxxk;P8+P9+P6+P5+P4+P3+K|xxxxxxk;P8+P9+P7+P3+P2+P1+K|xxxxxxk;P8+P9+P7+P4+P2+P1+K|xxxxxxk;P8+P9+P7+P4+P3+P1+K|xxxxxxk;P8+P9+P7+P4+P3+P2+K|xxxxxxk;P8+P9+P7+P5+P2+P1+K|xxxxxxk;P8+P9+P7+P5+P3+P1+K|xxxxxxk;P8+P9+P7+P5+P3+P2+K|xxxxxxk;P8+P9+P7+P5+P4+P1+K|xxxxxxk;P8+P9+P7+P5+P4+P2+K|xxxxxxk;P8+P9+P7+P5+P4+P3+K|xxxxxxk;P8+P9+P7+P6+P2+P1+K|xxxxxxk;P8+P9+P7+P6+P3+P1+K|xxxxxxk;P8+P9+P7+P6+P3+P2+K|xxxxxxk;P8+P9+P7+P6+P4+P1+K|xxxxxxk;P8+P9+P7+P6+P4+P2+K|xxxxxxk;P8+P9+P7+P6+P4+P3+K|xxxxxxk;P8+P9+P7+P6+P5+P1+K|xxxxxxk;P8+P9+P7+P6+P5+P2+K|xxxxxxk;P8+P9+P7+P6+P5+P3+K|xxxxxxk;P8+P9+P7+P6+P5+P4+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk swapped adjacent Slot elements "slot8" and "slot9" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/deep-optional-affix-nesting/slots/slot9~slot10 Ordering edge-cases/deep-optional-affix-nesting xxxxxxk ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P4+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P3+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P2+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P1+K|xxxxxxk;P10+P9+P5+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P3+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P2+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P1+K|xxxxxxk;P10+P9+P6+P4+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P2+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P1+K|xxxxxxk;P10+P9+P6+P5+P3+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P1+K|xxxxxxk;P10+P9+P6+P5+P4+P2+K|xxxxxxk;P10+P9+P6+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P3+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P2+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P1+K|xxxxxxk;P10+P9+P7+P4+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P2+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P1+K|xxxxxxk;P10+P9+P7+P5+P3+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P1+K|xxxxxxk;P10+P9+P7+P5+P4+P2+K|xxxxxxk;P10+P9+P7+P5+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P2+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P1+K|xxxxxxk;P10+P9+P7+P6+P3+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P1+K|xxxxxxk;P10+P9+P7+P6+P4+P2+K|xxxxxxk;P10+P9+P7+P6+P4+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P1+K|xxxxxxk;P10+P9+P7+P6+P5+P2+K|xxxxxxk;P10+P9+P7+P6+P5+P3+K|xxxxxxk;P10+P9+P7+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P3+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P2+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P1+K|xxxxxxk;P10+P9+P8+P4+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P2+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P1+K|xxxxxxk;P10+P9+P8+P5+P3+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P1+K|xxxxxxk;P10+P9+P8+P5+P4+P2+K|xxxxxxk;P10+P9+P8+P5+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P2+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P1+K|xxxxxxk;P10+P9+P8+P6+P3+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P1+K|xxxxxxk;P10+P9+P8+P6+P4+P2+K|xxxxxxk;P10+P9+P8+P6+P4+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P1+K|xxxxxxk;P10+P9+P8+P6+P5+P2+K|xxxxxxk;P10+P9+P8+P6+P5+P3+K|xxxxxxk;P10+P9+P8+P6+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P2+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P1+K|xxxxxxk;P10+P9+P8+P7+P3+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P1+K|xxxxxxk;P10+P9+P8+P7+P4+P2+K|xxxxxxk;P10+P9+P8+P7+P4+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P1+K|xxxxxxk;P10+P9+P8+P7+P5+P2+K|xxxxxxk;P10+P9+P8+P7+P5+P3+K|xxxxxxk;P10+P9+P8+P7+P5+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P1+K|xxxxxxk;P10+P9+P8+P7+P6+P2+K|xxxxxxk;P10+P9+P8+P7+P6+P3+K|xxxxxxk;P10+P9+P8+P7+P6+P4+K|xxxxxxk;P10+P9+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P3+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P2+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P1+K|xxxxxxk;P11+P10+P9+P4+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P2+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P1+K|xxxxxxk;P11+P10+P9+P5+P3+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P1+K|xxxxxxk;P11+P10+P9+P5+P4+P2+K|xxxxxxk;P11+P10+P9+P5+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P2+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P1+K|xxxxxxk;P11+P10+P9+P6+P3+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P1+K|xxxxxxk;P11+P10+P9+P6+P4+P2+K|xxxxxxk;P11+P10+P9+P6+P4+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P1+K|xxxxxxk;P11+P10+P9+P6+P5+P2+K|xxxxxxk;P11+P10+P9+P6+P5+P3+K|xxxxxxk;P11+P10+P9+P6+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P2+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P1+K|xxxxxxk;P11+P10+P9+P7+P3+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P1+K|xxxxxxk;P11+P10+P9+P7+P4+P2+K|xxxxxxk;P11+P10+P9+P7+P4+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P1+K|xxxxxxk;P11+P10+P9+P7+P5+P2+K|xxxxxxk;P11+P10+P9+P7+P5+P3+K|xxxxxxk;P11+P10+P9+P7+P5+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P1+K|xxxxxxk;P11+P10+P9+P7+P6+P2+K|xxxxxxk;P11+P10+P9+P7+P6+P3+K|xxxxxxk;P11+P10+P9+P7+P6+P4+K|xxxxxxk;P11+P10+P9+P7+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P2+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P1+K|xxxxxxk;P11+P10+P9+P8+P3+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P1+K|xxxxxxk;P11+P10+P9+P8+P4+P2+K|xxxxxxk;P11+P10+P9+P8+P4+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P1+K|xxxxxxk;P11+P10+P9+P8+P5+P2+K|xxxxxxk;P11+P10+P9+P8+P5+P3+K|xxxxxxk;P11+P10+P9+P8+P5+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P1+K|xxxxxxk;P11+P10+P9+P8+P6+P2+K|xxxxxxk;P11+P10+P9+P8+P6+P3+K|xxxxxxk;P11+P10+P9+P8+P6+P4+K|xxxxxxk;P11+P10+P9+P8+P6+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P1+K|xxxxxxk;P11+P10+P9+P8+P7+P2+K|xxxxxxk;P11+P10+P9+P8+P7+P3+K|xxxxxxk;P11+P10+P9+P8+P7+P4+K|xxxxxxk;P11+P10+P9+P8+P7+P5+K|xxxxxxk;P11+P10+P9+P8+P7+P6+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P3+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P2+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P1+K|xxxxxxk;P12+P10+P9+P4+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P2+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P1+K|xxxxxxk;P12+P10+P9+P5+P3+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P1+K|xxxxxxk;P12+P10+P9+P5+P4+P2+K|xxxxxxk;P12+P10+P9+P5+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P2+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P1+K|xxxxxxk;P12+P10+P9+P6+P3+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P1+K|xxxxxxk;P12+P10+P9+P6+P4+P2+K|xxxxxxk;P12+P10+P9+P6+P4+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P1+K|xxxxxxk;P12+P10+P9+P6+P5+P2+K|xxxxxxk;P12+P10+P9+P6+P5+P3+K|xxxxxxk;P12+P10+P9+P6+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P2+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P1+K|xxxxxxk;P12+P10+P9+P7+P3+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P1+K|xxxxxxk;P12+P10+P9+P7+P4+P2+K|xxxxxxk;P12+P10+P9+P7+P4+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P1+K|xxxxxxk;P12+P10+P9+P7+P5+P2+K|xxxxxxk;P12+P10+P9+P7+P5+P3+K|xxxxxxk;P12+P10+P9+P7+P5+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P1+K|xxxxxxk;P12+P10+P9+P7+P6+P2+K|xxxxxxk;P12+P10+P9+P7+P6+P3+K|xxxxxxk;P12+P10+P9+P7+P6+P4+K|xxxxxxk;P12+P10+P9+P7+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P2+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P1+K|xxxxxxk;P12+P10+P9+P8+P3+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P1+K|xxxxxxk;P12+P10+P9+P8+P4+P2+K|xxxxxxk;P12+P10+P9+P8+P4+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P1+K|xxxxxxk;P12+P10+P9+P8+P5+P2+K|xxxxxxk;P12+P10+P9+P8+P5+P3+K|xxxxxxk;P12+P10+P9+P8+P5+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P1+K|xxxxxxk;P12+P10+P9+P8+P6+P2+K|xxxxxxk;P12+P10+P9+P8+P6+P3+K|xxxxxxk;P12+P10+P9+P8+P6+P4+K|xxxxxxk;P12+P10+P9+P8+P6+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P1+K|xxxxxxk;P12+P10+P9+P8+P7+P2+K|xxxxxxk;P12+P10+P9+P8+P7+P3+K|xxxxxxk;P12+P10+P9+P8+P7+P4+K|xxxxxxk;P12+P10+P9+P8+P7+P5+K|xxxxxxk;P12+P10+P9+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P2+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P1+K|xxxxxxk;P12+P11+P10+P9+P3+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P1+K|xxxxxxk;P12+P11+P10+P9+P4+P2+K|xxxxxxk;P12+P11+P10+P9+P4+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P1+K|xxxxxxk;P12+P11+P10+P9+P5+P2+K|xxxxxxk;P12+P11+P10+P9+P5+P3+K|xxxxxxk;P12+P11+P10+P9+P5+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P1+K|xxxxxxk;P12+P11+P10+P9+P6+P2+K|xxxxxxk;P12+P11+P10+P9+P6+P3+K|xxxxxxk;P12+P11+P10+P9+P6+P4+K|xxxxxxk;P12+P11+P10+P9+P6+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P1+K|xxxxxxk;P12+P11+P10+P9+P7+P2+K|xxxxxxk;P12+P11+P10+P9+P7+P3+K|xxxxxxk;P12+P11+P10+P9+P7+P4+K|xxxxxxk;P12+P11+P10+P9+P7+P5+K|xxxxxxk;P12+P11+P10+P9+P7+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P1+K|xxxxxxk;P12+P11+P10+P9+P8+P2+K|xxxxxxk;P12+P11+P10+P9+P8+P3+K|xxxxxxk;P12+P11+P10+P9+P8+P4+K|xxxxxxk;P12+P11+P10+P9+P8+P5+K|xxxxxxk;P12+P11+P10+P9+P8+P6+K|xxxxxxk;P12+P11+P10+P9+P8+P7+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk Word ok::P10+P5+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P4+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P3+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P2+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P1+K|xxxxxxk;P10+P6+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P4+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P3+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P2+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P1+K|xxxxxxk;P10+P7+P5+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P3+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P2+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P1+K|xxxxxxk;P10+P7+P6+P4+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P2+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P1+K|xxxxxxk;P10+P7+P6+P5+P3+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P1+K|xxxxxxk;P10+P7+P6+P5+P4+P2+K|xxxxxxk;P10+P7+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P4+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P3+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P2+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P1+K|xxxxxxk;P10+P8+P5+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P3+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P2+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P1+K|xxxxxxk;P10+P8+P6+P4+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P2+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P1+K|xxxxxxk;P10+P8+P6+P5+P3+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P1+K|xxxxxxk;P10+P8+P6+P5+P4+P2+K|xxxxxxk;P10+P8+P6+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P3+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P2+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P1+K|xxxxxxk;P10+P8+P7+P4+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P2+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P1+K|xxxxxxk;P10+P8+P7+P5+P3+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P1+K|xxxxxxk;P10+P8+P7+P5+P4+P2+K|xxxxxxk;P10+P8+P7+P5+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P2+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P1+K|xxxxxxk;P10+P8+P7+P6+P3+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P1+K|xxxxxxk;P10+P8+P7+P6+P4+P2+K|xxxxxxk;P10+P8+P7+P6+P4+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P1+K|xxxxxxk;P10+P8+P7+P6+P5+P2+K|xxxxxxk;P10+P8+P7+P6+P5+P3+K|xxxxxxk;P10+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P4+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P3+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P2+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P1+K|xxxxxxk;P11+P10+P5+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P3+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P2+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P1+K|xxxxxxk;P11+P10+P6+P4+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P2+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P1+K|xxxxxxk;P11+P10+P6+P5+P3+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P1+K|xxxxxxk;P11+P10+P6+P5+P4+P2+K|xxxxxxk;P11+P10+P6+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P3+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P2+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P1+K|xxxxxxk;P11+P10+P7+P4+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P2+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P1+K|xxxxxxk;P11+P10+P7+P5+P3+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P1+K|xxxxxxk;P11+P10+P7+P5+P4+P2+K|xxxxxxk;P11+P10+P7+P5+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P2+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P1+K|xxxxxxk;P11+P10+P7+P6+P3+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P1+K|xxxxxxk;P11+P10+P7+P6+P4+P2+K|xxxxxxk;P11+P10+P7+P6+P4+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P1+K|xxxxxxk;P11+P10+P7+P6+P5+P2+K|xxxxxxk;P11+P10+P7+P6+P5+P3+K|xxxxxxk;P11+P10+P7+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P3+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P2+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P1+K|xxxxxxk;P11+P10+P8+P4+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P2+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P1+K|xxxxxxk;P11+P10+P8+P5+P3+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P1+K|xxxxxxk;P11+P10+P8+P5+P4+P2+K|xxxxxxk;P11+P10+P8+P5+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P2+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P1+K|xxxxxxk;P11+P10+P8+P6+P3+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P1+K|xxxxxxk;P11+P10+P8+P6+P4+P2+K|xxxxxxk;P11+P10+P8+P6+P4+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P1+K|xxxxxxk;P11+P10+P8+P6+P5+P2+K|xxxxxxk;P11+P10+P8+P6+P5+P3+K|xxxxxxk;P11+P10+P8+P6+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P2+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P1+K|xxxxxxk;P11+P10+P8+P7+P3+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P1+K|xxxxxxk;P11+P10+P8+P7+P4+P2+K|xxxxxxk;P11+P10+P8+P7+P4+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P1+K|xxxxxxk;P11+P10+P8+P7+P5+P2+K|xxxxxxk;P11+P10+P8+P7+P5+P3+K|xxxxxxk;P11+P10+P8+P7+P5+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P1+K|xxxxxxk;P11+P10+P8+P7+P6+P2+K|xxxxxxk;P11+P10+P8+P7+P6+P3+K|xxxxxxk;P11+P10+P8+P7+P6+P4+K|xxxxxxk;P11+P10+P8+P7+P6+P5+K|xxxxxxk;P11+P5+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P4+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P3+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P2+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P1+K|xxxxxxk;P11+P6+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P4+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P3+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P2+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P1+K|xxxxxxk;P11+P7+P5+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P3+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P2+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P1+K|xxxxxxk;P11+P7+P6+P4+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P2+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P1+K|xxxxxxk;P11+P7+P6+P5+P3+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P1+K|xxxxxxk;P11+P7+P6+P5+P4+P2+K|xxxxxxk;P11+P7+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P4+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P3+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P2+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P1+K|xxxxxxk;P11+P8+P5+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P3+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P2+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P1+K|xxxxxxk;P11+P8+P6+P4+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P2+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P1+K|xxxxxxk;P11+P8+P6+P5+P3+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P1+K|xxxxxxk;P11+P8+P6+P5+P4+P2+K|xxxxxxk;P11+P8+P6+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P3+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P2+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P1+K|xxxxxxk;P11+P8+P7+P4+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P2+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P1+K|xxxxxxk;P11+P8+P7+P5+P3+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P1+K|xxxxxxk;P11+P8+P7+P5+P4+P2+K|xxxxxxk;P11+P8+P7+P5+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P2+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P1+K|xxxxxxk;P11+P8+P7+P6+P3+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P1+K|xxxxxxk;P11+P8+P7+P6+P4+P2+K|xxxxxxk;P11+P8+P7+P6+P4+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P1+K|xxxxxxk;P11+P8+P7+P6+P5+P2+K|xxxxxxk;P11+P8+P7+P6+P5+P3+K|xxxxxxk;P11+P8+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P10+P3+P2+P1+K|xxxxxxk;P11+P9+P10+P4+P2+P1+K|xxxxxxk;P11+P9+P10+P4+P3+P1+K|xxxxxxk;P11+P9+P10+P4+P3+P2+K|xxxxxxk;P11+P9+P10+P5+P2+P1+K|xxxxxxk;P11+P9+P10+P5+P3+P1+K|xxxxxxk;P11+P9+P10+P5+P3+P2+K|xxxxxxk;P11+P9+P10+P5+P4+P1+K|xxxxxxk;P11+P9+P10+P5+P4+P2+K|xxxxxxk;P11+P9+P10+P5+P4+P3+K|xxxxxxk;P11+P9+P10+P6+P2+P1+K|xxxxxxk;P11+P9+P10+P6+P3+P1+K|xxxxxxk;P11+P9+P10+P6+P3+P2+K|xxxxxxk;P11+P9+P10+P6+P4+P1+K|xxxxxxk;P11+P9+P10+P6+P4+P2+K|xxxxxxk;P11+P9+P10+P6+P4+P3+K|xxxxxxk;P11+P9+P10+P6+P5+P1+K|xxxxxxk;P11+P9+P10+P6+P5+P2+K|xxxxxxk;P11+P9+P10+P6+P5+P3+K|xxxxxxk;P11+P9+P10+P6+P5+P4+K|xxxxxxk;P11+P9+P10+P7+P2+P1+K|xxxxxxk;P11+P9+P10+P7+P3+P1+K|xxxxxxk;P11+P9+P10+P7+P3+P2+K|xxxxxxk;P11+P9+P10+P7+P4+P1+K|xxxxxxk;P11+P9+P10+P7+P4+P2+K|xxxxxxk;P11+P9+P10+P7+P4+P3+K|xxxxxxk;P11+P9+P10+P7+P5+P1+K|xxxxxxk;P11+P9+P10+P7+P5+P2+K|xxxxxxk;P11+P9+P10+P7+P5+P3+K|xxxxxxk;P11+P9+P10+P7+P5+P4+K|xxxxxxk;P11+P9+P10+P7+P6+P1+K|xxxxxxk;P11+P9+P10+P7+P6+P2+K|xxxxxxk;P11+P9+P10+P7+P6+P3+K|xxxxxxk;P11+P9+P10+P7+P6+P4+K|xxxxxxk;P11+P9+P10+P7+P6+P5+K|xxxxxxk;P11+P9+P10+P8+P2+P1+K|xxxxxxk;P11+P9+P10+P8+P3+P1+K|xxxxxxk;P11+P9+P10+P8+P3+P2+K|xxxxxxk;P11+P9+P10+P8+P4+P1+K|xxxxxxk;P11+P9+P10+P8+P4+P2+K|xxxxxxk;P11+P9+P10+P8+P4+P3+K|xxxxxxk;P11+P9+P10+P8+P5+P1+K|xxxxxxk;P11+P9+P10+P8+P5+P2+K|xxxxxxk;P11+P9+P10+P8+P5+P3+K|xxxxxxk;P11+P9+P10+P8+P5+P4+K|xxxxxxk;P11+P9+P10+P8+P6+P1+K|xxxxxxk;P11+P9+P10+P8+P6+P2+K|xxxxxxk;P11+P9+P10+P8+P6+P3+K|xxxxxxk;P11+P9+P10+P8+P6+P4+K|xxxxxxk;P11+P9+P10+P8+P6+P5+K|xxxxxxk;P11+P9+P10+P8+P7+P1+K|xxxxxxk;P11+P9+P10+P8+P7+P2+K|xxxxxxk;P11+P9+P10+P8+P7+P3+K|xxxxxxk;P11+P9+P10+P8+P7+P4+K|xxxxxxk;P11+P9+P10+P8+P7+P5+K|xxxxxxk;P11+P9+P10+P8+P7+P6+K|xxxxxxk;P11+P9+P4+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P3+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P2+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P1+K|xxxxxxk;P11+P9+P5+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P3+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P2+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P1+K|xxxxxxk;P11+P9+P6+P4+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P2+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P1+K|xxxxxxk;P11+P9+P6+P5+P3+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P1+K|xxxxxxk;P11+P9+P6+P5+P4+P2+K|xxxxxxk;P11+P9+P6+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P3+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P2+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P1+K|xxxxxxk;P11+P9+P7+P4+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P2+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P1+K|xxxxxxk;P11+P9+P7+P5+P3+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P1+K|xxxxxxk;P11+P9+P7+P5+P4+P2+K|xxxxxxk;P11+P9+P7+P5+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P2+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P1+K|xxxxxxk;P11+P9+P7+P6+P3+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P1+K|xxxxxxk;P11+P9+P7+P6+P4+P2+K|xxxxxxk;P11+P9+P7+P6+P4+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P1+K|xxxxxxk;P11+P9+P7+P6+P5+P2+K|xxxxxxk;P11+P9+P7+P6+P5+P3+K|xxxxxxk;P11+P9+P7+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P3+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P2+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P1+K|xxxxxxk;P11+P9+P8+P4+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P2+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P1+K|xxxxxxk;P11+P9+P8+P5+P3+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P1+K|xxxxxxk;P11+P9+P8+P5+P4+P2+K|xxxxxxk;P11+P9+P8+P5+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P2+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P1+K|xxxxxxk;P11+P9+P8+P6+P3+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P1+K|xxxxxxk;P11+P9+P8+P6+P4+P2+K|xxxxxxk;P11+P9+P8+P6+P4+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P1+K|xxxxxxk;P11+P9+P8+P6+P5+P2+K|xxxxxxk;P11+P9+P8+P6+P5+P3+K|xxxxxxk;P11+P9+P8+P6+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P2+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P1+K|xxxxxxk;P11+P9+P8+P7+P3+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P1+K|xxxxxxk;P11+P9+P8+P7+P4+P2+K|xxxxxxk;P11+P9+P8+P7+P4+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P1+K|xxxxxxk;P11+P9+P8+P7+P5+P2+K|xxxxxxk;P11+P9+P8+P7+P5+P3+K|xxxxxxk;P11+P9+P8+P7+P5+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P1+K|xxxxxxk;P11+P9+P8+P7+P6+P2+K|xxxxxxk;P11+P9+P8+P7+P6+P3+K|xxxxxxk;P11+P9+P8+P7+P6+P4+K|xxxxxxk;P11+P9+P8+P7+P6+P5+K|xxxxxxk;P12+P10+P4+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P3+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P2+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P1+K|xxxxxxk;P12+P10+P5+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P3+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P2+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P1+K|xxxxxxk;P12+P10+P6+P4+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P2+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P1+K|xxxxxxk;P12+P10+P6+P5+P3+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P1+K|xxxxxxk;P12+P10+P6+P5+P4+P2+K|xxxxxxk;P12+P10+P6+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P3+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P2+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P1+K|xxxxxxk;P12+P10+P7+P4+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P2+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P1+K|xxxxxxk;P12+P10+P7+P5+P3+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P1+K|xxxxxxk;P12+P10+P7+P5+P4+P2+K|xxxxxxk;P12+P10+P7+P5+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P2+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P1+K|xxxxxxk;P12+P10+P7+P6+P3+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P1+K|xxxxxxk;P12+P10+P7+P6+P4+P2+K|xxxxxxk;P12+P10+P7+P6+P4+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P1+K|xxxxxxk;P12+P10+P7+P6+P5+P2+K|xxxxxxk;P12+P10+P7+P6+P5+P3+K|xxxxxxk;P12+P10+P7+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P3+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P2+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P1+K|xxxxxxk;P12+P10+P8+P4+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P2+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P1+K|xxxxxxk;P12+P10+P8+P5+P3+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P1+K|xxxxxxk;P12+P10+P8+P5+P4+P2+K|xxxxxxk;P12+P10+P8+P5+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P2+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P1+K|xxxxxxk;P12+P10+P8+P6+P3+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P1+K|xxxxxxk;P12+P10+P8+P6+P4+P2+K|xxxxxxk;P12+P10+P8+P6+P4+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P1+K|xxxxxxk;P12+P10+P8+P6+P5+P2+K|xxxxxxk;P12+P10+P8+P6+P5+P3+K|xxxxxxk;P12+P10+P8+P6+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P2+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P1+K|xxxxxxk;P12+P10+P8+P7+P3+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P1+K|xxxxxxk;P12+P10+P8+P7+P4+P2+K|xxxxxxk;P12+P10+P8+P7+P4+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P1+K|xxxxxxk;P12+P10+P8+P7+P5+P2+K|xxxxxxk;P12+P10+P8+P7+P5+P3+K|xxxxxxk;P12+P10+P8+P7+P5+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P1+K|xxxxxxk;P12+P10+P8+P7+P6+P2+K|xxxxxxk;P12+P10+P8+P7+P6+P3+K|xxxxxxk;P12+P10+P8+P7+P6+P4+K|xxxxxxk;P12+P10+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P3+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P2+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P1+K|xxxxxxk;P12+P11+P10+P4+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P2+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P1+K|xxxxxxk;P12+P11+P10+P5+P3+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P1+K|xxxxxxk;P12+P11+P10+P5+P4+P2+K|xxxxxxk;P12+P11+P10+P5+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P2+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P1+K|xxxxxxk;P12+P11+P10+P6+P3+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P1+K|xxxxxxk;P12+P11+P10+P6+P4+P2+K|xxxxxxk;P12+P11+P10+P6+P4+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P1+K|xxxxxxk;P12+P11+P10+P6+P5+P2+K|xxxxxxk;P12+P11+P10+P6+P5+P3+K|xxxxxxk;P12+P11+P10+P6+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P2+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P1+K|xxxxxxk;P12+P11+P10+P7+P3+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P1+K|xxxxxxk;P12+P11+P10+P7+P4+P2+K|xxxxxxk;P12+P11+P10+P7+P4+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P1+K|xxxxxxk;P12+P11+P10+P7+P5+P2+K|xxxxxxk;P12+P11+P10+P7+P5+P3+K|xxxxxxk;P12+P11+P10+P7+P5+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P1+K|xxxxxxk;P12+P11+P10+P7+P6+P2+K|xxxxxxk;P12+P11+P10+P7+P6+P3+K|xxxxxxk;P12+P11+P10+P7+P6+P4+K|xxxxxxk;P12+P11+P10+P7+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P2+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P1+K|xxxxxxk;P12+P11+P10+P8+P3+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P1+K|xxxxxxk;P12+P11+P10+P8+P4+P2+K|xxxxxxk;P12+P11+P10+P8+P4+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P1+K|xxxxxxk;P12+P11+P10+P8+P5+P2+K|xxxxxxk;P12+P11+P10+P8+P5+P3+K|xxxxxxk;P12+P11+P10+P8+P5+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P1+K|xxxxxxk;P12+P11+P10+P8+P6+P2+K|xxxxxxk;P12+P11+P10+P8+P6+P3+K|xxxxxxk;P12+P11+P10+P8+P6+P4+K|xxxxxxk;P12+P11+P10+P8+P6+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P1+K|xxxxxxk;P12+P11+P10+P8+P7+P2+K|xxxxxxk;P12+P11+P10+P8+P7+P3+K|xxxxxxk;P12+P11+P10+P8+P7+P4+K|xxxxxxk;P12+P11+P10+P8+P7+P5+K|xxxxxxk;P12+P11+P10+P8+P7+P6+K|xxxxxxk;P12+P11+P4+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P3+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P2+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P1+K|xxxxxxk;P12+P11+P5+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P3+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P2+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P1+K|xxxxxxk;P12+P11+P6+P4+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P2+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P1+K|xxxxxxk;P12+P11+P6+P5+P3+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P1+K|xxxxxxk;P12+P11+P6+P5+P4+P2+K|xxxxxxk;P12+P11+P6+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P3+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P2+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P1+K|xxxxxxk;P12+P11+P7+P4+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P2+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P1+K|xxxxxxk;P12+P11+P7+P5+P3+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P1+K|xxxxxxk;P12+P11+P7+P5+P4+P2+K|xxxxxxk;P12+P11+P7+P5+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P2+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P1+K|xxxxxxk;P12+P11+P7+P6+P3+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P1+K|xxxxxxk;P12+P11+P7+P6+P4+P2+K|xxxxxxk;P12+P11+P7+P6+P4+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P1+K|xxxxxxk;P12+P11+P7+P6+P5+P2+K|xxxxxxk;P12+P11+P7+P6+P5+P3+K|xxxxxxk;P12+P11+P7+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P3+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P2+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P1+K|xxxxxxk;P12+P11+P8+P4+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P2+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P1+K|xxxxxxk;P12+P11+P8+P5+P3+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P1+K|xxxxxxk;P12+P11+P8+P5+P4+P2+K|xxxxxxk;P12+P11+P8+P5+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P2+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P1+K|xxxxxxk;P12+P11+P8+P6+P3+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P1+K|xxxxxxk;P12+P11+P8+P6+P4+P2+K|xxxxxxk;P12+P11+P8+P6+P4+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P1+K|xxxxxxk;P12+P11+P8+P6+P5+P2+K|xxxxxxk;P12+P11+P8+P6+P5+P3+K|xxxxxxk;P12+P11+P8+P6+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P2+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P1+K|xxxxxxk;P12+P11+P8+P7+P3+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P1+K|xxxxxxk;P12+P11+P8+P7+P4+P2+K|xxxxxxk;P12+P11+P8+P7+P4+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P1+K|xxxxxxk;P12+P11+P8+P7+P5+P2+K|xxxxxxk;P12+P11+P8+P7+P5+P3+K|xxxxxxk;P12+P11+P8+P7+P5+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P1+K|xxxxxxk;P12+P11+P8+P7+P6+P2+K|xxxxxxk;P12+P11+P8+P7+P6+P3+K|xxxxxxk;P12+P11+P8+P7+P6+P4+K|xxxxxxk;P12+P11+P8+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P10+P2+P1+K|xxxxxxk;P12+P11+P9+P10+P3+P1+K|xxxxxxk;P12+P11+P9+P10+P3+P2+K|xxxxxxk;P12+P11+P9+P10+P4+P1+K|xxxxxxk;P12+P11+P9+P10+P4+P2+K|xxxxxxk;P12+P11+P9+P10+P4+P3+K|xxxxxxk;P12+P11+P9+P10+P5+P1+K|xxxxxxk;P12+P11+P9+P10+P5+P2+K|xxxxxxk;P12+P11+P9+P10+P5+P3+K|xxxxxxk;P12+P11+P9+P10+P5+P4+K|xxxxxxk;P12+P11+P9+P10+P6+P1+K|xxxxxxk;P12+P11+P9+P10+P6+P2+K|xxxxxxk;P12+P11+P9+P10+P6+P3+K|xxxxxxk;P12+P11+P9+P10+P6+P4+K|xxxxxxk;P12+P11+P9+P10+P6+P5+K|xxxxxxk;P12+P11+P9+P10+P7+P1+K|xxxxxxk;P12+P11+P9+P10+P7+P2+K|xxxxxxk;P12+P11+P9+P10+P7+P3+K|xxxxxxk;P12+P11+P9+P10+P7+P4+K|xxxxxxk;P12+P11+P9+P10+P7+P5+K|xxxxxxk;P12+P11+P9+P10+P7+P6+K|xxxxxxk;P12+P11+P9+P10+P8+P1+K|xxxxxxk;P12+P11+P9+P10+P8+P2+K|xxxxxxk;P12+P11+P9+P10+P8+P3+K|xxxxxxk;P12+P11+P9+P10+P8+P4+K|xxxxxxk;P12+P11+P9+P10+P8+P5+K|xxxxxxk;P12+P11+P9+P10+P8+P6+K|xxxxxxk;P12+P11+P9+P10+P8+P7+K|xxxxxxk;P12+P11+P9+P3+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P2+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P1+K|xxxxxxk;P12+P11+P9+P4+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P2+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P1+K|xxxxxxk;P12+P11+P9+P5+P3+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P1+K|xxxxxxk;P12+P11+P9+P5+P4+P2+K|xxxxxxk;P12+P11+P9+P5+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P2+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P1+K|xxxxxxk;P12+P11+P9+P6+P3+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P1+K|xxxxxxk;P12+P11+P9+P6+P4+P2+K|xxxxxxk;P12+P11+P9+P6+P4+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P1+K|xxxxxxk;P12+P11+P9+P6+P5+P2+K|xxxxxxk;P12+P11+P9+P6+P5+P3+K|xxxxxxk;P12+P11+P9+P6+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P2+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P1+K|xxxxxxk;P12+P11+P9+P7+P3+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P1+K|xxxxxxk;P12+P11+P9+P7+P4+P2+K|xxxxxxk;P12+P11+P9+P7+P4+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P1+K|xxxxxxk;P12+P11+P9+P7+P5+P2+K|xxxxxxk;P12+P11+P9+P7+P5+P3+K|xxxxxxk;P12+P11+P9+P7+P5+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P1+K|xxxxxxk;P12+P11+P9+P7+P6+P2+K|xxxxxxk;P12+P11+P9+P7+P6+P3+K|xxxxxxk;P12+P11+P9+P7+P6+P4+K|xxxxxxk;P12+P11+P9+P7+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P2+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P1+K|xxxxxxk;P12+P11+P9+P8+P3+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P1+K|xxxxxxk;P12+P11+P9+P8+P4+P2+K|xxxxxxk;P12+P11+P9+P8+P4+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P1+K|xxxxxxk;P12+P11+P9+P8+P5+P2+K|xxxxxxk;P12+P11+P9+P8+P5+P3+K|xxxxxxk;P12+P11+P9+P8+P5+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P1+K|xxxxxxk;P12+P11+P9+P8+P6+P2+K|xxxxxxk;P12+P11+P9+P8+P6+P3+K|xxxxxxk;P12+P11+P9+P8+P6+P4+K|xxxxxxk;P12+P11+P9+P8+P6+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P1+K|xxxxxxk;P12+P11+P9+P8+P7+P2+K|xxxxxxk;P12+P11+P9+P8+P7+P3+K|xxxxxxk;P12+P11+P9+P8+P7+P4+K|xxxxxxk;P12+P11+P9+P8+P7+P5+K|xxxxxxk;P12+P11+P9+P8+P7+P6+K|xxxxxxk;P12+P5+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P4+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P3+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P2+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P1+K|xxxxxxk;P12+P6+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P4+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P3+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P2+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P1+K|xxxxxxk;P12+P7+P5+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P3+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P2+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P1+K|xxxxxxk;P12+P7+P6+P4+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P2+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P1+K|xxxxxxk;P12+P7+P6+P5+P3+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P1+K|xxxxxxk;P12+P7+P6+P5+P4+P2+K|xxxxxxk;P12+P7+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P4+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P3+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P2+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P1+K|xxxxxxk;P12+P8+P5+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P3+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P2+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P1+K|xxxxxxk;P12+P8+P6+P4+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P2+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P1+K|xxxxxxk;P12+P8+P6+P5+P3+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P1+K|xxxxxxk;P12+P8+P6+P5+P4+P2+K|xxxxxxk;P12+P8+P6+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P3+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P2+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P1+K|xxxxxxk;P12+P8+P7+P4+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P2+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P1+K|xxxxxxk;P12+P8+P7+P5+P3+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P1+K|xxxxxxk;P12+P8+P7+P5+P4+P2+K|xxxxxxk;P12+P8+P7+P5+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P2+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P1+K|xxxxxxk;P12+P8+P7+P6+P3+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P1+K|xxxxxxk;P12+P8+P7+P6+P4+P2+K|xxxxxxk;P12+P8+P7+P6+P4+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P1+K|xxxxxxk;P12+P8+P7+P6+P5+P2+K|xxxxxxk;P12+P8+P7+P6+P5+P3+K|xxxxxxk;P12+P8+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P10+P3+P2+P1+K|xxxxxxk;P12+P9+P10+P4+P2+P1+K|xxxxxxk;P12+P9+P10+P4+P3+P1+K|xxxxxxk;P12+P9+P10+P4+P3+P2+K|xxxxxxk;P12+P9+P10+P5+P2+P1+K|xxxxxxk;P12+P9+P10+P5+P3+P1+K|xxxxxxk;P12+P9+P10+P5+P3+P2+K|xxxxxxk;P12+P9+P10+P5+P4+P1+K|xxxxxxk;P12+P9+P10+P5+P4+P2+K|xxxxxxk;P12+P9+P10+P5+P4+P3+K|xxxxxxk;P12+P9+P10+P6+P2+P1+K|xxxxxxk;P12+P9+P10+P6+P3+P1+K|xxxxxxk;P12+P9+P10+P6+P3+P2+K|xxxxxxk;P12+P9+P10+P6+P4+P1+K|xxxxxxk;P12+P9+P10+P6+P4+P2+K|xxxxxxk;P12+P9+P10+P6+P4+P3+K|xxxxxxk;P12+P9+P10+P6+P5+P1+K|xxxxxxk;P12+P9+P10+P6+P5+P2+K|xxxxxxk;P12+P9+P10+P6+P5+P3+K|xxxxxxk;P12+P9+P10+P6+P5+P4+K|xxxxxxk;P12+P9+P10+P7+P2+P1+K|xxxxxxk;P12+P9+P10+P7+P3+P1+K|xxxxxxk;P12+P9+P10+P7+P3+P2+K|xxxxxxk;P12+P9+P10+P7+P4+P1+K|xxxxxxk;P12+P9+P10+P7+P4+P2+K|xxxxxxk;P12+P9+P10+P7+P4+P3+K|xxxxxxk;P12+P9+P10+P7+P5+P1+K|xxxxxxk;P12+P9+P10+P7+P5+P2+K|xxxxxxk;P12+P9+P10+P7+P5+P3+K|xxxxxxk;P12+P9+P10+P7+P5+P4+K|xxxxxxk;P12+P9+P10+P7+P6+P1+K|xxxxxxk;P12+P9+P10+P7+P6+P2+K|xxxxxxk;P12+P9+P10+P7+P6+P3+K|xxxxxxk;P12+P9+P10+P7+P6+P4+K|xxxxxxk;P12+P9+P10+P7+P6+P5+K|xxxxxxk;P12+P9+P10+P8+P2+P1+K|xxxxxxk;P12+P9+P10+P8+P3+P1+K|xxxxxxk;P12+P9+P10+P8+P3+P2+K|xxxxxxk;P12+P9+P10+P8+P4+P1+K|xxxxxxk;P12+P9+P10+P8+P4+P2+K|xxxxxxk;P12+P9+P10+P8+P4+P3+K|xxxxxxk;P12+P9+P10+P8+P5+P1+K|xxxxxxk;P12+P9+P10+P8+P5+P2+K|xxxxxxk;P12+P9+P10+P8+P5+P3+K|xxxxxxk;P12+P9+P10+P8+P5+P4+K|xxxxxxk;P12+P9+P10+P8+P6+P1+K|xxxxxxk;P12+P9+P10+P8+P6+P2+K|xxxxxxk;P12+P9+P10+P8+P6+P3+K|xxxxxxk;P12+P9+P10+P8+P6+P4+K|xxxxxxk;P12+P9+P10+P8+P6+P5+K|xxxxxxk;P12+P9+P10+P8+P7+P1+K|xxxxxxk;P12+P9+P10+P8+P7+P2+K|xxxxxxk;P12+P9+P10+P8+P7+P3+K|xxxxxxk;P12+P9+P10+P8+P7+P4+K|xxxxxxk;P12+P9+P10+P8+P7+P5+K|xxxxxxk;P12+P9+P10+P8+P7+P6+K|xxxxxxk;P12+P9+P4+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P3+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P2+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P1+K|xxxxxxk;P12+P9+P5+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P3+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P2+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P1+K|xxxxxxk;P12+P9+P6+P4+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P2+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P1+K|xxxxxxk;P12+P9+P6+P5+P3+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P1+K|xxxxxxk;P12+P9+P6+P5+P4+P2+K|xxxxxxk;P12+P9+P6+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P3+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P2+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P1+K|xxxxxxk;P12+P9+P7+P4+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P2+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P1+K|xxxxxxk;P12+P9+P7+P5+P3+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P1+K|xxxxxxk;P12+P9+P7+P5+P4+P2+K|xxxxxxk;P12+P9+P7+P5+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P2+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P1+K|xxxxxxk;P12+P9+P7+P6+P3+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P1+K|xxxxxxk;P12+P9+P7+P6+P4+P2+K|xxxxxxk;P12+P9+P7+P6+P4+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P1+K|xxxxxxk;P12+P9+P7+P6+P5+P2+K|xxxxxxk;P12+P9+P7+P6+P5+P3+K|xxxxxxk;P12+P9+P7+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P3+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P2+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P1+K|xxxxxxk;P12+P9+P8+P4+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P2+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P1+K|xxxxxxk;P12+P9+P8+P5+P3+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P1+K|xxxxxxk;P12+P9+P8+P5+P4+P2+K|xxxxxxk;P12+P9+P8+P5+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P2+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P1+K|xxxxxxk;P12+P9+P8+P6+P3+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P1+K|xxxxxxk;P12+P9+P8+P6+P4+P2+K|xxxxxxk;P12+P9+P8+P6+P4+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P1+K|xxxxxxk;P12+P9+P8+P6+P5+P2+K|xxxxxxk;P12+P9+P8+P6+P5+P3+K|xxxxxxk;P12+P9+P8+P6+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P2+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P1+K|xxxxxxk;P12+P9+P8+P7+P3+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P1+K|xxxxxxk;P12+P9+P8+P7+P4+P2+K|xxxxxxk;P12+P9+P8+P7+P4+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P1+K|xxxxxxk;P12+P9+P8+P7+P5+P2+K|xxxxxxk;P12+P9+P8+P7+P5+P3+K|xxxxxxk;P12+P9+P8+P7+P5+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P1+K|xxxxxxk;P12+P9+P8+P7+P6+P2+K|xxxxxxk;P12+P9+P8+P7+P6+P3+K|xxxxxxk;P12+P9+P8+P7+P6+P4+K|xxxxxxk;P12+P9+P8+P7+P6+P5+K|xxxxxxk;P6+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P5+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P4+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P3+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P2+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P1+K|xxxxxxk;P7+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P5+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P4+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P3+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P2+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P1+K|xxxxxxk;P8+P6+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P4+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P3+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P2+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P1+K|xxxxxxk;P8+P7+P5+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P3+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P2+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P1+K|xxxxxxk;P8+P7+P6+P4+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P2+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P1+K|xxxxxxk;P8+P7+P6+P5+P3+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P1+K|xxxxxxk;P8+P7+P6+P5+P4+P2+K|xxxxxxk;P8+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P10+P4+P3+P2+P1+K|xxxxxxk;P9+P10+P5+P3+P2+P1+K|xxxxxxk;P9+P10+P5+P4+P2+P1+K|xxxxxxk;P9+P10+P5+P4+P3+P1+K|xxxxxxk;P9+P10+P5+P4+P3+P2+K|xxxxxxk;P9+P10+P6+P3+P2+P1+K|xxxxxxk;P9+P10+P6+P4+P2+P1+K|xxxxxxk;P9+P10+P6+P4+P3+P1+K|xxxxxxk;P9+P10+P6+P4+P3+P2+K|xxxxxxk;P9+P10+P6+P5+P2+P1+K|xxxxxxk;P9+P10+P6+P5+P3+P1+K|xxxxxxk;P9+P10+P6+P5+P3+P2+K|xxxxxxk;P9+P10+P6+P5+P4+P1+K|xxxxxxk;P9+P10+P6+P5+P4+P2+K|xxxxxxk;P9+P10+P6+P5+P4+P3+K|xxxxxxk;P9+P10+P7+P3+P2+P1+K|xxxxxxk;P9+P10+P7+P4+P2+P1+K|xxxxxxk;P9+P10+P7+P4+P3+P1+K|xxxxxxk;P9+P10+P7+P4+P3+P2+K|xxxxxxk;P9+P10+P7+P5+P2+P1+K|xxxxxxk;P9+P10+P7+P5+P3+P1+K|xxxxxxk;P9+P10+P7+P5+P3+P2+K|xxxxxxk;P9+P10+P7+P5+P4+P1+K|xxxxxxk;P9+P10+P7+P5+P4+P2+K|xxxxxxk;P9+P10+P7+P5+P4+P3+K|xxxxxxk;P9+P10+P7+P6+P2+P1+K|xxxxxxk;P9+P10+P7+P6+P3+P1+K|xxxxxxk;P9+P10+P7+P6+P3+P2+K|xxxxxxk;P9+P10+P7+P6+P4+P1+K|xxxxxxk;P9+P10+P7+P6+P4+P2+K|xxxxxxk;P9+P10+P7+P6+P4+P3+K|xxxxxxk;P9+P10+P7+P6+P5+P1+K|xxxxxxk;P9+P10+P7+P6+P5+P2+K|xxxxxxk;P9+P10+P7+P6+P5+P3+K|xxxxxxk;P9+P10+P7+P6+P5+P4+K|xxxxxxk;P9+P10+P8+P3+P2+P1+K|xxxxxxk;P9+P10+P8+P4+P2+P1+K|xxxxxxk;P9+P10+P8+P4+P3+P1+K|xxxxxxk;P9+P10+P8+P4+P3+P2+K|xxxxxxk;P9+P10+P8+P5+P2+P1+K|xxxxxxk;P9+P10+P8+P5+P3+P1+K|xxxxxxk;P9+P10+P8+P5+P3+P2+K|xxxxxxk;P9+P10+P8+P5+P4+P1+K|xxxxxxk;P9+P10+P8+P5+P4+P2+K|xxxxxxk;P9+P10+P8+P5+P4+P3+K|xxxxxxk;P9+P10+P8+P6+P2+P1+K|xxxxxxk;P9+P10+P8+P6+P3+P1+K|xxxxxxk;P9+P10+P8+P6+P3+P2+K|xxxxxxk;P9+P10+P8+P6+P4+P1+K|xxxxxxk;P9+P10+P8+P6+P4+P2+K|xxxxxxk;P9+P10+P8+P6+P4+P3+K|xxxxxxk;P9+P10+P8+P6+P5+P1+K|xxxxxxk;P9+P10+P8+P6+P5+P2+K|xxxxxxk;P9+P10+P8+P6+P5+P3+K|xxxxxxk;P9+P10+P8+P6+P5+P4+K|xxxxxxk;P9+P10+P8+P7+P2+P1+K|xxxxxxk;P9+P10+P8+P7+P3+P1+K|xxxxxxk;P9+P10+P8+P7+P3+P2+K|xxxxxxk;P9+P10+P8+P7+P4+P1+K|xxxxxxk;P9+P10+P8+P7+P4+P2+K|xxxxxxk;P9+P10+P8+P7+P4+P3+K|xxxxxxk;P9+P10+P8+P7+P5+P1+K|xxxxxxk;P9+P10+P8+P7+P5+P2+K|xxxxxxk;P9+P10+P8+P7+P5+P3+K|xxxxxxk;P9+P10+P8+P7+P5+P4+K|xxxxxxk;P9+P10+P8+P7+P6+P1+K|xxxxxxk;P9+P10+P8+P7+P6+P2+K|xxxxxxk;P9+P10+P8+P7+P6+P3+K|xxxxxxk;P9+P10+P8+P7+P6+P4+K|xxxxxxk;P9+P10+P8+P7+P6+P5+K|xxxxxxk;P9+P5+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P4+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P3+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P2+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P1+K|xxxxxxk;P9+P6+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P4+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P3+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P2+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P1+K|xxxxxxk;P9+P7+P5+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P3+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P2+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P1+K|xxxxxxk;P9+P7+P6+P4+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P2+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P1+K|xxxxxxk;P9+P7+P6+P5+P3+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P1+K|xxxxxxk;P9+P7+P6+P5+P4+P2+K|xxxxxxk;P9+P7+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P4+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P3+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P2+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P1+K|xxxxxxk;P9+P8+P5+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P3+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P2+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P1+K|xxxxxxk;P9+P8+P6+P4+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P2+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P1+K|xxxxxxk;P9+P8+P6+P5+P3+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P1+K|xxxxxxk;P9+P8+P6+P5+P4+P2+K|xxxxxxk;P9+P8+P6+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P3+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P2+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P1+K|xxxxxxk;P9+P8+P7+P4+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P2+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P1+K|xxxxxxk;P9+P8+P7+P5+P3+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P1+K|xxxxxxk;P9+P8+P7+P5+P4+P2+K|xxxxxxk;P9+P8+P7+P5+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P2+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P1+K|xxxxxxk;P9+P8+P7+P6+P3+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P1+K|xxxxxxk;P9+P8+P7+P6+P4+P2+K|xxxxxxk;P9+P8+P7+P6+P4+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P1+K|xxxxxxk;P9+P8+P7+P6+P5+P2+K|xxxxxxk;P9+P8+P7+P6+P5+P3+K|xxxxxxk;P9+P8+P7+P6+P5+P4+K|xxxxxxk swapped adjacent Slot elements "slot9" and "slot10" on AffixTemplate#0 ("deepOptionalTemplate") Evidenced +ordering:edge-cases/feature-gating-breadth/morphologicalRules/mrAgr~mrLoud Ordering edge-cases/feature-gating-breadth kalkano ok::KAL+AGR+LOUD|kalkano Word ok::- swapped adjacent morphologicalRules entries "mrAgr" and "mrLoud" on Stratum#0 ("Main") Evidenced +ordering:edge-cases/feature-gating-breadth/morphologicalRules/mrEmph~rrPast Ordering edge-cases/feature-gating-breadth kalmuid ok::KAL+EMPH+PAST|kalmuid Word ok::- swapped adjacent morphologicalRules entries "mrEmph" and "rrPast" on Stratum#0 ("Main") Evidenced +ordering:edge-cases/feature-gating-breadth/morphologicalRules/mrLoud~mrEmph Ordering edge-cases/feature-gating-breadth nalnomu ok::NAL+LOUD+EMPH|nalnomu Word ok::- swapped adjacent morphologicalRules entries "mrLoud" and "mrEmph" on Stratum#0 ("Main") Evidenced +ordering:edge-cases/feature-system-breadth/phonologicalRules/mtSwap~mtSwapOverlap Ordering edge-cases/feature-system-breadth ikt ok::TI+SUF|ikt;TIK|ikt Word ok::- swapped adjacent phonologicalRules entries "mtSwap" and "mtSwapOverlap" on Stratum#0 ("Main") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/coASlot~coBSlot Ordering edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- swapped adjacent Slot elements "coASlot" and "coBSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/coBSlot~coCSlot Ordering edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- swapped adjacent Slot elements "coBSlot" and "coCSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/coCSlot~coDSlot Ordering edge-cases/morphotactic-attribute-breadth topsakatana ok::TOP+COA+COB+COC+COD|topsakatana Word ok::- swapped adjacent Slot elements "coCSlot" and "coDSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/coDSlot~mbSlot Ordering edge-cases/morphotactic-attribute-breadth topsakanabu ok::TOP+COA+COB+COD+MB|topsakanabu Word ok::- swapped adjacent Slot elements "coDSlot" and "mbSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/maSlot~mreqSlot Ordering edge-cases/morphotactic-attribute-breadth kulbubidu ok::KUL+MB+MA+MREQ|kulbubidu Word ok::- swapped adjacent Slot elements "maSlot" and "mreqSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/mbSlot~maSlot Ordering edge-cases/morphotactic-attribute-breadth kulbubidu ok::KUL+MB+MA+MREQ|kulbubidu Word ok::- swapped adjacent Slot elements "mbSlot" and "maSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/partialSlot~realSlot Ordering edge-cases/morphotactic-attribute-breadth kulmoru ok::KUL+PART+REAL|kulmoru Word ok::- swapped adjacent Slot elements "partialSlot" and "realSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/morphotactic-attribute-breadth/slots/unblockableSlot~partialSlot Ordering edge-cases/morphotactic-attribute-breadth kulgimo ok::KUL+UNBLK+PART|kulgimo Word ok::- swapped adjacent Slot elements "unblockableSlot" and "partialSlot" on AffixTemplate#0 ("finalTemplate") Evidenced +ordering:edge-cases/mpr-gated-exception/phonologicalRules/prNasalAssimAlveolar~prObstruentDeletion Ordering edge-cases/mpr-gated-exception menulik ok::NPFX+TULIK|menulik Word ok::- swapped adjacent phonologicalRules entries "prNasalAssimAlveolar" and "prObstruentDeletion" on Stratum#0 ("Main") Evidenced +ordering:edge-cases/mpr-group-overwrite-without-realizational/morphologicalRules/mrThemeA~mrThemeB Ordering edge-cases/mpr-group-overwrite-without-realizational wudof ok::THEMEB+THEMEA+DOF|wudof Word ok::- swapped adjacent morphologicalRules entries "mrThemeA" and "mrThemeB" on Stratum#0 ("S") Evidenced +ordering:edge-cases/mpr-group-overwrite-without-realizational/morphologicalRules/mrThemeB~mrEndC Ordering edge-cases/mpr-group-overwrite-without-realizational wudofq ok::- Word ok::THEMEB+THEMEA+DOF+ENDC|wudofq swapped adjacent morphologicalRules entries "mrThemeB" and "mrEndC" on Stratum#0 ("S") Evidenced +ordering:languages/fusional-realizational-morphology/morphologicalRules/mrEndW~mrEndH Ordering languages/fusional-realizational-morphology gofwh ok::GOF+ENDW+ENDH|gofwh Word ok::- swapped adjacent morphologicalRules entries "mrEndW" and "mrEndH" on Stratum#1 ("MprGroups") Evidenced +ordering:languages/fusional-realizational-morphology/morphologicalRules/mrEndZ~mrEndW Ordering languages/fusional-realizational-morphology gofzw ok::GOF+ENDZ+ENDW|gofzw Word ok::- swapped adjacent morphologicalRules entries "mrEndZ" and "mrEndW" on Stratum#1 ("MprGroups") Evidenced +ordering:languages/fusional-realizational-morphology/morphologicalRules/mrThemeX~mrThemeY Ordering languages/fusional-realizational-morphology yxped ok::THEMEY+THEMEX+PED|yxped Word ok::- swapped adjacent morphologicalRules entries "mrThemeX" and "mrThemeY" on Stratum#1 ("MprGroups") Evidenced +ordering:languages/fusional-realizational-morphology/morphologicalRules/mrThemeY~mrEndZ Ordering languages/fusional-realizational-morphology ygofz ok::- Word ok::THEMEY+GOF+ENDZ|ygofz swapped adjacent morphologicalRules entries "mrThemeY" and "mrEndZ" on Stratum#1 ("MprGroups") Evidenced +ordering:languages/polysynthetic-stratal-derivation-chain/phonologicalRules/prMDC1~prMDC2 Ordering languages/polysynthetic-stratal-derivation-chain uui ok::MDC3|uui Word ok::- swapped adjacent phonologicalRules entries "prMDC1" and "prMDC2" on Stratum#0 ("Phonology") Evidenced +ordering:languages/prefixal-discontinuous-slot-dependency/slots/advA~advB Ordering languages/prefixal-discontinuous-slot-dependency hogabishiyidkal ok::ADVB+ADVA+OBJ+SBJ+PRF+CLF+KAL|hogabishiyidkal Word ok::- swapped adjacent Slot elements "advA" and "advB" on AffixTemplate#0 ("verbPrefixTemplate") Evidenced +ordering:languages/prefixal-discontinuous-slot-dependency/slots/classifier~mode Ordering languages/prefixal-discontinuous-slot-dependency shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal Word ok::- swapped adjacent Slot elements "classifier" and "mode" on AffixTemplate#0 ("verbPrefixTemplate") Evidenced +ordering:languages/prefixal-discontinuous-slot-dependency/slots/mode~subject Ordering languages/prefixal-discontinuous-slot-dependency shiyidkal ok::SBJ+PRF+CLF+KAL|shiyidkal Word ok::- swapped adjacent Slot elements "mode" and "subject" on AffixTemplate#0 ("verbPrefixTemplate") Evidenced +ordering:languages/prefixal-discontinuous-slot-dependency/slots/object~advA Ordering languages/prefixal-discontinuous-slot-dependency gabishiyidkal ok::ADVA+OBJ+SBJ+PRF+CLF+KAL|gabishiyidkal Word ok::- swapped adjacent Slot elements "object" and "advA" on AffixTemplate#0 ("verbPrefixTemplate") Evidenced +ordering:languages/prefixal-discontinuous-slot-dependency/slots/subject~object Ordering languages/prefixal-discontinuous-slot-dependency bishiyidkal ok::OBJ+SBJ+PRF+CLF+KAL|bishiyidkal Word ok::- swapped adjacent Slot elements "subject" and "object" on AffixTemplate#0 ("verbPrefixTemplate") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrCaus~mrAppl Ordering languages/suffixing-extension-slot-ordering andikilisha ok::AND+APPL+CAUS+FV|andikilisha Word ok::- swapped adjacent morphologicalRules entries "mrCaus" and "mrAppl" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrEndW~mrEndH Ordering languages/suffixing-extension-slot-ordering sekwh ok::SEK+ENDW+ENDH|sekwh Word ok::- swapped adjacent morphologicalRules entries "mrEndW" and "mrEndH" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrEndZ~mrEndW Ordering languages/suffixing-extension-slot-ordering sekzw ok::SEK+ENDZ+ENDW|sekzw Word ok::- swapped adjacent morphologicalRules entries "mrEndZ" and "mrEndW" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrExtX~mrExtY Ordering languages/suffixing-extension-slot-ordering yxkib ok::EXTY+EXTX+KIB|yxkib Word ok::- swapped adjacent morphologicalRules entries "mrExtX" and "mrExtY" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrExtY~mrEndZ Ordering languages/suffixing-extension-slot-ordering yxkibz ok::- Word ok::EXTY+EXTX+KIB+ENDZ|yxkibz swapped adjacent morphologicalRules entries "mrExtY" and "mrEndZ" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrNumPl~mrAgr Ordering languages/suffixing-extension-slot-ordering dabepez ok::DAB+NUMPL+AGR|dabepez Word ok::- swapped adjacent morphologicalRules entries "mrNumPl" and "mrAgr" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrRecurSuf~mrStemReq Ordering languages/suffixing-extension-slot-ordering dalizeh ok::DAL+RECURSUF+STEMREQ|dalizeh Word ok::- swapped adjacent morphologicalRules entries "mrRecurSuf" and "mrStemReq" on Stratum#0 ("Main") Evidenced +ordering:languages/suffixing-extension-slot-ordering/slots/applicative~finalVowel Ordering languages/suffixing-extension-slot-ordering andikila ok::AND+APPL+FV|andikila Word ok::- swapped adjacent Slot elements "applicative" and "finalVowel" on AffixTemplate#0 ("extensionTemplate") Evidenced +ordering:languages/suffixing-extension-slot-ordering/slots/causative~applicative Ordering languages/suffixing-extension-slot-ordering andikishila ok::AND+CAUS+APPL+FV|andikishila Word ok::- swapped adjacent Slot elements "causative" and "applicative" on AffixTemplate#0 ("extensionTemplate") Evidenced +ordering:languages/suffixing-vowel-harmony/phonologicalRules/prEpenthesis~prAlphaHighHarmony Ordering languages/suffixing-vowel-harmony kalut ok::KALT|kalut Word ok::- swapped adjacent phonologicalRules entries "prEpenthesis" and "prAlphaHighHarmony" on Stratum#0 ("Main") Evidenced diff --git a/conformance/semantic-coverage-presence-waivers.txt b/conformance/semantic-coverage-presence-waivers.txt new file mode 100644 index 000000000..992d77db1 --- /dev/null +++ b/conformance/semantic-coverage-presence-waivers.txt @@ -0,0 +1,53 @@ +# Presence-only waivers +# +# A surface counted as covered must have evidence behind it: a verified parse attributed to the rule +# that owns the construct (trace), a verified failing word observing a deactivated declaration +# (negative-control), or at minimum the load path of a fixture that parses (structural). +# +# "presence" means declared in a grammar and never exercised. It is NOT coverage. Each line below is +# a surface that is currently counted as covered on presence alone, with the reason it has not been +# fixed. The gate requires this file to equal the recomputed presence-only set exactly, so the list +# cannot grow silently and a fixed line must be deleted. +# +# Format: one surface ID per line. Blank lines and lines starting with "#" are ignored. + +# The inactive PhonologicalFeatureSystem in edge-cases/loader-isactive is observed by the grammar +# LOADING at all rather than by a failing word: were it loaded, "voi" would resolve against the wrong +# block and the whole grammar would fail. Distinguishing "a decoy that would change the result" from +# "a decoy nothing reads" requires per-construct counterfactuals, which do not exist in this repo yet +# (plan Task 5, CounterfactualGenerator). Until then this is honestly presence, not evidence. +dtd:enum/PhonologicalFeatureSystem/isActive/no + +# The six decoys in edge-cases/loader-isactive-breadth that no word targets. Each is declared so the +# enumerated value exists on that element; removing its isActive="no" would change no result in that +# fixture, which the grammar's own header states. They are waived rather than counted so the headline +# number matches the prose. Giving each a discriminating word is the fix; see grammar.xml's header for +# what such a word would have to observe. +dtd:enum/CharacterDefinitionTable/isActive/no +dtd:enum/Family/isActive/no +dtd:enum/FeatureNaturalClass/isActive/no +dtd:enum/MorphologicalPhonologicalRuleFeature/isActive/no + +# Three inactive declarations in edge-cases/morphotactic-attribute-breadth that no word can observe. +# Each would need a word combining two roots, and that fixture has no compounding rule: unconstrained +# head/non-head patterns made the analyser non-terminating there (the C# oracle did not finish in ten +# minutes on three words), so compounding is deliberately elsewhere. Giving these discriminating words +# means adding a bounded compounding rule to that grammar. +dtd:enum/AllomorphCoOccurrenceRule/isActive/no +dtd:enum/MorphemeCoOccurrenceRule/isActive/no +dtd:enum/MorphologicalPhonologicalRuleFeatureGroup/isActive/no + +# Three inactive declarations in edge-cases/feature-system-breadth that are deliberately referenced by +# nothing, because a reference would dangle when the declaration is correctly dropped, and that same +# absence leaves no word able to observe them. +dtd:enum/ComplexFeature/isActive/no +dtd:enum/SegmentNaturalClass/isActive/no +dtd:enum/SymbolicFeature/isActive/no + + + +# edge-cases/feature-system-breadth discriminates this with a feature-value bracket that consults the +# decoy, and the counterfactual sweep evidences it. The trace grader only credits a deactivated +# declaration that a word names in neutralizes:, and the discriminating word here is a positive +# parse rather than a failure, so it cannot carry that key. +dtd:enum/FeatureValue/isActive/no \ No newline at end of file diff --git a/conformance/semantic-coverage-proofs.tsv b/conformance/semantic-coverage-proofs.tsv new file mode 100644 index 000000000..42a40ed87 --- /dev/null +++ b/conformance/semantic-coverage-proofs.tsv @@ -0,0 +1,42 @@ +# Impossibility proofs +# +# The two-verdict standard: every grammar-observable surface must end as either `evidenced` (a +# counterfactual delta in semantic-coverage-counterfactuals.tsv) or an explicit claim that evidence is +# IMPOSSIBLE, recorded here with a proof kind the gate recomputes. +# +# A surface whose counterfactual verdict is Unobservable or Timeout fails the gate unless it appears +# below. Prose is not a proof: each kind names a mechanical check. +# +# dtd-default The value equals its attribute's DTD default, so the validating parser supplies it +# for every document and writing it is indistinguishable from omitting it. +# Recomputed from the inventory's own attribute-default surface. +# no-consumer The engine contains no reference to the owning element, so no grammar can make it +# influence a parse. Recomputed by scanning the engine source. This file only ever +# names a surface a fixture actually declares; the identical "no engine reference" +# fact for a surface no fixture ever attempts is the `dead-schema` classification in +# semantic-coverage-baseline.txt instead (it has no counterfactual verdict to be +# IMPOSSIBLE about, so it can never enter this ledger without an orphaned-proof +# failure in CoverageGapRatchetTests). conformance/README.md's exception list draws +# on both, and ExceptionListTests.cs pins it against both. +# not-in-signature The surface's data is carried by the model (loaded, copied, round-tripped) but +# never reaches a control-flow decision or the parse-comparison signature, so no word +# could ever discriminate it. Recomputed two ways: SignatureFormat.BuildSignature's +# own source is scanned for a reference to the property, and every fixture whose +# grammar contains the owning element is mutated and re-parsed, requiring the +# mutation to be genuinely applied and every word's outcome unchanged. Neither check +# alone is a full proof of unreachability -- see NotInSignatureCheck's own doc +# comment for exactly what remains a human-reviewed reading of the engine source. +# blocked-by-defect An engine defect prevents any word from exercising it. Must name a reproducing +# expect_crash fixture AND the upstream issue. Valid only while that issue is open. +# +# `label-symmetry` was removed. Its only use claimed 24 Greek VariableFeature names were +# interchangeable labels; that was FALSE, because alpha variables unify across every VariableFeature a +# rule declares rather than being scoped per declaration, so renaming one to collide with another +# reverses which words parse (see edge-cases/alpha-variable-name-collision). The check was weak because +# it never required the two values to CO-OCCUR in a grammar before believing they were interchangeable. +# +# Format: . Blank lines and lines starting with "#" are ignored. +surface kind evidence +dtd:enum/Stratum/cyclicity/cyclic no-consumer No Cyclicity property exists on Stratum.cs and the identifier appears nowhere in the engine; SynthesisStratumRule and AnalysisStratumRule build the pipeline as an unconditional LinearRuleCascade with no branch point that could consult a stratum ordering mode +dtd:enum/Stratum/phonologicalRuleOrder/simultaneous no-consumer Same as cyclicity: the identifier appears nowhere in the engine, and setting both attributes on edge-cases/simultaneous-epenthesis-cascade (engineered to be maximally ordering-sensitive) produced a byte-identical InfiniteLoopException with an identical stack trace +dtd:element/Properties not-in-signature Loaded via LoadProperties at XmlLanguageLoader.cs:469,517,912,981,1048 and copied through by value via AddRange at Morpher.cs:403,423 (lexicon-guessed roots); SignatureFormat.BuildSignature, the sole builder of the string two parses are diffed by, reads only Morpheme.Id and Shape and contains no reference to Properties (NotInSignatureCheck.SignatureSourceNeverReads). Neutralizing the element is genuinely applied and changes no word's outcome in either fixture that declares one: edge-cases/feature-gating-breadth (11 words) and edge-cases/loader-isactive-breadth, per NotInSignatureCheck.MutationChangesNoWordInAnyContainingFixture. Not mechanically checked: that no OTHER engine code path branches on a Properties VALUE; XmlLanguageWriter's isActive round-trip and the loader/Morpher call sites above were read by hand and are copy-throughs, not decisions. diff --git a/conformance/skills/README.md b/conformance/skills/README.md new file mode 100644 index 000000000..aa3bdf86f --- /dev/null +++ b/conformance/skills/README.md @@ -0,0 +1,138 @@ +# The authoring harness + +Four skills, one measurement, one feedback loop. The point is not that an agent *can* author coverage +— it is that we can say **how often it gets it right unaided**, and improve that number deliberately +rather than by intuition. + +Skills live here rather than only in `.claude/skills/` because they ship with the fixtures. A +consumer or a future maintainer receiving `conformance/` gets the instructions that produced it. + +## The four skills + +| skill | role | phase | +|---|---|---| +| `author-coverage-cell` | given an unsatisfied obligation cell, author the words and the claim that satisfy it | do | +| `review-coverage-claim` | judge role attribution on an authored claim | check | +| `measure-authoring-quality` | run a batch, score first-pass yield, attribute failures | measure | +| `revise-coverage-harness` | diagnose which instruction failed and revise the skills | improve | + +They form a loop: author → review → measure → revise → author. That shape is borrowed rather than +invented; it is the compile/evaluate/improve cycle DSPy uses for prompts, and the +capability-eval-to-regression-eval progression the agent-skill literature describes. + +## The quality signal: first-pass yield + +**FPY = the fraction of attempted cells that pass the production gate on first submission, with zero +reviewer feedback.** + +That is the number this harness exists to move. Not "can an agent do it with enough hand-holding" — +with enough hand-holding the answer is always yes and the measurement is worthless. FPY asks whether +the *instructions* are sufficient. + +The gate is the arbiter, not a reviewer and not the authoring agent's own judgment. A cell counts as +first-pass only when `DataflowClaimGate` accepts it against a fresh recomputation. + +### Failure attribution is the actionable part + +A bare pass rate tells you the harness is weak; it does not tell you which sentence to fix. Every +failure is classified: + +| class | what it means | which instruction is at fault | +|---|---|---| +| `wrong-grammar` | chose a fixture that cannot host the construct | grammar-selection guidance | +| `not-minimal-pair` | the two cases differ in more than one condition | the MC/DC explanation | +| `no-witness` | the authored word does not flip under severance | the witness requirement | +| `unrealistic-word` | form or gloss does not fit the grammar's shape | the realism constraint | +| `bad-cell-id` | claimed a cell that does not exist | the cell-id vocabulary | +| `evidence-mismatch` | inline before/after disagree with recomputation | the evidence-recording step | + +A class with a high rate is a documentation defect, not an agent defect. That is the whole premise +of the revise step. + +### Reference set and golden set, held apart + +Tuning the harness on the cells you measure it with makes FPY meaningless — the number goes up +because the instructions memorised those cells. + +- **Reference cells** — used while iterating. Look at them freely. +- **Golden cells** — held out. Only ever run to report FPY, never inspected while revising. + +A revision that raises reference FPY but not golden FPY has overfitted, and that gap is the signal +that it has. + +## Output format + +Every run appends to a machine-readable record so the revise step consumes data, not recollection: + +``` +attempt_id cell_id skill_version set(reference|golden) phase_reached outcome(pass|fail) failure_class notes +``` + +`skill_version` matters: FPY is only comparable across runs if you know which instructions produced +it. Bump it on every revision. + +## The loop, and when to stop + +1. Run `measure-authoring-quality` over the reference set. Record FPY and the failure histogram. +2. Run `revise-coverage-harness` on the dominant failure class. One class at a time — revising three + at once means you cannot attribute the change. +3. Re-measure on reference. If it moved, measure golden. +4. Stop when golden FPY is high enough that reviewing is cheaper than re-authoring. + +There is no target number here yet, because none has been measured. Setting one before the first +measurement would be inventing a threshold and then discovering it. + +## Running things that take longer than a tool call + +The single most common way work is lost here is not a wrong answer -- it is an author that starts a +long command, is told the command has been moved to the background, and ends its turn to wait for a +notification that its caller never routes back to it. Five authoring runs were lost this way before +anyone wrote it down. + +**This is not disobedience and it is not fixed by telling an author "do not background things."** The +tool has a hard foreground ceiling of about ten minutes and enforces it itself. The full test suite +here takes twelve to sixteen minutes and a release build can take longer, so any author that runs one +*will* be backgrounded whether or not it intended to be. The instruction to avoid must therefore be +aimed at the cause, not the symptom: + +**Never run the full suite to verify authoring work.** Run the tests that could possibly have changed: + +```powershell +dotnet test -c Debug --no-build --filter "FullyQualifiedName~" +``` + +Measured: the engine-gate ledger tests take **25 milliseconds** under a filter and about twelve +minutes as part of the whole suite. The same asymmetry holds for regeneration -- the scoped +single-fixture sweep in `author-coverage-cell` Phase 5 takes four seconds where the full sweep takes +seven minutes and produces identical rows for that fixture. + +So: an author verifies with filtered tests and scoped regenerations, both comfortably inside the +ceiling. **Running the full suite is the caller's job**, because only a persistent caller can receive +a completion notification across turns; an author structurally cannot. If an author believes it needs +the full suite, the honest move is to say so and stop, not to launch it and hope. + +If something genuinely must run longer than the ceiling, do not end the turn on it. Launch it so that +it writes a completion sentinel, then poll the sentinel with short foreground commands that each +finish well inside the limit. Waiting is then something the author does, rather than something it +delegates to a notification that may never arrive. + +## What this harness must never do + +**The gate stays the authority.** No skill here may mark a cell covered, weaken a gate, or edit an +expectation to make a claim true. An authoring agent that cannot satisfy a cell reports that it could +not — a failed attempt is data, and a fabricated success poisons both the corpus and the measurement. + +**Do not tune the measurement.** If FPY is low, that is the finding. Lowering the bar — accepting +`Unknown` cells as passes, or letting the reviewer pre-correct before the gate runs — produces a +better number and a worse suite. + +## Prior art + +- **DSPy** — declarative signature, explicit metric, optimizer that compiles instructions against it. + The discipline worth copying: engineer the metric first, because it is what everything else + optimises toward. +- **Agent-skill evaluation practice** — goldens as input/expected-output pairs; capability evals that + start with a low pass rate and graduate into regression evals once they approach 100%. +- **SkillAxe** (arXiv 2606.10546) — decomposes skill quality into quality impact, trigger precision, + instruction compliance with fault attribution, and solution-path coverage. Our failure-class table + is the fault-attribution idea applied to this domain. diff --git a/conformance/skills/author-coverage-cell/SKILL.md b/conformance/skills/author-coverage-cell/SKILL.md new file mode 100644 index 000000000..47c0d4a36 --- /dev/null +++ b/conformance/skills/author-coverage-cell/SKILL.md @@ -0,0 +1,257 @@ +--- +name: author-coverage-cell +description: >- + Use when asked to cover, satisfy, witness, or close an obligation cell in the HermitCrab + conformance suite — anything of the form "cover cell X", "satisfy this dataflow obligation", + "add words so this chain is witnessed", "close a coverage gap", or when handed a cell id from + conformance/dataflow-obligations.tsv. Authors the minimal-pair words in an existing language + grammar and the claimed_cells entry that records the evidence, then verifies by severance rather + than by inspection. Does NOT author new grammars, new fixtures, or grammar.xml content — if the + construct is absent from every language grammar, this skill reports that and stops. +--- + +# Authoring a coverage cell + +You are given an **obligation cell id** from `conformance/dataflow-obligations.tsv`. Your job is to +make it `Satisfied`: author words in an existing language-family grammar such that severing the +construct changes a parse, then record the claim. + +**Before anything else, run the feasibility check.** Most of an authoring budget has more than once +been spent proving an obligation impossible: + +```powershell +conformance\tools\check-obligation-feasibility.ps1 -Writer -Reader [-ControlElement ] +``` + +It answers mechanically whether the attribute can be severed at all, whether one fixture declares both +ends of the chain, and whether a Control arm can be attributed. If it exits non-zero, this is not an +authoring task -- record the blocker and stop. + +Then read `conformance/docs/severance-mechanics.md`. It states what severance can and cannot do, which +attributes are unsevereable, and three engine behaviours that each cost an author most of a budget to +rediscover. Do not reason about severance without it. + +Read `conformance/docs/what-it-claims.md` first if you have not. The distinction it draws between +*present* and *witnessed* is the one this task turns on. + +## Phase 1 — Understand the cell + +Read its card in `conformance/evidence-cards/` (find it via `index.tsv`). The card states the role in +plain English, the chain, and the current machine status. + +A cell id is `payload :: writer.attr -> reader.attr :: kind:role`. The four MC/DC roles: + +| role | means | +|---|---| +| `PresentControl` | payload present, the gated rule not applied — the baseline | +| `PresentGatedForm` | payload present, gated rule attempted — the interesting case | +| `AbsentControl` | payload absent, gated rule not applied | +| `AbsentGatedForm` | payload absent, gated rule attempted — proves the rule *can* fire | + +Stop and state, in one sentence, what would have to be true of a word for it to occupy this cell. If +you cannot, do not proceed — you will author something plausible and wrong. + +## Phase 2 — Find a host grammar + +Search `conformance/languages/*/grammar.xml` for one that already declares **both** the writer +construct and the reader construct. `conformance/fold-in-candidates.tsv` marks obligations whose +construct is already structurally present. + +- **Default: never edit `grammar.xml`.** If no language grammar hosts both, report `wrong-grammar` + and stop. That is a real finding about the corpus, not a failure of yours. +- Prefer a grammar where the construct is already used for something, so the new words sit naturally + among existing ones. + +### The one exception: a small, engine-justified grammar edit + +Some assignments (bucket-2 coverage obligations) explicitly license editing a grammar when the +construct is absent from every fixture but HCLoader can genuinely produce it and real morphology +exhibits it. That relaxation is narrow and directional — it does not turn Phase 2 into "invent +whatever makes the cell green." + +**The rule.** An edit is legitimate only when all three hold: + +1. **HCLoader demonstrably emits the construct**, cited by file and line (e.g. `HCLoader.cs:2057` + for `PhonologicalSubrule.RequiredMprFeatures`). +2. **Real morphology exhibits it** — the shape you are adding is a genuine, nameable linguistic + phenomenon (a minor rule, a lexically-conditioned exception, a category-changing derivation), + not a string manufactured to trip a check. +3. **The reasoning runs from engine behaviour TO a grammar shape — never from a red cell to + whatever turns it green.** Write down the HCLoader citation and the engine mechanism *before* + deciding what to add. If you cannot state both before touching `grammar.xml`, do not make the + edit. + +The edit must still leave the grammar a coherent description of a plausible language: synthetic +data only, never named after a real language, typological family in a comment only if at all. + +**The tell.** The direction of reasoning is everything. "This cell is red; if I add X the severance +will flip" is illegitimate even if X is grammatically well-formed and even if it works — the +grammar became a proof artifact for the cell instead of an independent thing the cell happens to +measure. "HCLoader.cs:1873 sets a compound's output category from a field a FLEx user fills in; a compound +taking a category that a later affix then checks is ordinary morphology; let me +add that pair and see what it demonstrates" is legitimate, because the construct and its +justification exist before any cell's colour is consulted. + +**Worked legitimate example.** Bucket-2 item C (`CompoundingRule.outputPartOfSpeech -> +MorphologicalRule.requiredPartsOfSpeech`): `HCLoader.cs:1873-1876` and `:1932-1935` set the compound's +output category from `compoundRule.OverridingMsaOA/ToMsaOA.PartOfSpeechRA` -- a field a FLEx user fills +in directly on a compound rule. A compound taking a category and a later affix checking it is ordinary +morphology (*blackbird* is a noun, so noun plural applies). The author read +`SynthesisCompoundingRule.cs` FIRST, found that the compound's feature struct is seeded from the head's +required POS before `outputPartOfSpeech` overwrites it, and therefore set the reader's required POS to +that fallback value rather than an arbitrary third category. An earlier attempt using an unrelated +category produced an Unobservable severance and is recorded in the commit as what did not work. That is +the shape to imitate: engine read first, a failed attempt kept, the grammar shaped by the mechanism. + +**Worked example of a citation that LOOKS legitimate and is not.** The first version of this section +used item D (`MorphologicalOutput.MPRFeatures -> MorphologicalInput.excludedMPRFeatures`) and cited +`HCLoader.cs:969` as the write and `HCLoader.cs:1717` as the read. An adversarial review found that +`:1717` sits inside `foreach (ILexEntryInflType t in types)` under the comment "block slot from applying +to irregularly inflected forms": it populates `ExcludedMprFeatures` ONLY from +`slot.ReferringObjects.OfType()`, never from an ordinary affix's output. `:969`'s +values come from `msa.ToInflectionClassRA`/`ToProdRestrictRC`. The two lines are separate mechanisms that +share a field NAME, so the authored shape -- an ordinary rule conferring a flag an ordinary sibling +excludes -- is not producible by FieldWorks at all. + +Both citations were real file:line references to real assignments, and the edit passed every automated +gate including the 33/33 self-check. **A file:line citation is not evidence on its own.** State the +FLEx source field that flows into the line you cite, and check that your writer's field and your +reader's field are the same channel. Two producible attributes do not make a producible chain. + +**Worked illegitimate example (do not do this).** Suppose `LexicalEntry.ruleFeatures -> +PhonologicalSubrule.requiredMPRFeatures` is red, and the temptation is: "add a root with +`ruleFeatures="mprX"` and a `PhonologicalSubrule` with `requiredMPRFeatures="mprX"`, run the +severance sweep, and see if it flips." That is illegitimate even before checking whether it works, +because the starting point was the red cell, not an engine citation — and in this specific case it +provably cannot work regardless: `SynthesisRewriteSubruleSpec.IsApplicable` +(`PhonologicalRules/SynthesisRewriteSubruleSpec.cs:47-49`) checks +`_subrule.RequiredMprFeatures.IsMatchRequired(input.MprFeatures, ...)` — a plain set-membership +test with no accumulation or overwrite semantics for a root-sourced feature. Severing +`LexicalEntry.ruleFeatures` can only ever *remove* a feature that was satisfying the requirement +(turning a pass into a fail — the wrong direction) or remove one that was already going to be +destroyed by some other write (a no-op). There is no grammar shape that flips this specific pairing +from fail to pass, so authoring words for it is `false-impossibility`'s mirror image: instead of +wrongly declaring victory impossible, it would be wrongly declaring victory achieved by adding +words to a chain the engine's own comparison logic forecloses. The fix when you hit this is to +write down the proof (as this paragraph does) and report `no-witness`, not to keep trying words. + +## Phase 3 — Design the minimal pair + +The cell needs a **control** — that is the entire point. From `conformance/docs/`: + +> Test every mechanism that can change a parse. A fixture must contain enough cases that exactly one +> explanation of the observed difference survives. + +For a gated chain that means two entries and four words: an entry carrying the payload and one not, +each with a bare-root control and a form where the gated rule applies. The ungated arm is what +distinguishes "the gate blocked it" from "the rule never fires at all". A fixture with only the gated +stem exercises the attribute and witnesses nothing. + +The pair must differ in **exactly one** condition. Two words that both parse as expected but differ +in two conditions establish nothing — and read perfectly well, which is why this is the easiest +mistake to make. + +### Severance is fixture-wide, and that is usually what you are missing + +`Sever()` removes an attribute from **every** element in the fixture at once -- not from one entry. +So removing a payload does not merely turn one match into a mismatch. It can make a gate vacuous, or +delete a competing analysis, and thereby take a word from failing to parsing. A writer severance +CAN flip a word from fail to pass on a `required*` reader; the ledger already contains cells proving +it. + +This matters because the paired witness you need is exactly a same-word fail-to-pass flip on both +sides, and reasoning about severance as if it were per-word makes that look impossible when it is +not. + +### Before you conclude a cell cannot be witnessed, falsify that + +A structural argument that a cell is unreachable is a claim like any other, and it is the easiest +claim to believe because it ends the task. So it carries the heaviest burden of proof here: + +**Test your impossibility argument against a cell that is already `Satisfied`.** Read the satisfied +rows out of `conformance/dataflow-obligations.tsv`, take your argument, and ask whether it would also +forbid those. If it would, your argument is wrong -- discard it and author the words. This check has +already caught a confident, well-written, entirely wrong proof that five separate cells were +unreachable. + +`wrong-grammar` is for a construct **absent from every language grammar** -- a fact you establish by +searching the grammars, not by deriving it. An argument that the words cannot be *made to flip* is +not that, and reporting it as a corpus finding when you never authored a word is the +`false-impossibility` failure class. You are expected to try, and a witnessed flip beats a proof. + +## Phase 4 — Author the words + +Follow the host fixture's existing conventions exactly: form shape, gloss style, `note:` density, +`exercises:` vocabulary. + +- **Realistic forms.** These are coherent language-family grammars. A word must be one the grammar + would plausibly generate, not a minimal string that trips the construct. +- **Synthetic only.** Never actual-language data; never name anything after a real language. + Typological family belongs in a comment. Cite WALS-style sources in `inspired_by` as the existing + fixtures do. +- Write the `note:` for every new word. The notes carry the derivation reasoning and are the most + valuable part of these files. + +## Phase 5 — Verify by severance, not by reading + +**This is the phase that decides whether you succeeded, and it is the one most often skipped.** + +Regenerate the witness ledger and confirm the cell's status actually changed. Adding a word that +*mentions* the construct proves nothing; the sweep is the result and your reasoning is not. + +If the cell did not become `Satisfied`, you have not covered it. Report `no-witness` with what you +tried. Do not adjust an expectation, weaken a gate, or claim partial success. + +### Regenerating fast enough to iterate + +The full sweep re-parses every interface in every fixture and takes about seven minutes. You do not +need it while iterating. Point the tool at a throwaway root holding only your fixture: + +```powershell +$root = "$env:TEMP\cellwork" +New-Item -ItemType Directory "$root\conformance\languages" -Force | Out-Null +Copy-Item conformance\languages\ "$root\conformance\languages\" -Recurse +Copy-Item conformance\HermitCrabInput.dtd,conformance\constructs.txt "$root\conformance\" +dotnet --fixtures "$root\conformance" --repository-root $root ` + --write-coverage-traceability +``` + +That runs in seconds and its rows for your fixture are byte-identical to the ones the full sweep +produces -- severance is evaluated per fixture, so nothing outside yours can change them. + +What it does **not** do is decide the obligation's status. `Satisfied` is a judgement across every +fixture, and a scoped root cannot see the others. So use the scoped run to answer "do my words flip +under severance", which is the question you are actually iterating on, and run the full sweep and the +gate once at the end to answer "is the cell now covered". + +## Phase 6 — Record the claim + +Add a `claimed_cells` entry on the word that carries the witness: + +```yaml +claimed_cells: + - cell: + severing: + before: "" + after: "" + distinct_from: + proof: +``` + +`before`/`after` must be the **recomputed** values, copied from the ledger — never predicted. The +gate re-severs and compares; a value you guessed will be caught and reported stale. + +Then run the gate and confirm it accepts. + +## Reporting + +State, in this order: the cell id, the host grammar and why, the words added, the severance result +that proves the witness, and the gate outcome. + +If you failed, say which phase and which failure class (`wrong-grammar`, `false-impossibility`, `not-minimal-pair`, +`no-witness`, `unrealistic-word`, `bad-cell-id`, `evidence-mismatch`). A classified failure is useful +data for improving these instructions; an unclassified one is not. + +**Never report a cell as covered because you added a word for it.** That conflation has been made +five times on this programme at five different levels, and this phase is where it would happen a +sixth. diff --git a/conformance/skills/measure-authoring-quality/SKILL.md b/conformance/skills/measure-authoring-quality/SKILL.md new file mode 100644 index 000000000..3971f100b --- /dev/null +++ b/conformance/skills/measure-authoring-quality/SKILL.md @@ -0,0 +1,86 @@ +--- +name: measure-authoring-quality +description: >- + Use when asked to measure, score, or benchmark the conformance authoring harness — "how good is + the author skill", "what's our first-pass yield", "run the harness eval", "measure before and + after a skill revision". Runs a batch of obligation cells through author-coverage-cell without + intervention, scores first-pass yield against the production gate, and attributes every failure to + a class. Produces a run record; changes no skill and fixes no fixture. +--- + +# Measuring authoring quality + +You are measuring the **instructions**, not the agent and not the corpus. The output is a number and +a histogram that tell someone which sentence to rewrite. + +## The metric + +**First-pass yield: the fraction of attempted cells that pass the production gate on first +submission, with zero reviewer feedback.** + +The gate is the arbiter. Not your judgment, not a reviewer's, not the authoring agent's self-report. +A cell counts only when `DataflowClaimGate` accepts it against a fresh recomputation. + +## Procedure + +1. **Pick the set.** Reference cells while iterating; golden cells only when reporting a headline + number. Never inspect golden cells while revising — that is what makes them golden. +2. **Run each cell through `author-coverage-cell` cold.** No hints, no clarifications, no + mid-attempt corrections. The moment you help, you are measuring yourself. +3. **Score against the gate.** Pass or fail, nothing in between. A cell that reaches `Unknown` is a + fail. +4. **Classify every failure** into exactly one class: + +| class | signature | +|---|---| +| `wrong-grammar` | chose a fixture that cannot host the construct | +| `not-minimal-pair` | the cases differ in more than one condition | +| `no-witness` | the authored word does not flip under severance | +| `false-impossibility` | concluded the cell unreachable without authoring anything | +| `unrealistic-word` | form or gloss does not fit the grammar's shape | +| `bad-cell-id` | claimed a cell that does not exist | +| `evidence-mismatch` | inline `before`/`after` disagree with recomputation | + +If a failure fits none, add a class rather than forcing it — a new class is a finding. + +5. **Append to the run record**, one row per attempt: + +``` +attempt_id cell_id skill_version set phase_reached outcome failure_class notes +``` + +`skill_version` is mandatory, and it is computed rather than typed: + +```powershell +git rev-parse HEAD:conformance/skills +``` + +That is the git tree hash of the skills directory. It changes when and only when a skill changes, so +two runs carrying the same `skill_version` genuinely ran the same instructions, and two that differ +genuinely did not. A hand-written version number answers neither question, because nothing obliges +anyone to bump it, and a stale one silently makes two different runs look comparable. + +Write the run record to `conformance/harness-runs/first-pass-yield.tsv`, appending -- never rewriting. The +history is the point: one yield number means little, and the series across skill versions is what +tells you whether a revision helped. + +## Reporting + +Report FPY as a fraction with its denominator (`4/12`, never "33%"), the failure histogram, and the +dominant class. Name the single class you would fix first and why. + +Also report **run-to-run stability**: if the same cell passes on one run and fails on the next with +identical instructions, the measurement is unreliable and that outranks the yield number. Say so +prominently — a metric that moves without a cause is worse than no metric. + +## Never + +- **Never help mid-attempt.** A rescued attempt is not a first-pass, and recording it as one + destroys the only thing this measures. +- **Never tune the measurement.** If yield is low, that is the finding. Accepting `Unknown` as a + pass, or letting a reviewer correct before the gate runs, produces a better number and a worse + suite. +- **Never revise a skill here.** Measuring and revising in one pass means you cannot attribute the + change. Hand the record to `revise-coverage-harness`. +- **Never fix the fixture.** A failed attempt is data. Repairing it by hand loses the data and + inflates the next run. diff --git a/conformance/skills/review-coverage-claim/SKILL.md b/conformance/skills/review-coverage-claim/SKILL.md new file mode 100644 index 000000000..86f1ef04f --- /dev/null +++ b/conformance/skills/review-coverage-claim/SKILL.md @@ -0,0 +1,63 @@ +--- +name: review-coverage-claim +description: >- + Use when asked to review, verify, certify, or check a coverage claim in the HermitCrab conformance + suite — "review this claimed_cells entry", "does this word really demonstrate that cell", "check + the role attribution", or when handed an evidence card from conformance/evidence-cards/. Judges + ONLY role attribution: whether the word occupies the cell it claims. Never sets a status, never + edits a claim, never edits a grammar or an expectation. Declining is a valid outcome. +--- + +# Reviewing a coverage claim + +The machinery has already established a **flip**: severing an attribute changed a word's outcome. +That is recomputed every run and you cannot affect it. + +You are judging **role attribution** — whether this word occupies the cell it claims. That needs +three facts the flip does not carry: the stem really carries the payload, the named rule really is +the gated one, and the observed polarity is the one that reader implies. + +**Your verdict never sets a status.** It is recorded as an opinion beside machine-established facts. +If you approve and recomputation disagrees, recomputation wins and your approval is discarded. +Nothing you write can make a cell count as covered. + +## The four checks + +**1. Predict before you read.** From the grammar and the word, state what the outcome will be with +the payload intact and with it severed — *before* reading the card's `before`/`after`. Then compare. + +Confirming a visible answer is nearly free, and you will do it convincingly whether or not you +understand the gate. Predicting requires deriving the behaviour. **If your prediction was wrong, say +so and do not approve** — a wrong prediction means you did not understand the claim well enough to +certify it. + +**2. Verify the citations; do not merely read them.** The card carries the `grammar.xml` lines where +the payload is declared and where the reader gates on it, extracted mechanically. Open the grammar +and confirm each cited line really declares what the chain names. The numbers are handed to you, so +the test is semantic: does that line carry that payload, on that element. + +**3. Check the counterpart.** `distinct_from` asserts a minimal pair differing in **exactly one** +condition. Verify it. Two words that both parse as expected but differ in *two* conditions establish +nothing — and read perfectly well, which makes this the easiest defect to wave through and the one +worth spending your attention on. + +**4. Read the prose against the values.** `proof:` must describe the same event the `before`/`after` +record. Prose that is true but about something else is a failure, not a nitpick. + +## How to decline + +Say which check failed and why. **A claim you cannot verify is not approved, and that is a normal +outcome.** "I could not determine whether the counterpart differs in one condition or two" is a +useful review; a confident yes covering that uncertainty is worse than no review at all. + +Some batches contain deliberately wrong claims. Approving one voids your other verdicts in the same +batch, so guessing costs more than declining. + +## Never + +- **Never edit** a claim, word, expectation, or grammar to make a claim true. Report the discrepancy. + An adjusted expectation destroys the finding. +- **Never review the authored file against itself.** The grammar and the recomputed severance are + ground truth; `words.yaml` is the claim under test, never evidence for itself. +- **Never infer a status.** `Satisfied`/`NotSatisfied`/`Unknown` are machine-established and appear + on the card already labelled as such. diff --git a/conformance/skills/revise-coverage-harness/SKILL.md b/conformance/skills/revise-coverage-harness/SKILL.md new file mode 100644 index 000000000..2ae7aa63e --- /dev/null +++ b/conformance/skills/revise-coverage-harness/SKILL.md @@ -0,0 +1,75 @@ +--- +name: revise-coverage-harness +description: >- + Use when asked to improve, revise, or fix the conformance authoring harness after a measurement — + "first-pass yield is low, fix the skill", "most failures are not-minimal-pair, revise the + instructions", "improve the harness based on the run record". Consumes a measurement run record, + diagnoses which instruction produced the dominant failure class, and revises exactly one thing. + Never revises without a measurement, and never touches the golden set. +--- + +# Revising the harness + +You are fixing **instructions**, on evidence. The premise: a failure class with a high rate is a +documentation defect, not an agent defect. Somewhere a sentence is missing, ambiguous, or buried. + +## Preconditions + +- A run record from `measure-authoring-quality` exists, with a failure histogram and a + `skill_version`. +- You have **not** looked at golden cells. If you have, the next golden measurement is compromised + and you must say so. + +**Never revise without a measurement.** A revision based on a hunch cannot be shown to have helped, +and it makes the next number uninterpretable — you will not know whether it moved because of your +change or the one you made on a hunch. + +## Procedure + +**1. Take the dominant class only.** One class per revision. Fixing three at once means you cannot +attribute the change, and the histogram stops being able to guide you. + +**2. Find the instruction at fault.** For each class there is a sentence that should have prevented +it: + +| class | where to look | +|---|---| +| `wrong-grammar` | the host-selection phase — is the "both constructs present" test stated as a test, or as advice? | +| `not-minimal-pair` | the MC/DC explanation — is "exactly one condition" prominent, or buried in prose? | +| `no-witness` | the verification phase — is severance framed as *the* result, or as a final check? | +| `false-impossibility` | the host-selection and design phases — is stopping offered as a respectable outcome with no test attached? | +| `unrealistic-word` | the realism constraint — is "plausible for this grammar" defined, or assumed? | +| `bad-cell-id` | the cell-id vocabulary — is the id's structure explained, or only exemplified? | +| `evidence-mismatch` | the evidence-recording step — does it say values are copied from the ledger, never predicted? | + +**3. Diagnose before editing.** State which sentence failed and *why an agent following it in good +faith would still have got it wrong*. If you cannot articulate that, you have not found the defect +and adding emphasis will not help. + +Three common shapes: +- **Buried** — correct but positioned where it is read after the decision it governs. +- **Advisory** — phrased as a preference where it needed to be a test with a failure mode. +- **Assumed** — a term used without definition ("realistic", "minimal") that the author must guess. + +**4. Revise minimally.** Change the one instruction. Resist rewriting the surrounding sections while +you are there — a large revision cannot be attributed either. + +**5. Bump `skill_version` and hand back for re-measurement.** You do not measure your own revision; +that is `measure-authoring-quality`'s job and keeping them apart is what makes the number credible. + +## Reading the result + +- **Reference yield up, golden yield up** — a genuine improvement. +- **Reference up, golden flat** — you have overfitted to the reference cells. Revert or generalise; + the gap is the evidence, not a coincidence. +- **Neither moved** — the diagnosis was wrong. Say so and pick the next class rather than adding + emphasis to the same sentence, which is the most common failure of this loop. + +## Never + +- **Never make the task easier to make the number better.** Weakening what the skill demands raises + yield and lowers coverage quality. The measurement exists to improve instructions, not to be + satisfied. +- **Never touch the gate.** If a class of failure looks like a gate defect rather than an instruction + defect, report it — that is a valuable finding and it is out of scope here. +- **Never revise the measurement skill** to reclassify failures more favourably. diff --git a/conformance/tools/check-obligation-feasibility.ps1 b/conformance/tools/check-obligation-feasibility.ps1 new file mode 100644 index 000000000..e6157c9a0 --- /dev/null +++ b/conformance/tools/check-obligation-feasibility.ps1 @@ -0,0 +1,99 @@ +#!/usr/bin/env pwsh +# Answers, before anyone spends an authoring budget, whether a coverage obligation is an authoring +# task at all. Every check here corresponds to a way an obligation has already consumed most of an +# agent's budget before proving itself impossible. See conformance/docs/severance-mechanics.md. +# +# Exits 0 if the obligation looks authorable, 1 if a check rules it out. A rule-out is a finding: it +# belongs in obligation-triage.tsv, not in a work queue. + +[CmdletBinding(PositionalBinding = $false)] +param( + # An attribute as Element.attribute, e.g. LexicalEntry.partOfSpeech. Repeat for writer and reader. + [Parameter(Mandatory = $true)][string] $Writer, + [Parameter(Mandatory = $true)][string] $Reader, + # Element name whose Control arm must be attributed, if this is a gate arm rather than a cell. + [string] $ControlElement, + [string] $ConformanceRoot = (Join-Path (Split-Path $PSScriptRoot -Parent) '') +) + +$ErrorActionPreference = 'Stop' +$root = (Resolve-Path $ConformanceRoot).Path +$dtd = Join-Path $root 'HermitCrabInput.dtd' +if (-not (Test-Path $dtd)) { throw "DTD not found at $dtd" } + +# GrammarRuleIndex.cs's switch on el.Name.LocalName -- the ONLY element names a fired rule can be +# mapped back to. An arm whose construct sits elsewhere cannot have a Control attributed. +$ruleIndexable = @( + 'MorphologicalRule', 'RealizationalRule', 'CompoundingRule', 'PhonologicalRule', 'MetathesisRule', + 'MorphemeCoOccurrenceRule', 'AllomorphCoOccurrenceRule' +) + +$dtdText = Get-Content $dtd -Raw +$verdicts = [System.Collections.Generic.List[string]]::new() +$blocked = $false + +function Test-Severable { + param([string] $Spec) + $parts = $Spec -split '\.', 2 + if ($parts.Count -ne 2) { throw "expected Element.attribute, got '$Spec'" } + $attr = $parts[1] + # A #REQUIRED attribute cannot be removed: the mutant throws and the row records RequiredByDtd. + $pattern = [regex]::Escape($attr) + '\s+\S+\s+#REQUIRED' + if ($dtdText -match $pattern) { return $false } + return $true +} + +foreach ($spec in @(@{n = 'writer'; v = $Writer }, @{n = 'reader'; v = $Reader })) { + if (Test-Severable -Spec $spec.v) { + $verdicts.Add(" OK $($spec.n) $($spec.v) is severable") + } + else { + $verdicts.Add(" BLOCKED $($spec.n) $($spec.v) is DTD #REQUIRED -- severing throws, so the row can only ever be RequiredByDtd") + $blocked = $true + } +} + +# Writer and reader must set and read the same payload inside ONE fixture, or there is no chain to +# witness -- a word cannot join constructs that live in different grammars. +$writerEl = ($Writer -split '\.')[0]; $writerAt = ($Writer -split '\.', 2)[1] +$readerEl = ($Reader -split '\.')[0]; $readerAt = ($Reader -split '\.', 2)[1] +$hosts = @() +foreach ($dir in @('languages', 'edge-cases')) { + $base = Join-Path $root $dir + if (-not (Test-Path $base)) { continue } + foreach ($fx in Get-ChildItem $base -Directory) { + $g = Join-Path $fx.FullName 'grammar.xml' + if (-not (Test-Path $g)) { continue } + $x = Get-Content $g -Raw + $hasW = $x -match "<$writerEl\b[^>]*\b$writerAt=" + $hasR = $x -match "<$readerEl\b[^>]*\b$readerAt=" + if ($hasW -and $hasR) { $hosts += "$dir/$($fx.Name)" } + } +} +if ($hosts.Count -gt 0) { + $verdicts.Add(" OK writer and reader co-occur in: $($hosts -join ', ')") +} +else { + $verdicts.Add(" BLOCKED no single fixture declares both $Writer and $Reader -- needs a grammar change, not a word") + $blocked = $true +} + +if ($ControlElement) { + if ($ruleIndexable -contains $ControlElement) { + $verdicts.Add(" OK Control arm on $ControlElement is rule-indexable") + } + else { + $verdicts.Add(" BLOCKED GrammarRuleIndex cannot resolve $ControlElement to a fired-rule id -- the Control arm cannot be attributed even with a correct word present") + $blocked = $true + } +} + +Write-Output "obligation: $Writer -> $Reader$(if ($ControlElement) { " (control on $ControlElement)" })" +$verdicts | ForEach-Object { Write-Output $_ } +Write-Output '' +if ($blocked) { + Write-Output 'VERDICT: not an authoring task. Record it in obligation-triage.tsv with the blocker above.' + exit 1 +} +Write-Output 'VERDICT: looks authorable. Nothing here guarantees a witness exists -- only that no known mechanism forbids one.' +exit 0 diff --git a/conformance/tools/generate-fieldworks-producibility.ps1 b/conformance/tools/generate-fieldworks-producibility.ps1 new file mode 100644 index 000000000..f435dd951 --- /dev/null +++ b/conformance/tools/generate-fieldworks-producibility.ps1 @@ -0,0 +1,570 @@ +<# +.SYNOPSIS + Generates conformance/fieldworks-producibility.tsv: a ledger of whether FieldWorks' HCLoader + (Src/LexText/ParserCore/HCLoader.cs in the FieldWorks repo) can ever produce each HC construct + that the conformance suite's other ledgers measure. + +.DESCRIPTION + The SUBJECT LIST is extracted mechanically from two files already in this repo, so it can never + be hand-typed out of sync with its source: + - every SIL.Machine.Morphology.HermitCrab.FailureReason enum member (except None), read from + src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs + - every (element, attribute) row in conformance/interface-inventory.tsv + + The VERDICT for each subject (producible / hcloader_sites / notes) is NOT something a script can + derive -- it required reading the whole of HCLoader.cs (FieldWorks repo, ~2837 lines) and cross- + referencing this repo's own engine source (property definitions, XmlLanguageLoader.cs as the + ground truth for which runtime property a DTD attribute maps to, and InteractionChainLedger.cs's + own "dead" annotations). That research is embedded below as $Verdicts. Re-deriving it requires a + human to re-read HCLoader.cs; this script only guarantees the OUTPUT is well-formed and complete + against the two mechanically-extracted subject lists -- it cannot detect the FieldWorks repo + changing underneath a verdict recorded here. See conformance/docs/how-it-is-computed.md. + + Every subject found in the two source files MUST have a verdict below, or this script throws -- + silently defaulting an unclassified subject would be exactly the wrong kind of "I could not look + reads as everything is fine." +#> + +#Requires -Version 5.1 +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path +$TraceManagerPath = Join-Path $RepoRoot "src\SIL.Machine.Morphology.HermitCrab\ITraceManager.cs" +$InterfaceInventoryPath = Join-Path $RepoRoot "conformance\interface-inventory.tsv" +$OutputPath = Join-Path $RepoRoot "conformance\fieldworks-producibility.tsv" + +if (-not (Test-Path $TraceManagerPath)) { throw "Cannot find $TraceManagerPath" } +if (-not (Test-Path $InterfaceInventoryPath)) { throw "Cannot find $InterfaceInventoryPath" } + +# --------------------------------------------------------------------------- +# 1. Mechanically extract the FailureReason subjects (23, excluding None). +# --------------------------------------------------------------------------- +$traceManagerText = Get-Content $TraceManagerPath -Raw +$enumMatch = [regex]::Match($traceManagerText, "public enum FailureReason\s*\{(?[^}]*)\}") +if (-not $enumMatch.Success) { throw "Could not locate 'public enum FailureReason { ... }' in $TraceManagerPath" } +$failureReasons = $enumMatch.Groups["body"].Value -split "," | + ForEach-Object { $_.Trim() } | + Where-Object { $_ -and $_ -ne "None" } + +if ($failureReasons.Count -ne 23) { + throw "Expected 23 FailureReason members besides None, found $($failureReasons.Count): $($failureReasons -join ', ')" +} + +# --------------------------------------------------------------------------- +# 2. Mechanically extract the interface-inventory subjects (60 rows). +# --------------------------------------------------------------------------- +$inventoryLines = Get-Content $InterfaceInventoryPath | Where-Object { $_ -and -not $_.StartsWith("#") } +if ($inventoryLines.Count -lt 2) { throw "$InterfaceInventoryPath has no data rows" } +$header = $inventoryLines[0] -split "`t" +$elementCol = [array]::IndexOf($header, "element") +$attributeCol = [array]::IndexOf($header, "attribute") +if ($elementCol -lt 0 -or $attributeCol -lt 0) { throw "interface-inventory.tsv header missing element/attribute columns" } + +$interfaceAttrs = @() +foreach ($line in $inventoryLines[1..($inventoryLines.Count - 1)]) { + $cols = $line -split "`t" + $interfaceAttrs += [PSCustomObject]@{ + Element = $cols[$elementCol] + Attribute = $cols[$attributeCol] + } +} + +if ($interfaceAttrs.Count -ne 60) { + throw "Expected 60 interface-inventory rows, found $($interfaceAttrs.Count)" +} + +# --------------------------------------------------------------------------- +# 3. Researched verdicts, keyed by subject_kind + subject. See the header +# comment: this table is the product of reading the whole of HCLoader.cs +# (FieldWorks repo) plus this repo's own engine source, not a derivation. +# --------------------------------------------------------------------------- +$Verdicts = @{} + +function Add-Verdict([string]$Kind, [string]$Subject, [string]$Producible, [string[]]$Sites, [string]$Notes) { + $key = "$Kind|$Subject" + if ($Verdicts.ContainsKey($key)) { throw "Duplicate verdict for $key" } + $Verdicts[$key] = [PSCustomObject]@{ + Producible = $Producible + Sites = ($Sites -join "; ") + Notes = $Notes + } +} + +# --- FailureReason subjects (subject_kind = failure-reason) ----------------- + +Add-Verdict "failure-reason" "ObligatorySyntacticFeatures" "No" @() ( + "HCLoader never sets AffixProcessRule.ObligatorySyntacticFeatures or CompoundingRule." + + "ObligatorySyntacticFeatures (checked LoadDerivAffixProcessRule HCLoader.cs:926-974, " + + "LoadInflAffixProcessRule 976-1006, LoadEndoCompoundingRule 1842-1912, LoadExoCompoundingRule " + + "1922-2001 -- zero assignments). The only engine trigger, Morpher.cs:603-613, gates on " + + "word.ObligatorySyntacticFeatures, fed exclusively by those two rule properties, so this " + + "reason can never fire for a FieldWorks-produced grammar. Searched HCLoader.cs for: " + + "ObligatorySyntacticFeatures, OutputObligatoryFeatures, obligatoryHeadFeatures, " + + "obligatoryFootFeatures, Obligatory -- zero hits beyond unrelated identifiers. Matches this " + + "task's stated known data point exactly, and is the same underlying gap behind interface rows " + + "CompoundingRule.outputObligatoryFeatures and MorphologicalRule.outputObligatoryFeatures (also No)." +) + +Add-Verdict "failure-reason" "AllomorphCoOccurrenceRules" "Yes" @( + "HCLoader.cs:2163-2189 (LoadAllomorphCoOccurrenceRules)" + "HCLoader.cs:341-345 (call site, gated on IMoAlloAdhocProhibRepository)" +) "Corroborated by HCLoaderTests.cs:1046-1047 (AllomorphCoOccurrenceRules.Count/First asserted)." + +Add-Verdict "failure-reason" "Environments" "Yes" @( + "HCLoader.cs:815-829 (LoadRootAllomorph)" + "HCLoader.cs:1322 (LoadCircumfixAffixProcessAllomorph)" + "HCLoader.cs:1577,1604 (LoadFormAffixProcessAllomorph)" +) "Any phonologically-conditioned allomorph environment a FieldWorks user enters produces this; one of the most routine constructs in the loader." + +Add-Verdict "failure-reason" "MorphemeCoOccurrenceRules" "Yes" @( + "HCLoader.cs:2213-2239 (LoadMorphemeCoOccurrenceRules)" + "HCLoader.cs:347-351 (call site, gated on IMoMorphAdhocProhibRepository)" +) "Corroborated by HCLoaderTests.cs:1066-1067 (MorphemeCoOccurrenceRules.Count/First asserted)." + +Add-Verdict "failure-reason" "DisjunctiveAllomorph" "Yes" @( + "HCLoader.cs:716-728 (LoadLexEntry, multiple RootAllomorph added per entry)" + "engine repo Allomorph.cs:127-151 derives this purely from allomorph index/environment ordering" +) "Not gated by a distinct DTD attribute; fires whenever an entry HCLoader builds has more than one ordered, differently-conditioned allomorph -- ordinary FieldWorks allomorphy." + +Add-Verdict "failure-reason" "SurfaceFormMismatch" "Yes" @( + "HCLoader.cs:204,2669-2743 (LoadCharacterDefinitionTable, always invoked once)" + "HCLoader.cs:233 (Surface stratum, always created)" +) "Intrinsic engine self-check (engine repo Morpher.cs:620-633) comparing a synthesized shape to the surface stratum's table; exercised on every FieldWorks-produced grammar, not gated by an optional construct." + +Add-Verdict "failure-reason" "Pattern" "Yes" @( + "HCLoader.cs:2313-2418 (LoadPatternNode/LoadPatternNodes, used throughout affix and phonological rule construction)" +) "Fires on any Lhs pattern mismatch; reachable trivially for any grammar with at least one rule, which every FieldWorks project produces." + +Add-Verdict "failure-reason" "HeadPattern" "Yes" @( + "HCLoader.cs:1808-1840 (DefaultCompoundingRules, always generated unless NoDefaultCompounding is set)" + "HCLoader.cs:1878-1904 (LoadEndoCompoundingRule head/nonhead pattern)" + "HCLoader.cs:1943-1965 (LoadExoCompoundingRule head/nonhead pattern)" +) "Default compounding rules alone make this reachable even with zero user-defined compound rules." + +Add-Verdict "failure-reason" "NonHeadPattern" "Yes" @( + "HCLoader.cs:1808-1840 (DefaultCompoundingRules)" + "HCLoader.cs:1878-1904,1943-1965 (Endo/Exo nonhead pattern)" +) "Same reachability as HeadPattern." + +Add-Verdict "failure-reason" "RequiredSyntacticFeatureStruct" "Yes" @( + "HCLoader.cs:930-936 (LoadDerivAffixProcessRule)" + "HCLoader.cs:985-991 (LoadInflAffixProcessRule)" + "HCLoader.cs:1016-1020 (LoadUnclassifiedAffixProcessRule)" + "HCLoader.cs:1034-1038 (LoadCliticAffixProcessRule)" + "HCLoader.cs:2051-2055 (LoadRewriteRule)" +) "" + +Add-Verdict "failure-reason" "HeadRequiredSyntacticFeatureStruct" "Yes" @( + "HCLoader.cs:1844-1892 (LoadEndoCompoundingRule)" + "HCLoader.cs:1922-1957 (LoadExoCompoundingRule, right rule)" +) "" + +Add-Verdict "failure-reason" "NonHeadRequiredSyntacticFeatureStruct" "Yes" @( + "HCLoader.cs:1844-1892 (LoadEndoCompoundingRule)" + "HCLoader.cs:1922-1984 (LoadExoCompoundingRule, both rules)" +) "" + +Add-Verdict "failure-reason" "HeadProdRestrictMprFeatures" "Yes" @( + "HCLoader.cs:1888 (LoadEndoCompoundingRule)" + "HCLoader.cs:1953,1980 (LoadExoCompoundingRule, both rules)" +) "Matches this task's stated known data point (~6 total hits across Head+NonHead assignments)." + +Add-Verdict "failure-reason" "NonHeadProdRestrictMprFeatures" "Yes" @( + "HCLoader.cs:1889 (LoadEndoCompoundingRule)" + "HCLoader.cs:1954,1981 (LoadExoCompoundingRule, both rules)" +) "Engine trigger site (AnalysisCompoundingRule.cs) is analysis/parse direction only, not synthesis -- still reachable since parsing text is FLEx's primary use of HC." + +Add-Verdict "failure-reason" "RequiredMprFeatures" "Yes" @( + "HCLoader.cs:968,1001,1069,1096,1123 (AffixProcessAllomorph.RequiredMprFeatures)" + "HCLoader.cs:2057 (RewriteSubrule.RequiredMprFeatures)" +) "The CompoundingSubrule.RequiredMprFeatures path (HeadMorphologicalInput.requiredMPRFeatures) is never populated (see that interface row, No), but the affix/phonological paths alone make this reachable." + +Add-Verdict "failure-reason" "ExcludedMprFeatures" "Yes" @( + "HCLoader.cs:1717 (slot-blocking of irregularly-inflected forms)" + "HCLoader.cs:2058 (RewriteSubrule.ExcludedMprFeatures)" +) "" + +Add-Verdict "failure-reason" "RequiredStemName" "Yes" @( + "HCLoader.cs:960-962 (LoadDerivAffixProcessRule)" +) "Corroborated by HCLoaderTests.cs:698." + +Add-Verdict "failure-reason" "ExcludedStemName" "Yes" @( + "HCLoader.cs:831-833 (LoadRootAllomorph sets Allomorph.stemName; nothing prevents >1 stem-named allomorph per entry)" + "engine repo RootAllomorph.cs:72-91 derives ExcludedStemName purely from a second, differently stem-named sibling allomorph" +) "Structural consequence of a stem-name-restricted paradigm with more than one region on one entry's allomorphs -- ordinary FieldWorks usage, same underlying attribute as Allomorph.stemName (Yes)." + +Add-Verdict "failure-reason" "PartialParse" "Yes" @( + "HCLoader.cs:708 (LoadLexEntry, IsPartial when entry has no POS)" + "HCLoader.cs:982 (LoadInflAffixProcessRule, IsPartial when no slots)" + "HCLoader.cs:1013 (LoadUnclassifiedAffixProcessRule, always IsPartial)" +) "Corroborated by HCLoaderTests.cs:662,726,845." + +Add-Verdict "failure-reason" "BoundRoot" "Yes" @( + "HCLoader.cs:835-841 (LoadRootAllomorph, IsBound for bound-root/bound-stem morph types)" +) "Corroborated by HCLoaderTests.cs:818." + +Add-Verdict "failure-reason" "NonPartialRuleProhibitedAfterFinalTemplate" "Yes" @( + "HCLoader.cs:1678 (AffixTemplate.IsFinal from LibLCM template.Final)" + "HCLoader.cs:708,982,1013 (rule IsPartial sites)" +) "Corroborated by HCLoaderTests.cs:750,789 (IsFinal). Reachable whenever a non-final template is followed by a non-partial, non-template rule such as a derivational affix or clitic." + +Add-Verdict "failure-reason" "NonPartialRuleRequiredAfterNonFinalTemplate" "Yes" @( + "HCLoader.cs:1678 (AffixTemplate.IsFinal)" + "HCLoader.cs:708,982,1013 (rule IsPartial sites)" +) "Same drivers as NonPartialRuleProhibitedAfterFinalTemplate, opposite polarity of the same engine check." + +Add-Verdict "failure-reason" "MaxApplicationCount" "Yes" @( + "HCLoader.cs:103-112 (ParserParameters CompoundRules/maxApps parsed into m_CompoundRuleLookup)" + "HCLoader.cs:1894-1896 (CompoundingRule.MaxApplicationCount assignment)" +) "Only ever wired for CompoundingRule, not AffixProcessRule (grep-confirmed single assignment site) -- still reachable via the compounding path." + +# --- Interface-inventory subjects (subject_kind = interface-attribute) ------ + +Add-Verdict "interface-attribute" "AffixTemplate.requiredPartsOfSpeech" "Yes" @( + "HCLoader.cs:1681-1684 (LoadAffixTemplate)" +) "" + +Add-Verdict "interface-attribute" "AffixTemplate.requiredSubcategorizedRules" "No" @() ( + "Subcategorization/SyntacticRule is dead schema across the WHOLE engine, not just HCLoader: " + + "grepping src/SIL.Machine.Morphology.HermitCrab for 'Subcategoriz' outside the DTD file itself " + + "returns zero hits (no C# class implements it), and HCLoader.cs / HCLoaderTests.cs likewise " + + "have zero hits for 'Subcategoriz' or 'SyntacticRule'. Confirmed by this repo's own " + + "InteractionChainLedger.cs comments ('dead (subcategorization)') on all 9 subcategorization-" + + "family attributes (rows 12,20,23,27,35(no -- separate reason),40,52,55,56,57)." +) + +Add-Verdict "interface-attribute" "Allomorph.stemName" "Yes" @( + "HCLoader.cs:831-833 (LoadRootAllomorph)" +) "Corroborated by HCLoaderTests.cs:817." + +Add-Verdict "interface-attribute" "AllomorphCoOccurrenceRule.otherAllomorphs" "Yes" @( + "HCLoader.cs:2163-2189" +) "" + +Add-Verdict "interface-attribute" "AllomorphCoOccurrenceRule.primaryAllomorph" "Yes" @( + "HCLoader.cs:2166,2181-2186" +) "" + +Add-Verdict "interface-attribute" "AlphaVariable.variableFeature" "Yes" @( + "HCLoader.cs:2005-2011 (LoadRewriteRule, variable naming)" + "HCLoader.cs:2765-2773 (GetVariables ties a variable name to a specific phonological feature)" +) "The Machine engine has no runtime 'AlphaVariable' class (grep-confirmed) -- the DTD's two-hop AlphaVariable->VariableFeature->feature indirection collapses at runtime to SymbolicFeatureValue(feature, variableName, agree), which HCLoader constructs directly." + +Add-Verdict "interface-attribute" "BoundaryMarker.boundary" "Yes" @( + "HCLoader.cs:2698-2712 (LoadCharacterDefinitionTable loads BoundaryMarkersOC into m_charDefs)" + "HCLoader.cs:2348-2360 (LoadPatternNode, PhSimpleContextBdry emits a Constraint referencing that charDef)" +) "" + +Add-Verdict "interface-attribute" "CompoundingRule.headPartsOfSpeech" "Yes" @( + "HCLoader.cs:1848-1869 (LoadEndoCompoundingRule)" + "HCLoader.cs:1924-1931 (LoadExoCompoundingRule)" +) "" + +Add-Verdict "interface-attribute" "CompoundingRule.headProdRestrictionsMprFeatures" "Yes" @( + "HCLoader.cs:1888,1953,1980" +) "Matches this task's stated known data point (~6 hits)." + +Add-Verdict "interface-attribute" "CompoundingRule.headSubcategorizedRules" "No" @() "Subcategorization, dead (see AffixTemplate.requiredSubcategorizedRules)." + +Add-Verdict "interface-attribute" "CompoundingRule.nonHeadPartsOfSpeech" "Yes" @( + "HCLoader.cs:1852-1864,1929-1930" +) "" + +Add-Verdict "interface-attribute" "CompoundingRule.nonHeadProdRestrictionsMprFeatures" "Yes" @( + "HCLoader.cs:1889,1954,1981" +) "interface-inventory.tsv shows present=no because no CONFORMANCE FIXTURE happens to exercise it -- a corpus-coverage fact, not an HCLoader-capability fact. The code path is identical to headProdRestrictionsMprFeatures." + +Add-Verdict "interface-attribute" "CompoundingRule.nonHeadSubcategorizedRules" "No" @() "Subcategorization, dead." + +Add-Verdict "interface-attribute" "CompoundingRule.outputObligatoryFeatures" "No" @() ( + "Absence confirmed across LoadEndoCompoundingRule (HCLoader.cs:1842-1912) and " + + "LoadExoCompoundingRule (HCLoader.cs:1922-2001) -- neither ever touches " + + "CompoundingRule.ObligatorySyntacticFeatures. The engine fully implements this " + + "(CompoundingRule.cs:54-57, XmlLanguageLoader.cs:1227-1231), so this is a FieldWorks-specific " + + "gap, not dead schema -- the same absence drives FailureReason.ObligatorySyntacticFeatures=No. " + + "Searched: ObligatorySyntacticFeatures, outputObligatoryFeatures, Obligatory." +) + +Add-Verdict "interface-attribute" "CompoundingRule.outputPartOfSpeech" "Yes" @( + "HCLoader.cs:1873-1876,1932-1935" +) "" + +Add-Verdict "interface-attribute" "CompoundingRule.outputProdRestrictionsMprFeatures" "No" @() ( + "Property OutputProdRestrictionsMprFeatures exists on CompoundingRule (engine repo " + + "CompoundingRule.cs:25,50) and is never set by HCLoader (checked LoadEndoCompoundingRule " + + "HCLoader.cs:1842-1912 and LoadExoCompoundingRule 1922-2001; grep-confirmed zero hits for " + + "'OutputProdRestrictionsMprFeatures' across all of HCLoader.cs). Only OutMprFeatures, " + + "HeadProdRestrictionsMprFeatures and NonHeadProdRestrictionsMprFeatures are ever populated." +) + +Add-Verdict "interface-attribute" "CompoundingRule.outputSubcategorization" "No" @() "Subcategorization, dead." + +Add-Verdict "interface-attribute" "CopyFromInput.index" "Yes" @( + "HCLoader.cs:1310,1384,1454-1518,1547-1601 (pervasive)" +) "" + +Add-Verdict "interface-attribute" "FeatureValue.feature" "Yes" @( + "HCLoader.cs:2500-2530 (LoadFeatureStruct)" +) "" + +Add-Verdict "interface-attribute" "FeatureValue.symbolValues" "Yes" @( + "HCLoader.cs:2507-2516" +) "" + +Add-Verdict "interface-attribute" "HeadMorphologicalInput.excludedMPRFeatures" "No" @() ( + "Absence confirmed across both compounding-rule loaders (HCLoader.cs:1898-1910 Endo, " + + "1959-1971/1986-1998 Exo) -- CompoundingSubrule.ExcludedMprFeatures (engine repo " + + "CompoundingSubrule.cs:48-51) is never set by HCLoader; grep-confirmed only OutMprFeatures is " + + "ever touched on a CompoundingSubrule. Ground truth for which runtime property this DTD " + + "attribute maps to: engine repo XmlLanguageLoader.cs:1278-1279." +) + +Add-Verdict "interface-attribute" "HeadMorphologicalInput.requiredMPRFeatures" "No" @() ( + "Same absence and citations as HeadMorphologicalInput.excludedMPRFeatures (CompoundingSubrule." + + "RequiredMprFeatures is likewise never set; XmlLanguageLoader.cs:1278 is the ground-truth mapping)." +) + +Add-Verdict "interface-attribute" "InsertSegments.characterDefinitionTable" "No" @() ( + "HCLoader.cs:204 loads exactly one PhonemeSetsOS[0] as the whole grammar's character table; " + + "HCLoader.cs:2831-2835 (Segments() helper) and every InsertSegments call always route through " + + "that single m_table field; HCLoader.cs:2742 adds it to m_language.CharacterDefinitionTables " + + "exactly once. HCLoader architecturally never builds more than one CharacterDefinitionTable, " + + "so an explicit override to a non-default table -- what this attribute exists for -- can never " + + "carry a meaningful value, in any FieldWorks project or configuration." +) + +Add-Verdict "interface-attribute" "LexicalEntry.family" "No" @() ( + "Full-file grep of HCLoader.cs for 'family'/'Family' returns zero hits. The engine's LexFamily/" + + "LexEntry.Family mechanism exists (engine repo LexEntry.cs:92, LexFamily.cs) and HCLoader's own " + + "TODO comment (HCLoader.cs:744, 'irregularly inflected forms should be handled by rule blocking " + + "in HC') shows it deliberately uses a different, MPR-feature-based mechanism instead of the " + + "engine's native Family-blocking feature for exactly the case (irregular/variant forms) the DTD " + + "comment says Family exists for." +) + +Add-Verdict "interface-attribute" "LexicalEntry.morphologicalRules" "No" @() ( + "Dead even in the engine's own reference XML loader (this repo's InteractionChainLedger.cs:79, " + + "'dead: no loader reference at all'). LexEntry has no MorphologicalRules property at all in the " + + "runtime object model (grep-confirmed against engine repo LexEntry.cs), so HCLoader cannot set " + + "it regardless of what LibLCM data exists." +) + +Add-Verdict "interface-attribute" "LexicalEntry.obligatoryFootFeatures" "No" @() ( + "Dead even in the engine's own reference XML loader (InteractionChainLedger.cs:80). LexEntry " + + "has no such property (only MprFeatures, SyntacticFeatureStruct -- engine repo LexEntry.cs:80,86)." +) + +Add-Verdict "interface-attribute" "LexicalEntry.obligatoryHeadFeatures" "No" @() ( + "Dead even in the engine's own reference XML loader (InteractionChainLedger.cs:81). Matches " + + "this task's stated expectation. Searched HCLoader.cs and engine repo LexEntry.cs for: " + + "obligatoryHeadFeatures, ObligatoryHeadFeatures, Obligatory -- zero hits beyond the unrelated " + + "ObligatorySyntacticFeatures mechanism." +) + +Add-Verdict "interface-attribute" "LexicalEntry.partOfSpeech" "Yes" @( + "HCLoader.cs:705-708" +) "" + +Add-Verdict "interface-attribute" "LexicalEntry.ruleFeatures" "Yes" @( + "HCLoader.cs:695-701,737-746 (inflection-class and productivity-restriction features unioned into hcEntry.MprFeatures)" +) "" + +Add-Verdict "interface-attribute" "LexicalEntry.subcategorizations" "No" @() "Subcategorization, dead." + +Add-Verdict "interface-attribute" "MetathesisRule.leftSwitch" "Yes" @( + "HCLoader.cs:2103-2161 (LoadMetathesisRule)" + "HCLoader.cs:322-336 (call site, gated on LeftSwitchIndex/RightSwitchIndex != -1)" +) "" + +Add-Verdict "interface-attribute" "MetathesisRule.rightSwitch" "Yes" @( + "HCLoader.cs:2103-2161" + "HCLoader.cs:322-336" +) "" + +Add-Verdict "interface-attribute" "ModifyFromInput.index" "Yes" @( + "HCLoader.cs:1409-1419" +) "" + +Add-Verdict "interface-attribute" "MorphemeCoOccurrenceRule.otherMorphemes" "Yes" @( + "HCLoader.cs:2213-2239" +) "" + +Add-Verdict "interface-attribute" "MorphemeCoOccurrenceRule.primaryMorpheme" "Yes" @( + "HCLoader.cs:2215-2235" +) "" + +Add-Verdict "interface-attribute" "MorphologicalInput.excludedMPRFeatures" "Yes" @( + "HCLoader.cs:1717 (AffixProcessAllomorph.ExcludedMprFeatures)" +) "Ground-truth mapping via engine repo XmlLanguageLoader.cs:1057-1062." + +Add-Verdict "interface-attribute" "MorphologicalInput.requiredMPRFeatures" "Yes" @( + "HCLoader.cs:968,1001,1069,1096,1123" +) "" + +Add-Verdict "interface-attribute" "MorphologicalOutput.MPRFeatures" "Yes" @( + "HCLoader.cs:969 (AffixProcessAllomorph.OutMprFeatures)" + "HCLoader.cs:1901,1961,1988 (CompoundingSubrule.OutMprFeatures)" +) "" + +Add-Verdict "interface-attribute" "MorphologicalPhonologicalRuleFeatureGroup.features" "Yes" @( + "HCLoader.cs:168-192 (LoadLanguage, three MprFeatureGroups)" + "HCLoader.cs:571-577 (LoadMprFeature, group.MprFeatures.Add(feat))" +) "" + +Add-Verdict "interface-attribute" "MorphologicalRule.outputObligatoryFeatures" "No" @() ( + "Absence confirmed across all four AffixProcessRule loaders (HCLoader.cs:926-1046). " + + "AffixProcessRule.ObligatorySyntacticFeatures (engine repo AffixProcessRule.cs:68) is never " + + "set. Same underlying gap as CompoundingRule.outputObligatoryFeatures and " + + "FailureReason.ObligatorySyntacticFeatures (both also No)." +) + +Add-Verdict "interface-attribute" "MorphologicalRule.outputPartOfSpeech" "Yes" @( + "HCLoader.cs:938-944" +) "" + +Add-Verdict "interface-attribute" "MorphologicalRule.outputSubcategorization" "No" @() "Subcategorization, dead." + +Add-Verdict "interface-attribute" "MorphologicalRule.requiredPartsOfSpeech" "Yes" @( + "HCLoader.cs:930-936,985-991,1016-1020,1034-1038" +) "" + +Add-Verdict "interface-attribute" "MorphologicalRule.requiredStemName" "Yes" @( + "HCLoader.cs:960-962" +) "Corroborated by HCLoaderTests.cs:698." + +Add-Verdict "interface-attribute" "MorphologicalRule.requiredSubcategorizedRules" "No" @() "Subcategorization, dead." + +Add-Verdict "interface-attribute" "OutputSubcategorizationOverride.inputSubcategorization" "No" @() "Subcategorization, dead; the OutputSubcategorizationOverride element is never referenced anywhere in HCLoader.cs." + +Add-Verdict "interface-attribute" "OutputSubcategorizationOverride.outputSubcategorization" "No" @() "Subcategorization, dead; see inputSubcategorization." + +Add-Verdict "interface-attribute" "PhonologicalSubrule.excludedMPRFeatures" "Yes" @( + "HCLoader.cs:2058" +) "interface-inventory.tsv shows present=no (no fixture exercises it) but the HCLoader code path is live -- a corpus-coverage fact, not a capability fact." + +Add-Verdict "interface-attribute" "PhonologicalSubrule.requiredMPRFeatures" "Yes" @( + "HCLoader.cs:2057" +) "Same corpus-coverage caveat as excludedMPRFeatures." + +Add-Verdict "interface-attribute" "PhonologicalSubrule.requiredPartsOfSpeech" "Yes" @( + "HCLoader.cs:2051-2055" +) "" + +Add-Verdict "interface-attribute" "Segment.segment" "Yes" @( + "HCLoader.cs:2362-2374 (LoadPatternNode, PhSimpleContextSeg)" +) "" + +Add-Verdict "interface-attribute" "Segments.characterDefinitionTable" "No" @() ( + "Same reasoning and citations as InsertSegments.characterDefinitionTable: HCLoader always " + + "builds exactly one CharacterDefinitionTable (HCLoader.cs:204,2742) so a per-instance override " + + "to a different table can never carry a meaningful value." +) + +Add-Verdict "interface-attribute" "SimpleContext.naturalClass" "Yes" @( + "HCLoader.cs:2745-2786 (TryLoadSimpleContext, both overloads)" +) "" + +Add-Verdict "interface-attribute" "Slot.morphologicalRules" "Yes" @( + "HCLoader.cs:1702-1731 (LoadAffixTemplate slot/rule assembly)" +) "" + +Add-Verdict "interface-attribute" "StemName.partsOfSpeech" "Yes" @( + "HCLoader.cs:206-224 (LoadLanguage, StemName regions)" +) "" + +Add-Verdict "interface-attribute" "Stratum.characterDefinitionTable" "Yes" @( + "HCLoader.cs:227-233 (default strata)" + "HCLoader.cs:374 (CreateStrata, custom strata)" +) "" + +Add-Verdict "interface-attribute" "Stratum.morphologicalRules" "Yes" @( + "HCLoader.cs:237,246,250 (compounding rules)" + "HCLoader.cs:290-292,916-923 (AddMorphologicalRule)" +) "" + +Add-Verdict "interface-attribute" "Stratum.phonologicalRules" "Yes" @( + "HCLoader.cs:314-333" +) "" + +Add-Verdict "interface-attribute" "SymbolicFeature.defaultSymbol" "No" @() ( + "HCLoader.cs:2650-2667 (LoadFeatureSystem) never sets a default value on any SymbolicFeature " + + "it builds. The engine property is SymbolicFeature.DefaultSymbolID/DefaultValue (engine repo " + + "FeatureModel/SymbolicFeature.cs:34-36), read by XmlLanguageLoader.cs:644 -- so this is a " + + "FieldWorks-specific gap, not dead schema. Searched HCLoader.cs for: Default, DefaultSymbol, " + + "DefaultValue -- only unrelated hits (writing-system/inflection-class/compounding defaults)." +) + +Add-Verdict "interface-attribute" "VariableFeature.phonologicalFeature" "Yes" @( + "HCLoader.cs:2765-2773 (GetVariables)" +) "Same runtime-collapse caveat as AlphaVariable.variableFeature -- no 'VariableFeature' class exists in the engine's runtime object model (grep-confirmed), so this is evaluated via the equivalent runtime construct HCLoader actually builds." + +# --------------------------------------------------------------------------- +# 4. Join mechanically-extracted subjects against the verdict table. Any +# subject missing a verdict is a loud failure, never a silent default. +# --------------------------------------------------------------------------- +$rows = New-Object System.Collections.Generic.List[PSCustomObject] + +foreach ($reason in $failureReasons) { + $key = "failure-reason|$reason" + if (-not $Verdicts.ContainsKey($key)) { throw "No verdict recorded for FailureReason.$reason -- add one to `$Verdicts before regenerating." } + $v = $Verdicts[$key] + $rows.Add([PSCustomObject]@{ + subject_kind = "failure-reason" + subject = $reason + producible = $v.Producible + hcloader_sites = $v.Sites + notes = $v.Notes + }) +} + +foreach ($attr in $interfaceAttrs) { + $subject = "$($attr.Element).$($attr.Attribute)" + $key = "interface-attribute|$subject" + if (-not $Verdicts.ContainsKey($key)) { throw "No verdict recorded for interface attribute $subject -- add one to `$Verdicts before regenerating." } + $v = $Verdicts[$key] + $rows.Add([PSCustomObject]@{ + subject_kind = "interface-attribute" + subject = $subject + producible = $v.Producible + hcloader_sites = $v.Sites + notes = $v.Notes + }) +} + +# Verify every verdict was actually consumed (catches a stale entry after a rename/removal). +$expectedKeys = @() +$expectedKeys += $failureReasons | ForEach-Object { "failure-reason|$_" } +$expectedKeys += $interfaceAttrs | ForEach-Object { "interface-attribute|$($_.Element).$($_.Attribute)" } +$staleKeys = $Verdicts.Keys | Where-Object { $expectedKeys -notcontains $_ } +if ($staleKeys) { throw "Verdict table has entries with no matching subject (stale after a rename?): $($staleKeys -join ', ')" } + +# Uniqueness, mechanically enforced. +$dupes = $rows | Group-Object subject_kind, subject | Where-Object { $_.Count -gt 1 } +if ($dupes) { throw "Duplicate subjects in output: $($dupes.Name -join '; ')" } + +if ($rows.Count -ne 83) { throw "Expected 83 total rows (23 failure-reason + 60 interface-attribute), got $($rows.Count)" } + +# --------------------------------------------------------------------------- +# 5. Emit the TSV. +# --------------------------------------------------------------------------- +$lines = New-Object System.Collections.Generic.List[string] +$lines.Add("# GENERATED by conformance/tools/generate-fieldworks-producibility.ps1. One row per subject,") +$lines.Add("# where subjects are every SIL.Machine.Morphology.HermitCrab.FailureReason enum member (except") +$lines.Add("# None) plus every (element, attribute) row in conformance/interface-inventory.tsv. Authority:") +$lines.Add("# FieldWorks' HCLoader.cs (Src/LexText/ParserCore/HCLoader.cs) -- the component that turns a") +$lines.Add("# real FieldWorks/LibLCM project into an HC grammar. producible=No means no FieldWorks user can") +$lines.Add("# ever produce this construct, so covering it elsewhere in this suite proves nothing about real") +$lines.Add("# use. See conformance/docs/how-it-is-computed.md for the full explanation, including why this") +$lines.Add("# ledger is a point-in-time snapshot of an external repo that cannot be drift-checked here.") +$lines.Add("subject_kind`tsubject`tproducible`thcloader_sites`tnotes") +foreach ($row in $rows) { + $lines.Add(("{0}`t{1}`t{2}`t{3}`t{4}" -f $row.subject_kind, $row.subject, $row.producible, $row.hcloader_sites, $row.notes)) +} + +Set-Content -Path $OutputPath -Value $lines -Encoding utf8NoBOM +Write-Host "Wrote $($rows.Count) rows to $OutputPath" +$yes = @($rows | Where-Object { $_.producible -eq "Yes" }).Count +$no = @($rows | Where-Object { $_.producible -eq "No" }).Count +$cond = @($rows | Where-Object { $_.producible -eq "Conditional" }).Count +Write-Host "producible: Yes=$yes No=$no Conditional=$cond" diff --git a/eng/HcRoslynCompilerReferences.props b/eng/HcRoslynCompilerReferences.props new file mode 100644 index 000000000..f28d299f0 --- /dev/null +++ b/eng/HcRoslynCompilerReferences.props @@ -0,0 +1,12 @@ + + + + $(MSBuildToolsPath)/Roslyn/bincore/Microsoft.CodeAnalysis.dll + true + + + $(MSBuildToolsPath)/Roslyn/bincore/Microsoft.CodeAnalysis.CSharp.dll + true + + + diff --git a/eng/HcSemanticCompilerInputs.targets b/eng/HcSemanticCompilerInputs.targets new file mode 100644 index 000000000..5eb751e06 --- /dev/null +++ b/eng/HcSemanticCompilerInputs.targets @@ -0,0 +1,8 @@ + + + hc-semantic-msbuild/v1 + + + + diff --git a/global.json b/global.json new file mode 100644 index 000000000..fe7e453b1 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "10.0.100", + "rollForward": "latestFeature", + "allowPrerelease": false + } +} \ No newline at end of file diff --git a/local_check.sh b/local_check.sh index 44d78c087..d80b368b7 100755 --- a/local_check.sh +++ b/local_check.sh @@ -10,3 +10,25 @@ if [ $? -ne 0 ]; then exit 1 fi dotnet test --verbosity normal +if [ $? -ne 0 ]; then + exit 1 +fi +# The same checks CI runs after the test suite: recompute the generated-surface coverage ledger and +# execute every conformance fixture. Both are also asserted from dotnet test; running them through the +# CLI keeps the failure legible and reproducible by hand. +dotnet run --no-build -c Release --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- \ + --semantic-coverage --repository-root . +if [ $? -ne 0 ]; then + exit 1 +fi +dotnet run --no-build -c Release --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- \ + --fixtures conformance +if [ $? -ne 0 ]; then + exit 1 +fi +python conformance/parity-check.py + +# The counterfactual evidence sweep re-parses every fixture once per surface, so it costs minutes and is +# deliberately not run here. It has its own workflow (.github/workflows/counterfactual-coverage.yml) and +# can be run on demand: +# dotnet run --project src/SIL.Machine.Morphology.HermitCrab.Conformance -- --counterfactual --repository-root . diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/AdapterEngine.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/AdapterEngine.cs new file mode 100644 index 000000000..c354a0296 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/AdapterEngine.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Runs a fixture against an external engine adapter process, per the contract in +/// conformance/PROTOCOL.md section 1: <engine-binary> batch <grammar> <words.txt> +/// <output.tsv>. The command template is supplied by the caller (--adapter) with +/// {grammar}/{words}/{output} placeholders, e.g.: +/// "C:\...\hc-rs.exe batch {grammar} {words} {output}". +/// +public class AdapterEngine : IEngine +{ + private readonly List _templateTokens; + private readonly int _timeoutMs; + + public AdapterEngine(string commandTemplate, IReadOnlySet capabilities, int timeoutMs = 5 * 60 * 1000) + { + // Tokenize + validate the template once here, not per fixture run: a bad/empty template is + // a configuration error that should fail fast, not surface 41 times over. Tokenization + // itself is shared with the Tool project's own command-line parsing (see + // Program.SplitCommandLine's doc comment) rather than a second, divergent copy. + _templateTokens = new List(SIL.Machine.Morphology.HermitCrab.Program.SplitCommandLine(commandTemplate)); + if (_templateTokens.Count == 0) + throw new InvalidOperationException("empty --adapter command template"); + _timeoutMs = timeoutMs; + Capabilities = capabilities; + } + + public string Name => "adapter"; + + public IReadOnlySet Capabilities { get; } + + public List Run(MaterializedFixture fixture) + { + string outputPath = Path.Combine(Path.GetTempPath(), "hc-conformance-" + Guid.NewGuid().ToString("N") + ".tsv"); + try + { + var tokens = new List(_templateTokens.Count); + foreach (string token in _templateTokens) + { + tokens.Add( + token + .Replace("{grammar}", Path.GetFullPath(fixture.GrammarPath)) + .Replace("{words}", Path.GetFullPath(fixture.WordsPath)) + .Replace("{output}", outputPath) + ); + } + + var psi = new ProcessStartInfo + { + FileName = tokens[0], + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + for (int i = 1; i < tokens.Count; i++) + psi.ArgumentList.Add(tokens[i]); + + using Process process = + Process.Start(psi) + ?? throw new InvalidOperationException($"failed to start adapter process '{tokens[0]}'"); + + // Start draining both streams asynchronously BEFORE waiting for exit: reading them + // synchronously (ReadToEnd) first would block forever on a child that fills its + // stderr/stdout buffer before exiting, making the timeout below unreachable. + Task stdoutTask = process.StandardOutput.ReadToEndAsync(); + Task stderrTask = process.StandardError.ReadToEndAsync(); + + // A fixture's own manifest budget (pathological fixtures) takes over the process + // timeout for that one run instead of the default 5 minutes, so a runaway adapter gets + // killed at the same wall-clock bound MaterializedRunner enforces, not five minutes later. + int effectiveTimeoutMs = + fixture.Manifest.Budget != null ? (int)fixture.Manifest.Budget.WallClockMs : _timeoutMs; + + bool exited = process.WaitForExit(effectiveTimeoutMs); + if (!exited) + { + try + { + process.Kill(entireProcessTree: true); + } + catch (InvalidOperationException) { } + throw new TimeoutException( + $"adapter process for fixture '{fixture.Id}' did not exit within {effectiveTimeoutMs}ms" + ); + } + + string stdout = stdoutTask.GetAwaiter().GetResult(); + string stderr = stderrTask.GetAwaiter().GetResult(); + + if (process.ExitCode != 0) + { + // The engine under test itself failed (as opposed to a harness-level problem like + // a bad --adapter template, a hung process, or exiting 0 with no output) -- see + // EngineCrashException's doc comment for the PASS/FAIL contract this feeds MaterializedRunner. + throw new EngineCrashException( + $"adapter process exited {process.ExitCode} for fixture '{fixture.Id}'.\nstdout:\n{stdout}\nstderr:\n{stderr}" + ); + } + if (!File.Exists(outputPath)) + { + throw new InvalidOperationException( + $"adapter process for fixture '{fixture.Id}' did not produce its output file.\nstdout:\n{stdout}\nstderr:\n{stderr}" + ); + } + return SignatureTsv.ReadFile(outputPath); + } + finally + { + try + { + if (File.Exists(outputPath)) + File.Delete(outputPath); + } + catch (IOException) { } + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/CoverageReport.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/CoverageReport.cs new file mode 100644 index 000000000..d37f7196d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/CoverageReport.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Emits two coverage tables: conformance/coverage.csv (language, word, parse signature, +/// construct -- one row per +/// parse×construct, expect_fail words getting an empty signature) and conformance/rules.csv +/// (language, rule id, exercising words -- semicolon-joined, blocked_by attributions marked +/// with a "!" prefix), plus dead-rule detection: every rule id finds +/// in a grammar.xml that no word's "rules:"/"blocked_by" ever names. +/// +public static class CoverageReport +{ + public class DeadRule + { + public string FixtureId = ""; + public string Language = ""; + public string RuleId = ""; + } + + public class CoverageResult + { + public List DeadRules { get; } = new(); + + /// Every construct string any word exercises (the distinct construct column + /// of coverage.csv). Diffed against constructs.txt by the caller to report absolute + /// construct coverage. + public HashSet CoveredConstructs { get; } = new(StringComparer.Ordinal); + } + + public static List LoadConstructChecklist(string path) + { + var constructs = new List(); + foreach (string rawLine in File.ReadAllLines(path)) + { + string line = rawLine.Trim(); + if (line.Length == 0 || line.StartsWith("#")) + continue; + constructs.Add(line); + } + return constructs; + } + + public static CoverageResult WriteCsvs(List fixtures, string coverageCsvPath, string rulesCsvPath) + { + var result = new CoverageResult(); + var coverageRows = new List<(string language, string word, string signature, string construct)>(); + var ruleRows = new List<(string language, string ruleId, string words)>(); + + foreach (Fixture fixture in fixtures) + { + string language = fixture.Words.Language; + GrammarRuleIndex ruleIndex = GrammarRuleIndex.Load(fixture.GrammarPath); + + // rule id -> exercising word tokens ("word" for a positive rules: hit, "!word" for a + // blocked_by attribution on an expect_fail word). + var exercisingWords = new Dictionary>(StringComparer.Ordinal); + void AddExercise(string ruleId, string token) + { + if (!exercisingWords.TryGetValue(ruleId, out List list)) + { + list = new List(); + exercisingWords[ruleId] = list; + } + list.Add(token); + } + + foreach (WordEntry word in fixture.Words.Words) + { + if (word.ExpectFail || word.ExpectSkip) + { + // expect_fail and expect_skip words both carry word-level exercises and no parses; + // only expect_fail words carry blocked_by (a skip is malformed input, not a + // rule-forbidden analysis), but iterating the empty list is harmless either way. + foreach (string construct in word.Exercises) + { + coverageRows.Add((language, word.Word, "", construct)); + result.CoveredConstructs.Add(construct); + } + foreach (string ruleId in word.BlockedBy) + AddExercise(ruleId, "!" + word.Word); + } + else + { + foreach (ParseEntry parse in word.Parses) + { + IEnumerable constructs = parse + .Exercises.Concat(word.Exercises) + .Distinct(StringComparer.Ordinal); + foreach (string construct in constructs) + { + coverageRows.Add((language, word.Word, parse.Signature, construct)); + result.CoveredConstructs.Add(construct); + } + foreach (string ruleId in parse.Rules) + AddExercise(ruleId, word.Word); + } + } + } + + foreach ( + string ruleId in ruleIndex + .AllRuleIds.Distinct(StringComparer.Ordinal) + .OrderBy(x => x, StringComparer.Ordinal) + ) + { + if (exercisingWords.TryGetValue(ruleId, out List words)) + { + ruleRows.Add((language, ruleId, string.Join(";", words.Distinct(StringComparer.Ordinal)))); + } + else + { + ruleRows.Add((language, ruleId, "")); + result.DeadRules.Add( + new DeadRule + { + FixtureId = fixture.Id, + Language = language, + RuleId = ruleId, + } + ); + } + } + } + + WriteCsv( + coverageCsvPath, + new[] { "language", "word", "signature", "construct" }, + coverageRows.Select(r => new[] { r.language, r.word, r.signature, r.construct }) + ); + WriteCsv( + rulesCsvPath, + new[] { "language", "rule_id", "words" }, + ruleRows.Select(r => new[] { r.language, r.ruleId, r.words }) + ); + + return result; + } + + private static void WriteCsv(string path, string[] header, IEnumerable rows) + { + var sb = new StringBuilder(); + sb.AppendLine(string.Join(",", header.Select(CsvField))); + foreach (string[] row in rows) + sb.AppendLine(string.Join(",", row.Select(CsvField))); + File.WriteAllText(path, sb.ToString()); + } + + private static string CsvField(string value) + { + value ??= ""; + if (value.IndexOfAny(new[] { ',', '"', '\n', '\r' }) >= 0) + return "\"" + value.Replace("\"", "\"\"") + "\""; + return value; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/Diff.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Diff.cs new file mode 100644 index 000000000..a1e674437 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Diff.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// Per-word outcome of diffing one fixture's actual output against its expected.tsv. +public class WordResult +{ + public string Word = ""; + public bool Passed; + public string Detail = ""; +} + +public class FixtureDiff +{ + public List WordResults { get; } = new(); + public bool AllPassed => WordResults.All(w => w.Passed); +} + +/// +/// Word/status/signature-only diffing between two batch-TSV row sets, per conformance/PROTOCOL.md +/// section 4. Rows are matched by word (idx/ms are never compared); a signature's ";"-separated +/// entries are compared as a multiset via . +/// +public static class Diff +{ + public static FixtureDiff Compare(List expected, List actual) + { + var diff = new FixtureDiff(); + Dictionary> expByWord = GroupByWord(expected); + Dictionary> actByWord = GroupByWord(actual); + + IEnumerable allWords = expByWord + .Keys.Union(actByWord.Keys, StringComparer.Ordinal) + .OrderBy(w => w, StringComparer.Ordinal); + + foreach (string word in allWords) + { + bool hasExpected = expByWord.TryGetValue(word, out List expRows); + bool hasActual = actByWord.TryGetValue(word, out List actRows); + + if (!hasExpected) + { + diff.WordResults.Add( + new WordResult + { + Word = word, + Passed = false, + Detail = "present in adapter output but not in expected.tsv", + } + ); + continue; + } + if (!hasActual) + { + diff.WordResults.Add( + new WordResult + { + Word = word, + Passed = false, + Detail = "missing from adapter/self-check output", + } + ); + continue; + } + + List expCanon = Canonicalize(expRows); + List actCanon = Canonicalize(actRows); + bool passed = expCanon.SequenceEqual(actCanon, StringComparer.Ordinal); + diff.WordResults.Add( + new WordResult + { + Word = word, + Passed = passed, + Detail = passed + ? "ok" + : $"expected [{string.Join(" | ", expCanon)}] got [{string.Join(" | ", actCanon)}]", + } + ); + } + + return diff; + } + + private static Dictionary> GroupByWord(List rows) + { + var byWord = new Dictionary>(); + foreach (TsvRow row in rows) + { + if (!byWord.TryGetValue(row.Word, out List list)) + { + list = new List(); + byWord[row.Word] = list; + } + list.Add(row); + } + return byWord; + } + + // One canonical "status|sorted-signature-entries" string per row, sorted across the word's + // rows (usually just one) so occurrence order/duplication is handled as a multiset. + private static List Canonicalize(List rows) + { + return rows.Select(r => r.Status + "|" + string.Join(";", SignatureTsv.SplitSignature(r.Signature))) + .OrderBy(s => s, StringComparer.Ordinal) + .ToList(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/EngineCrashException.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/EngineCrashException.cs new file mode 100644 index 000000000..604d3941c --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/EngineCrashException.cs @@ -0,0 +1,21 @@ +using System; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Thrown by an when the ENGINE UNDER TEST itself failed while loading a +/// grammar or parsing a word -- a genuine engine crash, as opposed to a harness-level failure +/// (the adapter process couldn't be started, timed out, or exited 0 without producing an output +/// file; see ). treats this exception specially: a +/// fixture whose manifest declares expectCrash: true (see ) +/// PASSes when this is thrown instead of the normal signature diff; any other fixture FAILs, +/// showing the carried diagnostics. +/// +public class EngineCrashException : Exception +{ + public EngineCrashException(string message) + : base(message) { } + + public EngineCrashException(string message, Exception innerException) + : base(message, innerException) { } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/FailureRuleAttributor.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/FailureRuleAttributor.cs new file mode 100644 index 000000000..78793903b --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/FailureRuleAttributor.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using SIL.Machine.Morphology.HermitCrab.MorphologicalRules; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Failure-side counterpart to : for one EXPECT_FAIL word already +/// confirmed elsewhere (self-check's own signature comparison) to have zero total parses, extracts +/// the grammar rule ids a real engine trace shows were EVALUATED AND REJECTED -- or blocked after +/// applying -- while reaching that result. This upgrades a hand-written blocked_by label from +/// asserted to VERIFIED, the same standard a crash-attributed rule is held to elsewhere in the +/// coverage report. +/// +/// Two trace shapes are used, both inherently self-limiting rather than filtered by +/// value: +/// +/// A node (Word.CheckBlocking substituted a suppletive +/// family partner) can only ever appear AFTER the rule already applied successfully to build that +/// specific candidate -- it cannot fire for a rule that was never in scope for this word, so it +/// carries rule identity directly on with no risk of blanket noise. +/// A node whose resolves to +/// an is likewise self-limiting: Environments/ +/// AllomorphCoOccurrenceRules/MorphemeCoOccurrenceRules are checked in +/// Morpher.IsWordValid only against allomorphs that are ALREADY PART OF a fully-synthesized +/// final candidate, so the rule that owns the allomorph ( -- an +/// / is itself a +/// ) genuinely did apply to build that candidate, not merely get tried. +/// +/// +/// Deliberately NOT used: a / +/// / +/// NotApplied node's , for ANY reason value, not just the +/// MPR-feature family. Confirmed empirically across this suite's own fixtures: a rule reached at +/// all during a linear/unordered stratum's search gets tried against candidates it has nothing to do +/// with, and / +/// alike fire routinely in that "not in scope for this candidate" sense (ordinary +/// requiredPartsOfSpeech gating on a phonological subrule compiles to the same +/// RequiredSyntacticFeatureStruct reason a genuine per-word feature CONFLICT does) -- there is no +/// FailureReason value that reliably separates "this candidate specifically conflicts with the rule" +/// from "the rule doesn't apply here, as it structurally never would." Widening on either produced +/// real, wrong cross-fixture attributions in testing (e.g. an unrelated word crediting a phonological +/// rule several constructs away). One target rule's one word (rrRRealTest/zimed, a genuine +/// RequiredSyntacticFeatureStruct conflict) is therefore left label-only rather than verified this +/// way -- see the class's own investigation notes for why: the rule ITSELF still verifies (its +/// sibling word zamed hits the Blocked case above), so the dead-rule/label-only gate is unaffected, +/// but this one word's own claim stays unverified. Under-attributing here is the safe direction. +/// +/// A phonological rule's own is reconstructed, +/// not read off one node: the rule that mutates a confirming-synthesis candidate away from the +/// input surface fires as an ordinary Applied node (the RULE succeeded; it is the WORD that then +/// fails to match) -- so an Applied node is only +/// attributed when the SAME WORD's own trace tree (a fresh ParseWord call per word, never +/// shared) also contains a top-level node carrying +/// , tying the rule to the specific failure mode its +/// own mechanism produces. +/// +/// What this cannot reach at all: and +/// are raised against a +/// -- a lexical entry's own allomorph, e.g. a free-variation pair sharing one +/// -- whose Morpheme identifies only the shared morpheme, not which of its several allomorphs +/// failed; the runtime object never retains its grammar.xml id +/// attribute at all (unlike ). No verified channel exists for that case +/// without adding the missing id -- see 's own doc comment for the +/// analogous, already-documented loss for four other rule kinds. +/// +public static class FailureRuleAttributor +{ + public static HashSet WordLevelFailureRuleIds(object trace, GrammarRuleIndex index) + { + var ids = new HashSet(StringComparer.Ordinal); + if (trace is not Trace root) + return ids; + + bool surfaceFormMismatch = HasSurfaceFormMismatch(root); + Walk(root); + return ids; + + void Walk(Trace node) + { + switch (node.Type) + { + case TraceType.Blocked: + AddMorphological(node.Source); + break; + case TraceType.PhonologicalRuleSynthesis: + if (node.FailureReason == FailureReason.None && surfaceFormMismatch) + AddPhonological(node.Source); + break; + case TraceType.Failed: + if ( + node.FailureAllomorph is AffixProcessAllomorph affixAllo + && affixAllo.Morpheme is IMorphologicalRule mrule + ) + { + AddMorphological(mrule); + } + break; + } + foreach (Trace child in node.Children) + Walk(child); + } + + void AddMorphological(IHCRule source) + { + if (source is not IMorphologicalRule mrule) + return; + string id = index.ResolveMorphologicalRuleId(mrule); + if (id != null) + ids.Add(id); + } + + void AddPhonological(IHCRule source) + { + if (source is not IPhonologicalRule prule) + return; + string id = index.ResolvePhonologicalRuleId(prule); + if (id != null) + ids.Add(id); + } + } + + private static bool HasSurfaceFormMismatch(Trace node) + { + if (node.Type == TraceType.Failed && node.FailureReason == FailureReason.SurfaceFormMismatch) + return true; + foreach (Trace child in node.Children) + { + if (HasSurfaceFormMismatch(child)) + return true; + } + return false; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/Fixture.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Fixture.cs new file mode 100644 index 000000000..a60dd0c8f --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Fixture.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.IO; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// One fixture directory: exactly grammar.xml + words.yaml, under +/// conformance/languages/<name>/ or conformance/edge-cases/<name>/. +/// +public class Fixture(string id, string directory, WordsYaml words) +{ + public string Id { get; } = id; + public string Directory { get; } = directory; + public WordsYaml Words { get; } = words; + + public string GrammarPath => Path.Combine(Directory, "grammar.xml"); + + public static List DiscoverAll(string fixturesRoot) + { + var fixtures = new List(); + foreach (string category in new[] { "languages", "edge-cases" }) + { + string categoryRoot = Path.Combine(fixturesRoot, category); + if (!System.IO.Directory.Exists(categoryRoot)) + continue; + + foreach (string dir in System.IO.Directory.EnumerateDirectories(categoryRoot)) + { + string grammarPath = Path.Combine(dir, "grammar.xml"); + string wordsYamlPath = Path.Combine(dir, "words.yaml"); + if (!File.Exists(grammarPath) || !File.Exists(wordsYamlPath)) + continue; + + string name = Path.GetFileName(dir); + string id = $"{category}/{name}"; + WordsYaml words = WordsYamlLoader.Load(wordsYamlPath); + fixtures.Add(new Fixture(id, dir, words)); + } + } + fixtures.Sort((a, b) => string.CompareOrdinal(a.Id, b.Id)); + return fixtures; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/FixtureManifest.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/FixtureManifest.cs new file mode 100644 index 000000000..478d119a8 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/FixtureManifest.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// In-memory adapter-mode fixture descriptor, built by from a +/// fixture's grammar.xml + words.yaml. is retained on each +/// field only because is a raw ; nothing in this +/// codebase deserializes a FixtureManifest from JSON on disk. +/// +public class FixtureManifest +{ + [JsonPropertyName("id")] + public string Id { get; set; } = ""; + + [JsonPropertyName("category")] + public string Category { get; set; } = "single-feature"; + + [JsonPropertyName("constructs")] + public List Constructs { get; set; } = new(); + + [JsonPropertyName("tags")] + public List Tags { get; set; } = new(); + + [JsonPropertyName("requires")] + public List Requires { get; set; } = new(); + + // Nullable so Runner can distinguish "field absent" (bool default false would look identical + // to an explicit "false") from an explicit value to cross-check against Category above. + [JsonPropertyName("pathological")] + public bool? Pathological { get; set; } + + [JsonPropertyName("expectCrash")] + public bool ExpectCrash { get; set; } + + [JsonPropertyName("budget")] + public FixtureBudget Budget { get; set; } + + [JsonPropertyName("oracle")] + public JsonElement Oracle { get; set; } + + [JsonPropertyName("provenance")] + public string Provenance { get; set; } = ""; +} + +/// +/// A pathological fixture's complexity budget: a wall-clock bound only (no step-count ceiling +/// exists on this branch -- see conformance framework plan notes on BatchCommand's stripped +/// --rule-stats option). Absent/null for non-pathological fixtures. +/// +public class FixtureBudget +{ + [JsonPropertyName("wallClockMs")] + public long WallClockMs { get; set; } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/FixtureMaterializer.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/FixtureMaterializer.cs new file mode 100644 index 000000000..7bff6087f --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/FixtureMaterializer.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Materializes a fixture (grammar.xml + words.yaml) into the on-disk adapter shape +/// (grammar.xml + words.txt + expected.tsv) in a temp directory, plus an in-memory +/// , so it can be run through + +/// for adapter mode without either needing to know about the +/// words.yaml format. This is the only code path that touches AdapterEngine/MaterializedRunner. +/// +public static class FixtureMaterializer +{ + /// + /// Builds the temp directory and returns a pointing at it. + /// Caller owns cleanup (delete the returned fixture's + /// when done). + /// + public static MaterializedFixture Materialize(Fixture fixture) + { + string tempDir = Path.Combine(Path.GetTempPath(), "hc-conformance-" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(tempDir); + + File.Copy(fixture.GrammarPath, Path.Combine(tempDir, "grammar.xml")); + + // Words with any guess:true parse are self-check-only (PROTOCOL.md section 3: BatchCommand + // has no guessRoot opt-in, so no contract-compliant adapter can ever produce a guess parse) + // and are omitted from adapter materialization entirely rather than materialized with + // expectations no adapter can meet. + var adapterWords = fixture.Words.Words.Where(w => w.Parses.All(p => !p.Guess)).ToList(); + + string wordsPath = Path.Combine(tempDir, "words.txt"); + File.WriteAllLines(wordsPath, adapterWords.Select(w => w.Word)); + + string expectedPath = Path.Combine(tempDir, "expected.tsv"); + using (var writer = new StreamWriter(expectedPath)) + { + if (fixture.Words.ExpectCrash) + { + // See conformance/PROTOCOL.md's "STARTED sentinel" section: only the STARTED + // sentinel for the one word that crashes the oracle, no real result row -- + // MaterializedRunner never reads this content for an expectCrash fixture (its + // crash-handling catch block bypasses the diff entirely), but + // SignatureTsv.ReadFile still needs *a* file to exist. + WordEntry first = fixture.Words.Words[0]; + writer.WriteLine($"0\t{first.Word}\tSTARTED"); + } + else + { + int i = 0; + foreach (WordEntry word in adapterWords) + { + string signature = BuildExpectedSignature(word); + // expect_skip words carry status "SKIPPED" (the oracle throws InvalidShapeException), + // matching the expected.tsv row shape "N word 0 SKIPPED -"; everything else is "ok". + string status = word.ExpectSkip ? "SKIPPED" : "ok"; + writer.WriteLine($"{i}\t{word.Word}\t0\t{status}\t{signature}"); + i++; + } + } + } + + var manifest = new FixtureManifest + { + Id = fixture.Id, + Category = fixture.Words.BudgetMs.HasValue ? "pathological" : "single-feature", + Requires = fixture.Words.Requires, + ExpectCrash = fixture.Words.ExpectCrash, + Budget = fixture.Words.BudgetMs.HasValue + ? new FixtureBudget { WallClockMs = fixture.Words.BudgetMs.Value } + : null, + Provenance = string.Join( + "; ", + fixture.Words.Words.Where(w => !string.IsNullOrEmpty(w.Provenance)).Select(w => w.Provenance) + ), + }; + + return new MaterializedFixture(tempDir, manifest); + } + + public static void Cleanup(MaterializedFixture materialized) + { + try + { + if (Directory.Exists(materialized.Directory)) + Directory.Delete(materialized.Directory, recursive: true); + } + catch (IOException) { } + } + + /// The signature string materialized into expected.tsv column 5: "-" for a word with zero expected + /// parses (expect_fail), else the ";"-joined, ordinally-sorted set of parses[].signature -- the same shape + /// BatchCommand.BuildSignature itself produces. + public static string BuildExpectedSignature(WordEntry word) + { + if (word.ExpectFail || word.ExpectSkip || word.Parses.Count == 0) + return "-"; + return string.Join(";", word.Parses.Select(p => p.Signature).OrderBy(s => s, StringComparer.Ordinal)); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/GrammarRuleIndex.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/GrammarRuleIndex.cs new file mode 100644 index 000000000..668d405ac --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/GrammarRuleIndex.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Independently re-parses a fixture's grammar.xml (not via , +/// whose runtime rule objects lose the XML id attribute for several rule kinds -- see below) +/// to answer two questions the harness needs for the "rules:" coverage dimension: (1) every rule id +/// the grammar declares (for dead-rule detection), and (2) how to translate a *runtime* rule +/// identity (what or a node's +/// Source actually expose at parse time) back to that XML id attribute, so a traced +/// rule application can be compared against a words.yaml "rules:" entry. +/// +/// Why this indirection is needed (see XmlLanguageLoader.TryLoadAffixProcessRule / +/// TryLoadCompoundingRule / LoadRewriteRule / LoadMetathesisRule): the XML +/// id attribute on a MorphologicalRule/RealizationalRule element is used only +/// as the loader's own lookup key while building the graph -- the *runtime* +/// object's is loaded from the separate <MorphemeId> child +/// element instead (the short code that appears in a parse's morph-chain signature, e.g. "PL"). +/// A CompoundingRule, PhonologicalRule, and MetathesisRule element has no +/// MorphemeId at all; their runtime objects expose only (from the +/// element's <Name> child). None of the four runtime rule kinds retains the XML +/// id attribute itself anywhere the harness can read it back after loading. This class +/// rebuilds that lost mapping straight from the XML. +/// +/// +/// answers a third, related question: given an XML element that +/// is not itself a rule element (Allomorph, MorphologicalInput, AffixTemplate, +/// PhonologicalSubrule), which rule -- if any -- it belongs to, by walking up the tree rather +/// than through a runtime object at all. +/// +/// +public class GrammarRuleIndex +{ + /// Every rule id declared by the grammar (MorphologicalRule/RealizationalRule/CompoundingRule/ + /// PhonologicalRule/MetathesisRule ids, plus the co-occurrence-rule pseudo-ids below), in document + /// order. + public List AllRuleIds { get; } = new(); + + // MorphemeId text -> XML id attribute, for MorphologicalRule/RealizationalRule (AffixProcessRule + // /RealizationalAffixProcessRule at runtime): these are the only two kinds whose runtime object + // exposes a stable per-morpheme string (Morpheme.Id) that this class can translate back. + private readonly Dictionary _ruleIdByMorphemeId = new(StringComparer.Ordinal); + + // text -> XML id attribute, for CompoundingRule/PhonologicalRule/MetathesisRule: the only + // identity these three retain at runtime is IHCRule.Name. + private readonly Dictionary _ruleIdByRuleName = new(StringComparer.Ordinal); + + /// + /// MorphemeCoOccurrenceRule/AllomorphCoOccurrenceRule elements are EMPTY per the DTD -- they + /// have no id attribute of their own at all, only primaryMorpheme/ + /// primaryAllomorph IDREFs. This harness's convention (documented here -- it is + /// coverage/dead-rule bookkeeping, internal to the harness, not part of PROTOCOL.md's wire + /// adapter contract) is: such a rule's "rule id", for both + /// blocked_by and dead-rule detection purposes, IS the referenced primary morpheme/ + /// allomorph id. is that set, so dead-rule detection can + /// tell a real dead co-occurrence rule from an id that was never declared at all. + /// + public HashSet CoOccurrencePseudoIds { get; } = new(StringComparer.Ordinal); + + public static GrammarRuleIndex Load(string grammarPath) + { + var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }; + using XmlReader reader = XmlReader.Create(grammarPath, settings); + XDocument doc = XDocument.Load(reader); + + var index = new GrammarRuleIndex(); + foreach (XElement el in doc.Descendants()) + { + switch (el.Name.LocalName) + { + case "MorphologicalRule": + case "RealizationalRule": + { + string id = (string)el.Attribute("id"); + string morphemeId = (string)el.Element("MorphemeId"); + if (id == null) + continue; + index.AllRuleIds.Add(id); + if (morphemeId != null) + { + index._ruleIdByMorphemeId[morphemeId] = id; + } + else + { + // Conservative fallback for a MorphologicalRule/RealizationalRule with no + // child at all (Morpheme.Id then null, so the morpheme-id path + // above can never resolve it) -- register its text the same way + // CompoundingRule/PhonologicalRule/MetathesisRule already are below, but only + // in this no-MorphemeId case, so every existing grammar (which assigns + // MorphemeId to every rule) is byte-for-byte unaffected: this dict only ever + // gains an entry when the morpheme-id path was never going to work anyway. + // Discovered authoring edge-cases/disjunctive-recheck + edge-cases/strrep- + // identity (both assign no MorphemeId at all, a deliberate choice -- adding + // one would change the "+|wokta"-style signatures those fixtures pin) -- see + // those fixtures' words.yaml headers. + string name = (string)el.Element("Name"); + if (name != null) + index._ruleIdByRuleName[name] = id; + } + break; + } + case "CompoundingRule": + case "PhonologicalRule": + case "MetathesisRule": + { + string id = (string)el.Attribute("id"); + string name = (string)el.Element("Name"); + if (id == null) + continue; + index.AllRuleIds.Add(id); + if (name != null) + index._ruleIdByRuleName[name] = id; + break; + } + case "MorphemeCoOccurrenceRule": + case "AllomorphCoOccurrenceRule": + { + string primary = (string)(el.Attribute("primaryMorpheme") ?? el.Attribute("primaryAllomorph")); + if (primary == null) + continue; + index.AllRuleIds.Add(primary); + index.CoOccurrencePseudoIds.Add(primary); + break; + } + } + } + return index; + } + + /// + /// Translates a fired (from , + /// or a RealizationalAffixProcessRule taken from a MorphologicalRuleSynthesis trace node -- see + /// ) back to its grammar.xml rule id. Returns null (rather than + /// throwing) for a rule kind this index cannot attribute. + /// + public string ResolveMorphologicalRuleId(IMorphologicalRule rule) + { + if ( + rule is Morpheme morpheme + && morpheme.Id != null + && _ruleIdByMorphemeId.TryGetValue(morpheme.Id, out string byMorphemeId) + ) + { + return byMorphemeId; + } + if (rule.Name != null && _ruleIdByRuleName.TryGetValue(rule.Name, out string byName)) + return byName; + return null; + } + + /// Translates a fired phonological rule (from a trace node's Source) back to its grammar.xml + /// rule id, by IHCRule.Name -- see the class doc comment. + public string ResolvePhonologicalRuleId(IPhonologicalRule rule) + { + return rule.Name != null && _ruleIdByRuleName.TryGetValue(rule.Name, out string id) ? id : null; + } + + /// Element names that carry a rule's own id attribute directly -- see the class doc + /// comment. + private static readonly HashSet RuleElementNames = new(StringComparer.Ordinal) + { + "MorphologicalRule", + "RealizationalRule", + "CompoundingRule", + "PhonologicalRule", + "MetathesisRule", + }; + + /// + /// Resolves an element that is not itself a rule element -- Allomorph, + /// MorphologicalInput, AffixTemplate, PhonologicalSubrule -- to the id + /// of its nearest rule-element ancestor, by walking up 's own XML tree. + /// Per the DTD, MorphologicalInput is always nested under a MorphologicalRule/ + /// RealizationalRule and PhonologicalSubrule always under a PhonologicalRule, + /// so those two kinds always resolve. Returns null -- never a guessed id -- when no rule-element + /// ancestor exists at all: an + /// Allomorph is always a child of LexicalEntry, never of a rule, and an + /// AffixTemplate is a direct child of Stratum with no id attribute of its own + /// either (the DTD never declares one), so it has no identity to attribute to at all. + /// + public static string ResolveAncestorRuleId(XElement element) + { + ArgumentNullException.ThrowIfNull(element); + foreach (XElement ancestor in element.Ancestors()) + { + if (RuleElementNames.Contains(ancestor.Name.LocalName)) + return (string)ancestor.Attribute("id"); + } + return null; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/IEngine.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/IEngine.cs new file mode 100644 index 000000000..69902bad1 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/IEngine.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Something that can produce batch-TSV rows for a fixture: either the live C# oracle running +/// in-process () or an external adapter process +/// (), per conformance/PROTOCOL.md. +/// +public interface IEngine +{ + /// A short, human-readable name for reporting (e.g. "self-check", "adapter"). + string Name { get; } + + /// + /// The capability set this engine declares support for. Self-check mode always reports the + /// full set (it IS the reference C# oracle); an adapter's set comes from the --capabilities + /// flag. + /// + IReadOnlySet Capabilities { get; } + + /// Runs every word in the fixture's words.txt, returning the resulting TSV rows. + List Run(MaterializedFixture fixture); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/MaterializedFixture.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/MaterializedFixture.cs new file mode 100644 index 000000000..9e61ab030 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/MaterializedFixture.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// A fixture materialized onto disk in the on-disk adapter shape (grammar.xml + words.txt + +/// expected.tsv + an in-memory ), so it can be handed to +/// and (self-check or an external adapter +/// process). Built by from a . +/// +public class MaterializedFixture(string directory, FixtureManifest manifest) +{ + public string Id { get; } = manifest.Id; + public string Directory { get; } = directory; + public FixtureManifest Manifest { get; } = manifest; + + public string GrammarPath => Path.Combine(Directory, "grammar.xml"); + public string WordsPath => Path.Combine(Directory, "words.txt"); + public string ExpectedPath => Path.Combine(Directory, "expected.tsv"); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/MaterializedRunner.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/MaterializedRunner.cs new file mode 100644 index 000000000..297f9fb44 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/MaterializedRunner.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +public enum FixtureOutcome +{ + Passed, + Failed, + Skipped, +} + +public class FixtureResult +{ + public string FixtureId = ""; + public FixtureOutcome Outcome; + public string Reason = ""; + public long ElapsedMs; + public List WordResults = new(); +} + +public class MaterializedRunReport +{ + public List Results { get; } = new(); + public int ExcludedPathologicalCount { get; set; } + + public int Passed => Results.Count(r => r.Outcome == FixtureOutcome.Passed); + public int Failed => Results.Count(r => r.Outcome == FixtureOutcome.Failed); + public int Skipped => Results.Count(r => r.Outcome == FixtureOutcome.Skipped); +} + +/// +/// Runs a list of s through an , applying +/// category exclusion (pathological) and capability filtering (manifest "requires" vs. the engine's +/// declared capabilities), and diffs results against each fixture's expected.tsv. Called by +/// against fixtures writes to disk. +/// +public static class MaterializedRunner +{ + public static MaterializedRunReport Run( + List fixtures, + IEngine engine, + bool includePathological + ) + { + var report = new MaterializedRunReport(); + + foreach (MaterializedFixture fixture in fixtures) + { + // category:pathological is the authoritative signal (the only thing docs ever mention); + // the manifest's own "pathological" boolean is redundant and, if present, must agree + // with it -- a mismatch is a manifest bug, not a runtime condition to silently resolve. + bool isPathological = fixture.Manifest.Category == "pathological"; + var result = new FixtureResult { FixtureId = fixture.Id }; + if (fixture.Manifest.Pathological.HasValue && fixture.Manifest.Pathological.Value != isPathological) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = + $"manifest error: pathological={fixture.Manifest.Pathological.Value.ToString().ToLowerInvariant()} " + + $"disagrees with category '{fixture.Manifest.Category}'"; + report.Results.Add(result); + continue; + } + + if (isPathological && !includePathological) + { + report.ExcludedPathologicalCount++; + continue; + } + + // manifest.requires must mechanically match what grammar.xml actually contains (see + // PROTOCOL.md section 5 / RequiresDerivation) -- a hand-authored drift here is a + // manifest bug, caught the same way the pathological/category mismatch above is. + List derivedRequires = RequiresDerivation.Derive(fixture.GrammarPath); + if ( + !new HashSet(derivedRequires, StringComparer.Ordinal).SetEquals( + new HashSet(fixture.Manifest.Requires, StringComparer.Ordinal) + ) + ) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = + $"manifest error: requires [{string.Join(",", fixture.Manifest.Requires)}] does not match " + + $"grammar-derived [{string.Join(",", derivedRequires)}]"; + report.Results.Add(result); + continue; + } + + List missingCapabilities = fixture + .Manifest.Requires.Where(req => !engine.Capabilities.Contains(req)) + .ToList(); + if (missingCapabilities.Count > 0) + { + result.Outcome = FixtureOutcome.Skipped; + result.Reason = + $"requires [{string.Join(",", fixture.Manifest.Requires)}], " + + $"engine declares [{string.Join(",", engine.Capabilities.OrderBy(c => c))}]; " + + $"missing [{string.Join(",", missingCapabilities)}]"; + report.Results.Add(result); + continue; + } + + // Read once, before the try: the old code re-read expected.tsv from inside the catch + // block too, so a genuinely missing file could throw from inside exception handling. + List expected = SignatureTsv.ReadFile(fixture.ExpectedPath); + + var sw = Stopwatch.StartNew(); + try + { + List actual = RunWithBudget(engine, fixture); + sw.Stop(); + result.ElapsedMs = sw.ElapsedMilliseconds; + + // A handful of fixtures deliberately pin a CRASH as their ground truth (e.g. + // rewrite/simultaneous-epenthesis-cascade's InfiniteLoopException): the manifest + // says so explicitly (expectCrash: true) rather than the harness inferring it from + // an empty expected.tsv. If the engine returns normally here, it did not reproduce + // that crash, which is itself a conformance failure. + if (fixture.Manifest.ExpectCrash) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = "expected crash, engine produced output"; + } + else + { + FixtureDiff diff = Diff.Compare(expected, actual); + result.WordResults = diff.WordResults; + + // Enforced whenever a budget is present, regardless of category: today only + // pathological fixtures carry one, but nothing about the check is category- + // specific. + bool overBudget = + fixture.Manifest.Budget != null && result.ElapsedMs > fixture.Manifest.Budget.WallClockMs; + + if (overBudget) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = + $"exceeded wall-clock budget ({result.ElapsedMs}ms > {fixture.Manifest.Budget.WallClockMs}ms)"; + } + else if (diff.AllPassed) + { + result.Outcome = FixtureOutcome.Passed; + } + else + { + result.Outcome = FixtureOutcome.Failed; + // Name the words. A bare count cannot be diagnosed from a CI log on a machine you cannot reach. + + WordResult[] mismatched = diff.WordResults.Where(word => !word.Passed).ToArray(); + + string named = string.Join( + "; ", + mismatched.Take(5).Select(word => $"{word.Word}: {Truncate(word.Detail)}") + ); + + result.Reason = + mismatched.Length > 5 + ? $"{mismatched.Length}/{ +diff.WordResults +.Count} word(s) mismatched: {named}; and {mismatched.Length - 5} more" + : $"{mismatched.Length}/{ +diff.WordResults +.Count} word(s) mismatched: {named}"; + } + } + } + catch (EngineCrashException ex) + { + sw.Stop(); + result.ElapsedMs = sw.ElapsedMilliseconds; + + if (fixture.Manifest.ExpectCrash) + { + result.Outcome = FixtureOutcome.Passed; + result.Reason = $"engine crashed as expected (manifest expectCrash: true): {ex.Message}"; + } + else + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = $"engine crashed: {ex.Message}"; + } + } + catch (TimeoutException ex) when (fixture.Manifest.Budget != null) + { + sw.Stop(); + result.ElapsedMs = sw.ElapsedMilliseconds; + + result.Outcome = FixtureOutcome.Failed; + result.Reason = $"exceeded budget {fixture.Manifest.Budget.WallClockMs}ms: {ex.Message}"; + } + catch (Exception ex) + { + sw.Stop(); + result.ElapsedMs = sw.ElapsedMilliseconds; + + // Any other exception is a plain harness error (bad --adapter template, process + // couldn't start, timed out, etc.) -- never a pass, regardless of expectCrash. + result.Outcome = FixtureOutcome.Failed; + result.Reason = $"harness error: {ex.Message}"; + } + + report.Results.Add(result); + } + + return report; + } + + /// + /// Runs the engine for one fixture. If the manifest carries a budget, engine.Run happens on a + /// background thread and this waits up to budget + a small margin; AdapterEngine independently + /// plumbs the same budget into its own process timeout (so a subprocess adapter gets killed), + /// but self-check's in-process call has no external process to kill, so this watchdog is what + /// keeps a runaway self-check parse from hanging the whole harness run. If the watchdog expires, + /// a TimeoutException is thrown and the background thread is simply abandoned -- this is a + /// short-lived CLI, so a leaked runaway thread on the rare budget-blown fixture is an acceptable + /// trade for keeping this shape simple. + /// + private static List RunWithBudget(IEngine engine, MaterializedFixture fixture) + { + FixtureBudget budget = fixture.Manifest.Budget; + if (budget == null) + return engine.Run(fixture); + + Task> task = Task.Run(() => engine.Run(fixture)); + long marginMs = Math.Max(budget.WallClockMs / 5, 1000); + bool completed; + try + { + completed = task.Wait((int)(budget.WallClockMs + marginMs)); + } + catch (AggregateException ex) when (ex.InnerException != null) + { + // Unwrap: rethrow the engine's own exception so the caller's EngineCrashException/ + // generic catch blocks see the real exception type, not Task's wrapper. + throw ex.InnerException; + } + if (!completed) + throw new TimeoutException("watchdog timed out waiting for engine.Run"); + return task.GetAwaiter().GetResult(); + } + + /// Shortens a per-word detail so a fixture reason stays readable in a log. + /// The word detail, which may carry every expected and actual parse. + private static string Truncate(string detail) + { + const int Limit = 160; + if (string.IsNullOrEmpty(detail) || detail.Length <= Limit) + { + return detail; + } + + return detail[..Limit] + "..."; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/Program.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Program.cs new file mode 100644 index 000000000..2c03de3c6 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Program.cs @@ -0,0 +1,1628 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +internal class Program +{ + private static int Main(string[] args) + { + string fixturesRoot = null; + string adapterTemplate = null; + string capabilitiesArg = null; + bool capabilitiesProvided = false; + bool includePathological = false; + bool coverageReport = false; + string constructsPath = null; + bool propose = false; + bool semanticCoverage = false; + bool writeCoverageBaseline = false; + bool proposeSemanticCatalog = false; + bool generateManifest = false; + bool checkManifest = false; + var proposedAuditedScopes = new List(); + bool counterfactual = false; + string mutantGrammar = null; + string mutantWords = null; + bool writeCounterfactual = false; + bool coverageEvidence = false; + bool writeCoverageEvidence = false; + bool ruleInteractionPairs = false; + bool writeRuleInteractionPairs = false; + bool interfaceInventory = false; + bool writeInterfaceInventory = false; + bool interactionChains = false; + bool writeInteractionChains = false; + bool dataflowObligations = false; + bool writeDataflowObligations = false; + bool coverageTraceability = false; + bool writeCoverageTraceability = false; + bool evidenceCards = false; + bool writeEvidenceCards = false; + bool engineGateInventory = false; + bool writeEngineGateInventory = false; + bool gateObligations = false; + bool writeGateObligations = false; + string repositoryRoot = null; + + for (int i = 0; i < args.Length; i++) + { + switch (args[i]) + { + case "--fixtures": + if (!TryGetNextArg(args, ref i, "--fixtures", out fixturesRoot)) + return 2; + break; + case "--adapter": + if (!TryGetNextArg(args, ref i, "--adapter", out adapterTemplate)) + return 2; + break; + case "--capabilities": + if (!TryGetNextArg(args, ref i, "--capabilities", out capabilitiesArg)) + return 2; + capabilitiesProvided = true; + break; + case "--include-pathological": + includePathological = true; + break; + case "--coverage-report": + coverageReport = true; + break; + case "--constructs": + if (!TryGetNextArg(args, ref i, "--constructs", out constructsPath)) + return 2; + break; + case "--propose": + propose = true; + break; + case "--semantic-coverage": + semanticCoverage = true; + break; + case "--write-coverage-baseline": + writeCoverageBaseline = true; + break; + case "--evaluate-mutant": + if (!TryGetNextArg(args, ref i, "--evaluate-mutant", out mutantGrammar)) + return 2; + if (!TryGetNextArg(args, ref i, "--evaluate-mutant", out mutantWords)) + return 2; + break; + case "--counterfactual": + counterfactual = true; + break; + case "--write-counterfactual": + writeCounterfactual = true; + break; + case "--coverage-evidence": + coverageEvidence = true; + break; + case "--write-coverage-evidence": + writeCoverageEvidence = true; + break; + case "--rule-interaction-pairs": + ruleInteractionPairs = true; + break; + case "--write-rule-interaction-pairs": + writeRuleInteractionPairs = true; + break; + case "--interface-inventory": + interfaceInventory = true; + break; + case "--write-interface-inventory": + writeInterfaceInventory = true; + break; + case "--interaction-chains": + interactionChains = true; + break; + case "--write-interaction-chains": + writeInteractionChains = true; + break; + case "--dataflow-obligations": + dataflowObligations = true; + break; + case "--write-dataflow-obligations": + writeDataflowObligations = true; + break; + case "--coverage-traceability": + coverageTraceability = true; + break; + case "--write-coverage-traceability": + writeCoverageTraceability = true; + break; + case "--evidence-cards": + evidenceCards = true; + break; + case "--write-evidence-cards": + writeEvidenceCards = true; + break; + case "--engine-gate-inventory": + engineGateInventory = true; + break; + case "--write-engine-gate-inventory": + writeEngineGateInventory = true; + break; + case "--gate-obligations": + gateObligations = true; + break; + case "--write-gate-obligations": + writeGateObligations = true; + break; + case "--propose-semantic-catalog": + proposeSemanticCatalog = true; + break; + case "--generate-manifest": + generateManifest = true; + break; + case "--check-manifest": + checkManifest = true; + break; + case "--audited-source-scope": + if (!TryGetNextArg(args, ref i, "--audited-source-scope", out string proposedScope)) + return 2; + proposedAuditedScopes.Add(proposedScope); + break; + case "--repository-root": + if (!TryGetNextArg(args, ref i, "--repository-root", out repositoryRoot)) + return 2; + break; + case "-h": + case "--help": + PrintUsage(); + return 0; + default: + Console.Error.WriteLine($"unrecognized argument: {args[i]}"); + PrintUsage(); + return 2; + } + } + + // One mutant evaluation, in its own process so a non-terminating parse can be killed rather + // than abandoned; an abandoned in-process task keeps allocating for the life of the sweep. + if (mutantGrammar != null) + { + // Per-word timing goes to stderr, prefixed and distinct from the outcome lines on stdout, + // so a parent process can recover it without it ever contaminating a baseline diff. + IReadOnlyList outcomes = SemanticCoverage.CounterfactualGate.EvaluateOneGrammar( + mutantGrammar, + mutantWords, + onTimed: (word, elapsedMs) => Console.Error.WriteLine($"TIME\t{word}\t{elapsedMs}") + ); + foreach (string outcome in outcomes) + Console.Out.WriteLine(outcome); + + return 0; + } + + // Semantic coverage reads the DTD and every grammar.xml directly, so it needs a repository + // root rather than a discovered fixture set. + if ( + semanticCoverage + || writeCoverageBaseline + || proposeSemanticCatalog + || generateManifest + || checkManifest + || counterfactual + || writeCounterfactual + || coverageEvidence + || writeCoverageEvidence + || ruleInteractionPairs + || writeRuleInteractionPairs + || interfaceInventory + || writeInterfaceInventory + || interactionChains + || writeInteractionChains + || dataflowObligations + || writeDataflowObligations + || coverageTraceability + || writeCoverageTraceability + || evidenceCards + || writeEvidenceCards + || engineGateInventory + || writeEngineGateInventory + || gateObligations + || writeGateObligations + ) + { + repositoryRoot ??= FindRepositoryRoot(Directory.GetCurrentDirectory()); + if (repositoryRoot == null) + { + Console.Error.WriteLine("could not locate the repository root; pass --repository-root "); + return 2; + } + + try + { + if (generateManifest || checkManifest) + return RunConformanceManifest(repositoryRoot, generateManifest); + + if (coverageEvidence || writeCoverageEvidence) + return RunCoverageEvidence(repositoryRoot, writeCoverageEvidence); + + if (ruleInteractionPairs || writeRuleInteractionPairs) + return RunRuleInteractionPairs(repositoryRoot, writeRuleInteractionPairs); + + if (interfaceInventory || writeInterfaceInventory) + return RunInterfaceInventory(repositoryRoot, writeInterfaceInventory); + + if (interactionChains || writeInteractionChains) + return RunInteractionChains(repositoryRoot, writeInteractionChains); + if (dataflowObligations || writeDataflowObligations) + return RunDataflowObligations(repositoryRoot, writeDataflowObligations); + if (coverageTraceability || writeCoverageTraceability) + return RunCoverageTraceability(repositoryRoot, writeCoverageTraceability); + if (evidenceCards || writeEvidenceCards) + return RunEvidenceCards(repositoryRoot, writeEvidenceCards); + if (engineGateInventory || writeEngineGateInventory) + return RunEngineGateInventory(repositoryRoot, writeEngineGateInventory); + if (gateObligations || writeGateObligations) + return RunGateObligations(repositoryRoot, writeGateObligations); + + return counterfactual || writeCounterfactual + ? RunCounterfactual(repositoryRoot, writeCounterfactual) + : RunSemanticCoverage( + repositoryRoot, + writeCoverageBaseline, + proposeSemanticCatalog, + proposedAuditedScopes + ); + } + catch (Exception ex) + when (ex + is IOException + or UnauthorizedAccessException + or FormatException + or InvalidOperationException + or System.Xml.XmlException + or WordsYamlException + ) + { + Console.Error.WriteLine($"semantic coverage authority unavailable: {ex.Message}"); + return 2; + } + } + + if (string.IsNullOrEmpty(fixturesRoot)) + { + Console.Error.WriteLine("--fixtures is required"); + PrintUsage(); + return 2; + } + + List fixtures; + try + { + fixtures = Fixture.DiscoverAll(fixturesRoot); + } + catch (WordsYamlException ex) + { + Console.Error.WriteLine($"words.yaml error: {ex.Message}"); + return 2; + } + Console.WriteLine($"discovered {fixtures.Count} fixture(s) under '{fixturesRoot}'"); + + if (fixtures.Count == 0) + { + Console.Error.WriteLine($"no fixtures discovered under '{fixturesRoot}'"); + return 2; + } + + if (coverageReport) + { + constructsPath ??= Path.Combine(fixturesRoot, "constructs.txt"); + RunCoverageReport(fixtures, fixturesRoot, constructsPath); + return 0; + } + + IEngine engine; + if (adapterTemplate != null) + { + HashSet capabilities = ParseCapabilities(capabilitiesArg ?? ""); + engine = new AdapterEngine(adapterTemplate, capabilities); + } + else + { + // Self-check mode implies phonology support (it IS the reference engine) unless the + // caller explicitly overrides --capabilities, which is how the capability-filtering + // mechanism itself gets exercised without needing a second engine (see conformance + // framework verification notes). + IReadOnlySet capabilities = capabilitiesProvided ? ParseCapabilities(capabilitiesArg) : null; + engine = new SelfCheckEngine(capabilities); + } + + RunReport report = + adapterTemplate != null + ? Runner.RunAdapter(fixtures, engine, includePathological) + : Runner.RunSelfCheck(fixtures, includePathological, engine.Capabilities, propose, Console.Out); + PrintRunReport(report, engine); + + bool anyRan = report.Passed > 0 || report.Failed > 0; + if (!anyRan) + { + Console.Error.WriteLine("no fixtures actually ran (all excluded or skipped) -- treating this as an error"); + return 2; + } + + return report.Failed > 0 ? 1 : 0; + } + + private static string FindRepositoryRoot(string start) + { + for (string dir = start; dir != null; dir = Directory.GetParent(dir)?.FullName) + { + if (File.Exists(Path.Combine(dir, "conformance", "constructs.txt"))) + return dir; + } + + return null; + } + + private static int RunCounterfactual(string repositoryRoot, bool writeLedger) + { + SemanticCoverage.SemanticInventory inventory = SemanticCoverage.GrammarCoverageGate.ReadInventory( + repositoryRoot + ); + var timings = new List(); + var stopwatch = Stopwatch.StartNew(); + // A stalled surface is otherwise invisible until the whole sweep finishes, which is exactly + // the failure mode this gate exists to bound. + IReadOnlyList fresh = SemanticCoverage.CounterfactualLedger.Sweep( + repositoryRoot, + inventory, + (fixtureId, surfaceCount) => Console.Error.WriteLine($" {fixtureId} ({surfaceCount} surface(s))"), + timings.Add + ); + stopwatch.Stop(); + + foreach ( + SemanticCoverage.CounterfactualVerdict verdict in Enum.GetValues() + ) + { + Console.WriteLine($" {verdict, -15} {fresh.Count(r => r.Verdict == verdict)}"); + } + + PrintTimingReport(timings, stopwatch.Elapsed); + + // Read BEFORE writing: the verdict below reports whether the ledger checked in at the start + // of this run matches, and writing must never flip that to green within the same invocation + // -- otherwise regenerating silently absorbs a real regression, exactly as the coverage + // baseline gate's own header warns against. + IReadOnlyList checkedIn = SemanticCoverage.CounterfactualLedger.Read( + repositoryRoot + ); + var checkedInById = checkedIn.ToDictionary(entry => entry.SurfaceId, StringComparer.Ordinal); + var freshById = fresh.ToDictionary(entry => entry.SurfaceId, StringComparer.Ordinal); + + string[] added = freshById + .Keys.Except(checkedInById.Keys, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] removed = checkedInById + .Keys.Except(freshById.Keys, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] changed = freshById + .Keys.Intersect(checkedInById.Keys, StringComparer.Ordinal) + .Where(id => freshById[id] != checkedInById[id]) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + foreach (string id in added) + Console.Error.WriteLine($"NEW SURFACE {id}: {fresh.First(r => r.SurfaceId == id).Verdict}"); + foreach (string id in removed) + { + Console.Error.WriteLine( + $"GONE SURFACE {id} (delete from {SemanticCoverage.CounterfactualLedger.RelativePath})" + ); + } + foreach (string id in changed) + Console.Error.WriteLine($"CHANGED {id}: {checkedInById[id].Verdict} -> {freshById[id].Verdict}"); + + if (writeLedger) + { + SemanticCoverage.CounterfactualLedger.Write(repositoryRoot, fresh); + Console.WriteLine($"wrote {SemanticCoverage.CounterfactualLedger.RelativePath} ({fresh.Count} surfaces)"); + } + + // A surface must end as authoritative evidence or as an actually verified proof. The checked-in + // proof file is input to CoverageCompletenessGate, never a bypass around it. + IReadOnlyList proofs = SemanticCoverage.ImpossibilityProofs.Read( + repositoryRoot + ); + IReadOnlyList items = fresh + .Select(result => new SemanticCoverage.CoverageItem( + result.SurfaceId, + SemanticCoverage.CoverageItemKind.Surface, + result.SurfaceId.StartsWith(SemanticCoverage.GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal) + ? "dtd-enum" + : "dtd-element", + result.FixtureId + )) + .OrderBy(item => item.Id, StringComparer.Ordinal) + .ToArray(); + IReadOnlyList evidence = SemanticCoverage.CoverageEvidencePipeline.BuildEvidence( + fresh + ); + IReadOnlyList coverageProofs = proofs + .Select(proof => new SemanticCoverage.Proof(proof.SurfaceId, proof.Kind, proof.Evidence)) + .ToArray(); + SemanticCoverage.CompletenessReport completeness = SemanticCoverage.CoverageCompletenessGate.Evaluate( + items, + evidence, + coverageProofs + ); + IReadOnlyList staleProofs = SemanticCoverage.ImpossibilityProofs.Stale(fresh, proofs); + foreach ( + SemanticCoverage.CoverageResolutionResult item in completeness.Items.Where(result => + result.Resolution == SemanticCoverage.CoverageResolution.Unresolved + ) + ) + { + Console.Error.WriteLine($"UNACCOUNTED {item.ItemId}: {item.Detail}"); + } + foreach ( + SemanticCoverage.CoverageResolutionResult item in completeness.Items.Where(result => + result.Resolution == SemanticCoverage.CoverageResolution.Rejected + ) + ) + { + Console.Error.WriteLine($"REJECTED PROOF {item.ItemId}: {item.Detail}"); + } + foreach ( + SemanticCoverage.CoverageResolutionResult item in completeness.Items.Where(result => + result.Resolution == SemanticCoverage.CoverageResolution.Conflicting + ) + ) + { + Console.Error.WriteLine($"CONFLICT {item.ItemId}: {item.Detail}"); + } + foreach (string id in completeness.OrphanedProofItemIds) + { + Console.Error.WriteLine( + $"ORPHAN PROOF {id} (delete from {SemanticCoverage.ImpossibilityProofs.RelativePath})" + ); + } + foreach (string id in completeness.OrphanedEvidenceItemIds) + { + Console.Error.WriteLine( + $"ORPHAN EVIDENCE {id} (delete from {SemanticCoverage.EvidenceLedger.RelativePath})" + ); + } + + foreach (string id in staleProofs) + { + Console.Error.WriteLine( + $"STALE PROOF {id} (delete from {SemanticCoverage.ImpossibilityProofs.RelativePath})" + ); + } + + Console.WriteLine( + $" evidence: {completeness.Items.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Evidenced)}" + + $" proven impossible: {completeness.Items.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Proven)}" + + $" rejected proofs: {completeness.Items.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Rejected)}" + + $" conflicts: {completeness.Items.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Conflicting)}" + + $" orphan evidence: {completeness.OrphanedEvidenceItemIds.Count}" + + $" orphan proofs: {completeness.OrphanedProofItemIds.Count}" + + $" unaccounted: {completeness.Items.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Unresolved)}" + ); + + if ( + added.Length != 0 + || removed.Length != 0 + || changed.Length != 0 + || !completeness.IsComplete + || staleProofs.Count != 0 + ) + { + Console.Error.WriteLine( + $"counterfactual coverage findings: {added.Length} new, {removed.Length} gone, {changed.Length} changed, " + + $"{completeness.Items.Count(r => r.Resolution is SemanticCoverage.CoverageResolution.Unresolved or SemanticCoverage.CoverageResolution.Rejected)} unresolved/rejected, {staleProofs.Count} stale proof(s)" + ); + return 1; + } + + Console.WriteLine("every surface is evidenced or proven impossible"); + return 0; + } + + /// Generates the fixture manifest, or verifies the checked-in one byte for byte. + private static int RunConformanceManifest(string repositoryRoot, bool write) + { + string relative = "conformance/generated/hc-conformance-manifest.v1.json"; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + + SemanticCoverage.ConformanceManifest corpus = SemanticCoverage.ConformanceManifestGenerator.Generate( + repositoryRoot + ); + string dtd = Path.Combine( + repositoryRoot, + SemanticCoverage.GrammarCoverageGate.DtdRelativePath.Replace('/', Path.DirectorySeparatorChar) + ); + string wordsSchema = Path.Combine( + repositoryRoot, + SemanticCoverage.WordsSchemaValidation.SchemaRelativePath.Replace('/', Path.DirectorySeparatorChar) + ); + // Validate every fixture before anything is written, so a rejected one cannot leave a + // half-updated product behind. + foreach (SemanticCoverage.ManifestFixture fixture in corpus.Fixtures) + { + IReadOnlyList messages = SemanticCoverage.GrammarValidation.Validate( + Path.Combine(repositoryRoot, fixture.GrammarPath.Replace('/', Path.DirectorySeparatorChar)), + dtd + ); + if (messages.Count != 0) + { + Console.Error.WriteLine($"{fixture.FixtureId}: grammar does not validate against {corpus.DtdPath}"); + foreach (string message in messages) + Console.Error.WriteLine($" {message}"); + return 2; + } + + messages = SemanticCoverage.WordsSchemaValidation.Validate( + Path.Combine(repositoryRoot, fixture.WordsPath.Replace('/', Path.DirectorySeparatorChar)), + wordsSchema + ); + if (messages.Count == 0) + continue; + Console.Error.WriteLine( + $"{fixture.FixtureId}: words.yaml does not conform to {SemanticCoverage.WordsSchemaValidation.SchemaRelativePath}" + ); + foreach (string message in messages) + Console.Error.WriteLine($" {message}"); + return 2; + } + + string json = SemanticCoverage.ManifestJson.Serialize(corpus) + "\n"; + if (write) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + File.WriteAllText(path, json); + Console.WriteLine($"wrote {relative} ({corpus.Fixtures.Count} fixtures, sourceHash {corpus.SourceHash})"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --generate-manifest"); + return 1; + } + + if (!string.Equals(File.ReadAllText(path).ReplaceLineEndings("\n"), json, StringComparison.Ordinal)) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --generate-manifest"); + return 1; + } + + Console.WriteLine($"{relative} is current ({corpus.Fixtures.Count} fixtures)"); + return 0; + } + + /// Recomputes every fixture's rule-interaction denominator and checks it against the checked-in + /// ledger, or rewrites it. + private static int RunRuleInteractionPairs(string repositoryRoot, bool writeLedger) + { + var rows = new List(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + System.Xml.Linq.XDocument grammar = System.Xml.Linq.XDocument.Load(fixture.GrammarPath); + rows.AddRange(SemanticCoverage.RuleInteractionLedger.Compute(grammar, fixture.Id)); + } + + var byKind = rows.ToLookup(r => r.PairKind); + var byRelation = rows.ToLookup(r => r.Relation); + Console.WriteLine($"rule-interaction pairs: {rows.Count}"); + foreach (SemanticCoverage.StratumPairKind kind in Enum.GetValues()) + Console.WriteLine($" {kind, -12} {byKind[kind].Count()}"); + foreach (SemanticCoverage.DomainRelation relation in Enum.GetValues()) + Console.WriteLine($" {relation, -12} {byRelation[relation].Count()}"); + + string relative = SemanticCoverage.RuleInteractionLedger.RelativePath; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + string fresh = SemanticCoverage.RuleInteractionLedger.ToText(rows); + + if (writeLedger) + { + SemanticCoverage.RuleInteractionLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {relative} ({rows.Count} row(s))"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-rule-interaction-pairs"); + return 1; + } + + if ( + !string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ) + ) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-rule-interaction-pairs"); + return 1; + } + + Console.WriteLine($"{relative} is current ({rows.Count} row(s))"); + return 0; + } + + /// Recomputes the DTD-derived interface inventory against the real corpus and checks it against + /// the checked-in ledger, or rewrites it. + private static int RunInterfaceInventory(string repositoryRoot, bool writeLedger) + { + IReadOnlyList rows = + SemanticCoverage.InterfaceInventoryLedger.Compute(repositoryRoot); + IReadOnlyList junctions = + SemanticCoverage.InterfaceInventoryLedger.ComputeJunctions(rows); + int presentCount = rows.Count(r => r.Present); + int typedEdgeCount = rows.Sum(r => r.ObservedTargetTypes.Count); + + Console.WriteLine($"declared interfaces: {rows.Count}"); + Console.WriteLine($" present {presentCount} (structural only -- see interface-witness.tsv for witness)"); + Console.WriteLine($" not present {rows.Count - presentCount}"); + Console.WriteLine($"typed edges: {typedEdgeCount}"); + Console.WriteLine($"junctions: {junctions.Count}"); + foreach (SemanticCoverage.InterfaceJunction junction in junctions) + { + Console.WriteLine( + $" {junction.TargetType} ({junction.WriterCount} writer(s), {junction.ReaderCount} reader(s))" + ); + } + + string relative = SemanticCoverage.InterfaceInventoryLedger.RelativePath; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + string fresh = SemanticCoverage.InterfaceInventoryLedger.ToText(rows); + + if (writeLedger) + { + SemanticCoverage.InterfaceInventoryLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {relative} ({rows.Count} row(s))"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-interface-inventory"); + return 1; + } + + if ( + !string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ) + ) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-interface-inventory"); + return 1; + } + + Console.WriteLine($"{relative} is current ({rows.Count} row(s))"); + return 0; + } + + /// Recomputes the write/read interaction-chain denominator and checks it against the + /// checked-in ledger, or rewrites it. + private static int RunInteractionChains(string repositoryRoot, bool writeLedger) + { + IReadOnlyList rows = + SemanticCoverage.InteractionChainLedger.Compute(repositoryRoot); + IReadOnlyList junctions = + SemanticCoverage.InteractionChainLedger.ComputeJunctions(repositoryRoot); + int exercisedCount = rows.Count(r => r.Exercised); + int hazardousCount = rows.Count(r => r.Hazardous); + + Console.WriteLine($"junctions: {junctions.Count}"); + foreach (SemanticCoverage.ChainJunction junction in junctions) + { + Console.WriteLine( + $" {junction.PayloadType} ({junction.Writers.Count} writer(s), {junction.Readers.Count} reader(s))" + ); + } + Console.WriteLine($"interaction chains: {rows.Count}"); + Console.WriteLine($" exercised {exercisedCount}"); + Console.WriteLine($" unexercised {rows.Count - exercisedCount}"); + Console.WriteLine($" hazardous {hazardousCount}"); + + string relative = SemanticCoverage.InteractionChainLedger.RelativePath; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + string fresh = SemanticCoverage.InteractionChainLedger.ToText(rows); + + if (writeLedger) + { + SemanticCoverage.InteractionChainLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {relative} ({rows.Count} row(s))"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-interaction-chains"); + return 1; + } + + if ( + !string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ) + ) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-interaction-chains"); + return 1; + } + + Console.WriteLine($"{relative} is current ({rows.Count} row(s))"); + return 0; + } + + /// Recomputes the data-flow/MC/DC obligation-matrix cells and checks them against the + /// checked-in ledger, or rewrites it. + private static int RunDataflowObligations(string repositoryRoot, bool writeLedger) + { + IReadOnlyList rows = + SemanticCoverage.DataflowObligationLedger.Compute(repositoryRoot); + int satisfied = rows.Count(r => r.Status == SemanticCoverage.ObligationStatus.Satisfied); + int notSatisfied = rows.Count(r => r.Status == SemanticCoverage.ObligationStatus.NotSatisfied); + int unknown = rows.Count(r => r.Status == SemanticCoverage.ObligationStatus.Unknown); + + Console.WriteLine($"obligation cells: {rows.Count}"); + Console.WriteLine($" satisfied {satisfied}"); + Console.WriteLine($" not_satisfied {notSatisfied}"); + Console.WriteLine($" unknown {unknown}"); + + string relative = SemanticCoverage.DataflowObligationLedger.RelativePath; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + string fresh = SemanticCoverage.DataflowObligationLedger.ToText(rows); + + if (writeLedger) + { + SemanticCoverage.DataflowObligationLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {relative} ({rows.Count} row(s))"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-dataflow-obligations"); + return 1; + } + + if ( + !string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ) + ) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-dataflow-obligations"); + return 1; + } + + Console.WriteLine($"{relative} is current ({rows.Count} row(s))"); + return 0; + } + + /// Recomputes the engine-gate inventory (one row per SIL.Machine.Morphology.HermitCrab. + /// FailureReason member) -- mechanically scanned raise sites, hand-verified DTD attributes, and an + /// actual traced engine sweep for witness evidence -- and checks it against the checked-in ledger, + /// or rewrites it. + private static int RunEngineGateInventory(string repositoryRoot, bool writeLedger) + { + Console.WriteLine("tracing every non-pathological, non-crash fixture's words for engine-gate evidence..."); + IReadOnlyList rows = + SemanticCoverage.EngineGateInventoryLedger.Compute(repositoryRoot); + int witnessed = rows.Count(r => r.Status == SemanticCoverage.EngineGateStatus.Witnessed); + int unreached = rows.Count(r => r.Status == SemanticCoverage.EngineGateStatus.Unreached); + int noDtdAttribute = rows.Count(r => r.DtdAttributes == "-"); + + Console.WriteLine($"engine gates: {rows.Count}"); + Console.WriteLine($" witnessed {witnessed}"); + Console.WriteLine($" unreached {unreached}"); + Console.WriteLine($" no DTD attribute {noDtdAttribute}"); + foreach ( + SemanticCoverage.EngineGateInventoryLedger.Row row in rows.Where(r => + r.Status == SemanticCoverage.EngineGateStatus.Unreached + ) + ) + { + Console.Error.WriteLine($"UNREACHED {row.Gate} (raise sites: {row.RaiseSites})"); + } + + string relative = SemanticCoverage.EngineGateInventoryLedger.RelativePath; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + string fresh = SemanticCoverage.EngineGateInventoryLedger.ToText(rows); + + if (writeLedger) + { + SemanticCoverage.EngineGateInventoryLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {relative} ({rows.Count} row(s))"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-engine-gate-inventory"); + return 1; + } + + if ( + !string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ) + ) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-engine-gate-inventory"); + return 1; + } + + Console.WriteLine($"{relative} is current ({rows.Count} row(s))"); + return 0; + } + + /// Recomputes the gate-keyed MC/DC obligation ledger (Blocked/Control arm per + /// FailureReason gate, conformance/gate-obligations.tsv) -- reads the already-checked-in + /// engine-gate-inventory.tsv, interface-witness.tsv and fieldworks-producibility.tsv where it can, + /// falling back to a fresh severance run only where those do not already cover an attribute -- and + /// checks it against the checked-in ledger, or rewrites it. + private static int RunGateObligations(string repositoryRoot, bool writeLedger) + { + Console.WriteLine( + "evaluating gate-keyed obligations (engine-gate-inventory + interface-witness, with a severance fallback)..." + ); + IReadOnlyList rows = SemanticCoverage.GateObligationLedger.Compute( + repositoryRoot + ); + + int gates = rows.Select(r => r.Gate).Distinct().Count(); + int worthCovering = rows.Count(r => r.WorthCovering == "Yes") / 2; + int evidenced = rows.Count(r => r.Status == SemanticCoverage.GateArmStatus.Evidenced); + int notEvidenced = rows.Count(r => r.Status == SemanticCoverage.GateArmStatus.NotEvidenced); + int blockedEvidenced = rows.Count(r => + r.Arm == "Blocked" && r.Status == SemanticCoverage.GateArmStatus.Evidenced + ); + int controlEvidenced = rows.Count(r => + r.Arm == "Control" && r.Status == SemanticCoverage.GateArmStatus.Evidenced + ); + int bothEvidenced = rows.Where(r => r.Status == SemanticCoverage.GateArmStatus.Evidenced) + .GroupBy(r => r.Gate) + .Count(g => g.Count() == 2); + + Console.WriteLine($"gates: {gates} obligations (gate x arm): {rows.Count}"); + Console.WriteLine($" worth_covering (xml_reachable=Yes and flex_producible=Yes) {worthCovering}"); + Console.WriteLine($" arms evidenced {evidenced}"); + Console.WriteLine($" arms not evidenced {notEvidenced}"); + Console.WriteLine($" Blocked evidenced {blockedEvidenced}"); + Console.WriteLine($" Control evidenced {controlEvidenced}"); + Console.WriteLine($" gates with BOTH arms evidenced {bothEvidenced}"); + + string relative = SemanticCoverage.GateObligationLedger.RelativePath; + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + string fresh = SemanticCoverage.GateObligationLedger.ToText(rows); + + if (writeLedger) + { + SemanticCoverage.GateObligationLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {relative} ({rows.Count} row(s))"); + return 0; + } + + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-gate-obligations"); + return 1; + } + + if ( + !string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ) + ) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-gate-obligations"); + return 1; + } + + Console.WriteLine($"{relative} is current ({rows.Count} row(s))"); + return 0; + } + + /// Renders (or checks) one reviewable Markdown card per conformance/dataflow-obligations.tsv + /// cell under conformance/evidence-cards/. Never recomputes any ledger -- purely a rendering of + /// already-checked-in facts for a human or reviewing agent to read; the only failure mode is staleness. + private static int RunEvidenceCards(string repositoryRoot, bool writeCards) + { + IReadOnlyList cards = SemanticCoverage.EvidenceCardGenerator.Compute( + repositoryRoot + ); + IReadOnlyList ledgerRows = + SemanticCoverage.DataflowObligationLedger.Read(repositoryRoot); + + Console.WriteLine($"evidence cards: {cards.Count}"); + foreach (SemanticCoverage.ObligationStatus status in Enum.GetValues()) + Console.WriteLine($" {status, -13} {ledgerRows.Count(r => r.Status == status)}"); + + if (writeCards) + { + SemanticCoverage.EvidenceCardGenerator.Write(repositoryRoot, cards); + Console.WriteLine( + $"wrote {cards.Count} card(s) to {SemanticCoverage.EvidenceCardGenerator.RelativeDirectory}" + ); + return 0; + } + + SemanticCoverage.EvidenceCardDiff diff = SemanticCoverage.EvidenceCardGenerator.Check(repositoryRoot, cards); + foreach (string detail in diff.Details) + Console.Error.WriteLine(detail); + + if (!diff.IsCurrent) + { + Console.Error.WriteLine( + $"{SemanticCoverage.EvidenceCardGenerator.RelativeDirectory} is stale ({diff.StaleOrMissingCount} " + + $"missing/stale, {diff.ExtraFileCount} extra); regenerate with --write-evidence-cards" + ); + return 1; + } + + Console.WriteLine( + $"{SemanticCoverage.EvidenceCardGenerator.RelativeDirectory} is current ({cards.Count} card(s))" + ); + return 0; + } + + /// + /// Regenerates (or checks) the four traceability artifacts together: interface-witness.tsv (the + /// only expensive part -- a severance sweep, same cost class as --write-counterfactual), then the + /// three cheap joins that read it back: grammar-coverage-ledger.tsv, construct-claim-corroboration.tsv, + /// and fold-in-candidates.tsv. Even the non-writing (check) path re-runs the severance sweep, so this + /// is a deliberate, occasional command -- never part of ordinary CI -- not a cheap drift check. + /// + private static int RunCoverageTraceability(string repositoryRoot, bool writeLedgers) + { + int WriteOrCheck(string relative, string fresh, Action write) + { + if (writeLedgers) + { + write(); + Console.WriteLine($"wrote {relative}"); + return 0; + } + + string path = Path.Combine(repositoryRoot, relative.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + { + Console.Error.WriteLine($"{relative} is missing; regenerate with --write-coverage-traceability"); + return 1; + } + + bool same = string.Equals( + File.ReadAllText(path).ReplaceLineEndings("\n"), + fresh.ReplaceLineEndings("\n"), + StringComparison.Ordinal + ); + if (!same) + { + Console.Error.WriteLine($"{relative} is stale; regenerate with --write-coverage-traceability"); + return 1; + } + + Console.WriteLine($"{relative} is current"); + return 0; + } + + Console.WriteLine( + "sweeping interface severance witnesses (this re-parses every present interface x fixture)..." + ); + IReadOnlyList witnessRows = + SemanticCoverage.InterfaceWitnessLedger.Sweep( + repositoryRoot, + onFixtureStarted: (fixtureId, count) => Console.Error.WriteLine($" {fixtureId} ({count} interface(s))") + ); + int failed = WriteOrCheck( + SemanticCoverage.InterfaceWitnessLedger.RelativePath, + SemanticCoverage.InterfaceWitnessLedger.ToText(witnessRows), + () => SemanticCoverage.InterfaceWitnessLedger.Write(repositoryRoot, witnessRows) + ); + + // The three joins below read interface-witness.tsv back off disk (see their own doc comments + // for why that is deliberate), so in write mode the write above has to have already landed; + // WriteOrCheck runs its `write` callback before returning, so that is already guaranteed here. + string constructsPath = Path.Combine(repositoryRoot, "conformance", "constructs.txt"); + IReadOnlyList claimRows = + SemanticCoverage.ConstructClaimCorroboration.Compute(repositoryRoot, constructsPath); + failed += WriteOrCheck( + SemanticCoverage.ConstructClaimCorroboration.RelativePath, + SemanticCoverage.ConstructClaimCorroboration.ToText(claimRows), + () => SemanticCoverage.ConstructClaimCorroboration.Write(repositoryRoot, claimRows) + ); + + IReadOnlyList grammarRows = + SemanticCoverage.GrammarCoverageLedger.Compute(repositoryRoot); + failed += WriteOrCheck( + SemanticCoverage.GrammarCoverageLedger.RelativePath, + SemanticCoverage.GrammarCoverageLedger.ToText(grammarRows), + () => SemanticCoverage.GrammarCoverageLedger.Write(repositoryRoot, grammarRows) + ); + + IReadOnlyList foldInRows = + SemanticCoverage.FoldInCandidateLedger.Compute(repositoryRoot); + failed += WriteOrCheck( + SemanticCoverage.FoldInCandidateLedger.RelativePath, + SemanticCoverage.FoldInCandidateLedger.ToText(foldInRows), + () => SemanticCoverage.FoldInCandidateLedger.Write(repositoryRoot, foldInRows) + ); + + return failed == 0 ? 0 : 1; + } + + /// + /// Reads the checked-in Surface ledger (already refreshed by a prior --write-counterfactual + /// run -- never recomputed here, so this mode's cost is the Ordering sweep alone), runs the Ordering + /// sweep, combines both into the CoverageItem inventory, recomputes completeness, and prints the + /// breakdown by item kind and by counterexample kind. Never blends Word and LoadFailure counts, and + /// never blends Surface and Ordering counts. + /// + private static int RunCoverageEvidence(string repositoryRoot, bool writeLedger) + { + IReadOnlyList surfaceResults = + SemanticCoverage.CounterfactualLedger.Read(repositoryRoot); + if (surfaceResults.Count == 0) + { + Console.Error.WriteLine( + $"{SemanticCoverage.CounterfactualLedger.RelativePath} is empty; run --write-counterfactual first" + ); + return 2; + } + + Console.WriteLine("combined Surface+Ordering inventory"); + Console.WriteLine("------------------------------------"); + IReadOnlyList orderingResults = + SemanticCoverage.CounterfactualLedger.SweepOrdering( + repositoryRoot, + (fixtureId, itemCount) => Console.Error.WriteLine($" ordering: {fixtureId} ({itemCount} item(s))") + ); + + IReadOnlyList items = SemanticCoverage.CoverageEvidencePipeline.BuildItems( + surfaceResults, + orderingResults + ); + IReadOnlyList evidence = SemanticCoverage.CoverageEvidencePipeline.BuildEvidence( + surfaceResults.Concat(orderingResults).ToArray() + ); + var evidencedIds = evidence.Select(e => e.ItemId).ToHashSet(StringComparer.Ordinal); + SemanticCoverage.CoverageItem[] nonEvidencedOrdering = items + .Where(item => item.Kind == SemanticCoverage.CoverageItemKind.Ordering && !evidencedIds.Contains(item.Id)) + .ToArray(); + IReadOnlyList proofs = SemanticCoverage.CoverageEvidencePipeline.BuildProofs( + repositoryRoot, + nonEvidencedOrdering + ); + + SemanticCoverage.CompletenessReport report = SemanticCoverage.CoverageCompletenessGate.Evaluate( + items, + evidence, + proofs, + SemanticCoverage.CoverageEvidencePipeline.GrammarLoader(repositoryRoot) + ); + + var kindByItemId = items.ToDictionary(item => item.Id, item => item.Kind, StringComparer.Ordinal); + foreach (SemanticCoverage.CoverageItemKind kind in Enum.GetValues()) + { + SemanticCoverage.CoverageResolutionResult[] ofKind = report + .Items.Where(result => kindByItemId[result.ItemId] == kind) + .ToArray(); + if (ofKind.Length == 0) + continue; + + Console.WriteLine($" {kind} ({ofKind.Length} item(s)):"); + Console.WriteLine( + $" evidenced (Word): {ofKind.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Evidenced && r.CounterexampleKind == SemanticCoverage.CounterexampleKind.Word)}" + ); + Console.WriteLine( + $" evidenced (LoadFailure): {ofKind.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Evidenced && r.CounterexampleKind == SemanticCoverage.CounterexampleKind.LoadFailure)}" + ); + Console.WriteLine( + $" proven: {ofKind.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Proven)}" + ); + Console.WriteLine( + $" unresolved (gap): {ofKind.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Unresolved)}" + ); + Console.WriteLine( + $" conflicting: {ofKind.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Conflicting)}" + ); + Console.WriteLine( + $" rejected proof: {ofKind.Count(r => r.Resolution == SemanticCoverage.CoverageResolution.Rejected)}" + ); + } + + Console.WriteLine($" total: {items.Count} item(s), complete: {report.IsComplete}"); + if (report.OrphanedEvidenceItemIds.Count != 0) + Console.Error.WriteLine($" orphaned evidence row(s): {string.Join(", ", report.OrphanedEvidenceItemIds)}"); + if (report.OrphanedProofItemIds.Count != 0) + Console.Error.WriteLine($" orphaned proof(s): {string.Join(", ", report.OrphanedProofItemIds)}"); + + if (writeLedger) + { + IReadOnlyList rows = + SemanticCoverage.CoverageEvidencePipeline.BuildLedgerRows(items, evidence); + SemanticCoverage.EvidenceLedger.Write(repositoryRoot, rows); + Console.WriteLine($"wrote {SemanticCoverage.EvidenceLedger.RelativePath} ({rows.Count} row(s))"); + } + + // This is authoritative, unlike the additive freshness stats above: every non-evidenced item + // must either pass a recomputed proof or remain an explicit failure. + return report.IsComplete ? 0 : 1; + } + + // 2s is the sweep's real per-word target; the child-process kill is only the safety net behind + // it, so a word over 2s is worth naming even when the run it belongs to still finished in time. + private static readonly TimeSpan SlowWordThreshold = TimeSpan.FromSeconds(2); + + private static void PrintTimingReport(IReadOnlyList timings, TimeSpan elapsed) + { + long thresholdMs = (long)SlowWordThreshold.TotalMilliseconds; + SemanticCoverage.WordTiming[] baseline = timings.Where(t => t.Phase == "baseline").ToArray(); + SemanticCoverage.WordTiming[] mutant = timings.Where(t => t.Phase == "mutant").ToArray(); + SemanticCoverage.WordTiming[] slowBaseline = baseline + .Where(t => t.ElapsedMs >= thresholdMs) + .OrderByDescending(t => t.ElapsedMs) + .ToArray(); + SemanticCoverage.WordTiming[] slowMutant = mutant + .Where(t => t.ElapsedMs >= thresholdMs) + .OrderByDescending(t => t.ElapsedMs) + .ToArray(); + int slowMutantEvaluations = slowMutant.Select(t => (t.FixtureId, t.SurfaceId)).Distinct().Count(); + + Console.WriteLine(); + Console.WriteLine( + $"timing: {baseline.Length} unmutated word parse(s), {mutant.Length} mutant word parse(s), " + + $"sweep took {elapsed.TotalSeconds:0.0}s" + ); + Console.WriteLine($" unmutated word(s) >= {SlowWordThreshold.TotalSeconds:0}s: {slowBaseline.Length}"); + foreach (SemanticCoverage.WordTiming t in slowBaseline) + Console.Error.WriteLine($"SLOW BASELINE {t.FixtureId} '{t.Word}' {t.ElapsedMs}ms"); + Console.WriteLine( + $" mutant evaluation(s) with a word >= {SlowWordThreshold.TotalSeconds:0}s: {slowMutantEvaluations}" + ); + foreach (SemanticCoverage.WordTiming t in slowMutant.Take(20)) + Console.Error.WriteLine($"SLOW MUTANT {t.FixtureId} {t.SurfaceId} '{t.Word}' {t.ElapsedMs}ms"); + } + + private static int RunSemanticCoverage( + string repositoryRoot, + bool writeBaseline, + bool proposeCatalog, + IReadOnlyCollection proposedAuditedScopes + ) + { + // A proposal is review material, not an authority verdict. If the curated catalog already + // names scopes, use that live source snapshot; an empty catalog remains on the explicit + // legacy DTD-only path rather than guessing scopes or silently becoming authoritative. + if (proposeCatalog) + { + SemanticCoverage.SemanticInventory proposal; + IReadOnlyList proposalScopes; + try + { + SemanticCoverage.SemanticCatalog existingCatalog = SemanticCoverage.CatalogBootstrap.Load( + repositoryRoot + ); + proposalScopes = + proposedAuditedScopes.Count != 0 + ? proposedAuditedScopes + .Distinct(StringComparer.Ordinal) + .OrderBy(scope => scope, StringComparer.Ordinal) + .ToArray() + : existingCatalog.AuditedSourceScopes; + if (proposalScopes.Count == 0) + { + Console.Error.WriteLine( + "semantic catalog proposal requires one or more --audited-source-scope arguments " + + "when the checked-in catalog has no audited scopes" + ); + return 2; + } + + proposal = SemanticCoverage.GraphSemanticCensus.Read( + repositoryRoot, + proposalScopes, + System.Threading.CancellationToken.None + ); + } + catch (Exception ex) + when (ex + is IOException + or UnauthorizedAccessException + or FormatException + or ArgumentException + or InvalidOperationException + ) + { + Console.Error.WriteLine($"semantic catalog proposal unavailable: {ex.Message}"); + return 2; + } + SemanticCoverage.CatalogBootstrap.WriteProposal(Console.Out, proposal, proposalScopes); + Console.Error.WriteLine( + "semantic catalog proposal only; canonical catalog was not changed and no authority verdict was produced" + ); + return 1; + } + + SemanticCoverage.SemanticCatalog catalog; + try + { + // Load the catalog before touching source roots. Empty scopes are a controlled audit + // failure; they must never be replaced by guessed roots or a DTD-only fallback. + catalog = SemanticCoverage.CatalogBootstrap.Load(repositoryRoot); + } + catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or FormatException) + { + Console.Error.WriteLine( + $"semantic coverage authority unavailable: malformed or missing catalog ({ex.Message})" + ); + return 2; + } + + SemanticCoverage.SemanticInventory inventory; + try + { + inventory = SemanticCoverage.GraphSemanticCensus.Read( + repositoryRoot, + catalog.AuditedSourceScopes, + System.Threading.CancellationToken.None + ); + } + catch (Exception ex) + when (ex + is IOException + or UnauthorizedAccessException + or ArgumentException + or InvalidOperationException + or FormatException + ) + { + Console.Error.WriteLine( + $"semantic coverage authority unavailable: source snapshot could not be read ({ex.Message})" + ); + return 2; + } + + SemanticCoverage.GrammarCoverageResult result = SemanticCoverage.GrammarCoverageGate.Compute( + repositoryRoot, + inventory + ); + + Console.WriteLine($"generated surfaces: {inventory.Surfaces.Count}"); + Console.WriteLine($"grammar-observable: {result.Observable.Count}"); + Console.WriteLine($"covered by fixtures: {result.Covered.Count}"); + Console.WriteLine($"uncovered: {result.Uncovered.Count}"); + + IReadOnlyList existing = + SemanticCoverage.GrammarCoverageGate.ReadBaseline(repositoryRoot); + IReadOnlyList classified = + SemanticCoverage.GrammarCoverageGate.Classify(repositoryRoot, result.Uncovered, existing); + int dead = classified.Count(entry => entry.Classification == SemanticCoverage.GrammarCoverageGate.DeadSchema); + int quotient = classified.Count(entry => + entry.Classification == SemanticCoverage.GrammarCoverageGate.AlphabetQuotient + ); + int dtdDefault = classified.Count(entry => + entry.Classification == SemanticCoverage.GrammarCoverageGate.DtdDefault + ); + Console.WriteLine($" dead schema: {dead}"); + Console.WriteLine($" dtd default: {dtdDefault}"); + Console.WriteLine($" alphabet quotient: {quotient}"); + Console.WriteLine($" awaiting fixture: {classified.Count - dead - quotient - dtdDefault}"); + + IReadOnlyList evidence = SemanticCoverage.GrammarCoverageGate.GradeEvidence( + repositoryRoot, + inventory + ); + Console.WriteLine("evidence behind the covered surfaces:"); + foreach ( + SemanticCoverage.EvidenceStrength strength in Enum.GetValues() + .OrderByDescending(value => value) + ) + { + Console.WriteLine($" {strength, -11} {evidence.Count(item => item.Strength == strength)}"); + } + + // Presence is not coverage, so an unwaived presence-only surface fails the run rather than + // merely printing. + string[] presenceOnly = evidence + .Where(item => item.Strength == SemanticCoverage.EvidenceStrength.Presence) + .Select(item => item.SurfaceId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + IReadOnlyList waived = SemanticCoverage.GrammarCoverageGate.ReadPresenceWaivers(repositoryRoot); + string[] unwaivedPresence = presenceOnly.Except(waived, StringComparer.Ordinal).ToArray(); + string[] staleWaivers = waived.Except(presenceOnly, StringComparer.Ordinal).ToArray(); + foreach ( + SemanticCoverage.SurfaceEvidence item in evidence + .Where(item => item.Strength == SemanticCoverage.EvidenceStrength.Presence) + .OrderBy(item => item.SurfaceId, StringComparer.Ordinal) + ) + { + string state = waived.Contains(item.SurfaceId, StringComparer.Ordinal) ? "waived" : "UNWAIVED"; + Console.Error.WriteLine($"PRESENCE ONLY ({state}) {item.SurfaceId} [{item.FixtureId}] {item.Detail}"); + } + + foreach (string id in staleWaivers) + Console.Error.WriteLine($"STALE PRESENCE WAIVER (delete it) {id}"); + + SemanticCoverage.AuditResult audit = SemanticCoverage.SemanticCoverageAudit.Run(inventory, catalog); + Console.WriteLine( + $"catalog audit: {(audit.IsComplete ? "complete" : $"{audit.Diagnostics.Count} diagnostic(s)")}" + ); + foreach (SemanticCoverage.AuditDiagnostic diagnostic in audit.Diagnostics.Take(25)) + Console.Error.WriteLine($"AUDIT {diagnostic.Code} {diagnostic.SubjectId}"); + if (audit.Diagnostics.Count > 25) + Console.Error.WriteLine($"AUDIT ... and {audit.Diagnostics.Count - 25} more"); + + IReadOnlyList unbacked = SemanticCoverage.GrammarCoverageGate.UnbackedQuotients( + classified, + result.Covered + ); + foreach (string id in unbacked) + Console.Error.WriteLine($"UNBACKED QUOTIENT (no covered sibling) {id}"); + + var baseline = SemanticCoverage + .GrammarCoverageGate.ReadBaseline(repositoryRoot) + .Select(entry => entry.SurfaceId) + .ToArray(); + string[] newGaps = result + .Uncovered.Except(baseline, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] stale = baseline + .Except(result.Uncovered, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + foreach (string id in newGaps) + Console.Error.WriteLine($"NEW GAP {id}"); + foreach (string id in stale) + Console.Error.WriteLine($"NOW COVERED (delete from baseline) {id}"); + // Writing happens BEFORE the verdict and never changes it: regenerating the baseline must + // never absorb a real regression as a fresh todo line and report success. + if (writeBaseline) + { + SemanticCoverage.GrammarCoverageGate.WriteBaseline(repositoryRoot, classified); + Console.WriteLine($"wrote {SemanticCoverage.GrammarCoverageGate.BaselineRelativePath}"); + } + + if ( + !audit.IsComplete + || newGaps.Length != 0 + || stale.Length != 0 + || unbacked.Count != 0 + || unwaivedPresence.Length != 0 + || staleWaivers.Length != 0 + ) + { + Console.Error.WriteLine( + $"semantic coverage findings: {newGaps.Length} new gap(s), " + + $"{stale.Length} stale line(s), {unbacked.Count} unbacked quotient(s), " + + $"{unwaivedPresence.Length} unwaived presence-only, {staleWaivers.Length} stale waiver(s)" + ); + return 1; + } + + Console.WriteLine("semantic coverage matches the baseline"); + return 0; + } + + /// Returns the argument following , or prints usage and returns + /// false if was the last token (no bounds-check crash on a truncated + /// command line). + private static bool TryGetNextArg(string[] args, ref int i, string flag, out string value) + { + if (i + 1 >= args.Length) + { + Console.Error.WriteLine($"{flag} requires a value"); + PrintUsage(); + value = null; + return false; + } + value = args[++i]; + return true; + } + + private static HashSet ParseCapabilities(string arg) + { + return arg.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .ToHashSet(StringComparer.Ordinal); + } + + private static void PrintRunReport(RunReport report, IEngine engine) + { + Console.WriteLine(); + Console.WriteLine( + $"engine: {engine.Name}, capabilities: [{string.Join(",", engine.Capabilities.OrderBy(c => c))}]" + ); + if (report.ExcludedPathologicalCount > 0) + { + Console.WriteLine( + $"{report.ExcludedPathologicalCount} pathological (budget_ms) fixture(s) excluded by default (--include-pathological to run)" + ); + } + Console.WriteLine(); + + foreach (FixtureResult result in report.Results) + { + string status = result.Outcome switch + { + FixtureOutcome.Passed => "PASS", + FixtureOutcome.Failed => "FAIL", + FixtureOutcome.Skipped => "SKIP", + _ => "?", + }; + Console.WriteLine($"[{status}] {result.FixtureId} ({result.ElapsedMs}ms) {result.Reason}"); + if (result.Outcome == FixtureOutcome.Failed) + { + foreach (WordResult w in result.WordResults.Where(w => !w.Passed)) + Console.WriteLine($" word '{w.Word}': {w.Detail}"); + } + } + + Console.WriteLine(); + Console.WriteLine( + $"totals: {report.Passed} passed, {report.Failed} failed, {report.Skipped} skipped (of {report.Results.Count} attempted)" + ); + } + + // "Tracing" is the one construct the suite deliberately never covers: no adapter can produce a + // trace through PROTOCOL.md's wire contract, so no word's expected.tsv signature can exercise it. + private const string OutOfScopeConstruct = "Tracing (TraceType)"; + + private static void RunCoverageReport(List fixtures, string fixturesRoot, string constructsPath) + { + string coverageCsvPath = Path.Combine(fixturesRoot, "coverage.csv"); + string rulesCsvPath = Path.Combine(fixturesRoot, "rules.csv"); + CoverageReport.CoverageResult result = CoverageReport.WriteCsvs(fixtures, coverageCsvPath, rulesCsvPath); + + Console.WriteLine(); + Console.WriteLine("coverage report"); + Console.WriteLine("==============="); + Console.WriteLine($"wrote {coverageCsvPath}"); + Console.WriteLine($"wrote {rulesCsvPath}"); + + // Absolute construct-coverage check against constructs.txt: every construct except Tracing + // must be covered. + if (File.Exists(constructsPath)) + { + List checklist = CoverageReport.LoadConstructChecklist(constructsPath); + List uncovered = checklist + .Where(c => !string.Equals(c, OutOfScopeConstruct, StringComparison.Ordinal)) + .Where(c => !result.CoveredConstructs.Contains(c)) + .ToList(); + Console.WriteLine(); + int inScope = checklist.Count(c => !string.Equals(c, OutOfScopeConstruct, StringComparison.Ordinal)); + Console.WriteLine( + $"construct coverage: {inScope - uncovered.Count}/{inScope} in-scope constructs covered " + + $"(Tracing out of scope by design)" + ); + if (uncovered.Count > 0) + { + Console.WriteLine($"*** {uncovered.Count} CONSTRUCT(S) AT ZERO COVERAGE ***"); + foreach (string c in uncovered) + Console.WriteLine($" {c}"); + } + } + + if (result.DeadRules.Count > 0) + { + Console.WriteLine(); + Console.WriteLine($"*** {result.DeadRules.Count} DEAD RULE(S) (exercised by zero words) ***"); + foreach (CoverageReport.DeadRule dead in result.DeadRules) + Console.WriteLine($" {dead.FixtureId}: rule '{dead.RuleId}'"); + } + else + { + Console.WriteLine("0 dead rules across all grammars."); + } + } + + private static void PrintUsage() + { + Console.WriteLine( + """ + usage: hc-conformance --fixtures [options] + + options: + --adapter "" Run fixtures through an external engine adapter. + Template placeholders: {grammar} {words} {output}. + Omit to run the harness's self-check mode (in-process + C# oracle) instead. + --capabilities Capability set the engine under test declares (e.g. + "phonology", or "" for none). Defaults to the full set + in self-check mode, empty in --adapter mode. + --include-pathological Also run category:pathological fixtures (excluded by + default). + --coverage-report Print a coverage report instead of running fixtures. + --constructs Construct checklist file for --coverage-report + --semantic-coverage Recompute generated-surface coverage and check the + baseline; exits 1 on a new gap or a stale line. + --write-coverage-baseline Rewrite conformance/semantic-coverage-baseline.txt. + --propose-semantic-catalog Print a review-only catalog proposal to stdout; + never changes conformance/semantic-catalog.yaml. + --audited-source-scope Exact canonical C# symbol scope for a proposal; + repeat for multiple scopes. Required when the + checked-in catalog has no scopes. + --counterfactual Re-run every fixture with each surface neutralized + and check the ledger; exits 1 on a new, gone, or + changed verdict. + --write-counterfactual Rewrite conformance/semantic-coverage-counterfactuals.tsv. + --coverage-evidence Combine the checked-in Surface ledger with a fresh + Ordering adjacent-pair sweep into the 332-item + Surface+Ordering inventory and print completeness by + item kind and counterexample kind. Run + --write-counterfactual first so the Surface half is + fresh; this never recomputes it. + --write-coverage-evidence Also rewrite conformance/semantic-coverage-evidence.tsv. + --rule-interaction-pairs Recompute every fixture's pipeline-permitted Stratum + rule-interaction pairs and check them against + conformance/rule-interaction-pairs.tsv; exits 1 if stale. + --write-rule-interaction-pairs Rewrite conformance/rule-interaction-pairs.tsv. + --interface-inventory Recompute the DTD-declared IDREF/IDREFS interfaces, + resolved against the real corpus, and check them + against conformance/interface-inventory.tsv; exits 1 + if stale. + --write-interface-inventory Rewrite conformance/interface-inventory.tsv. + --interaction-chains Recompute the write/read interaction-chain denominator + (writer edge x payload type x reader edge, at each + interface-inventory junction) and check it against + conformance/interaction-chains.tsv; exits 1 if stale. + --write-interaction-chains Rewrite conformance/interaction-chains.tsv. + --dataflow-obligations Recompute the data-flow/MC/DC obligation-matrix cells + (all-uses, plus MC/DC on every gate, plus every + kill-path witnessed) from + conformance/interaction-chains.tsv and check them + against conformance/dataflow-obligations.tsv; exits 1 + if stale. + --write-dataflow-obligations Rewrite conformance/dataflow-obligations.tsv. + --coverage-traceability Re-sweep interface severance witness (expensive -- one + reparse per present interface x fixture) and check + interface-witness.tsv, grammar-coverage-ledger.tsv, + construct-claim-corroboration.tsv, and + fold-in-candidates.tsv; exits 1 if any is stale. + --write-coverage-traceability Rewrite all four files above. + --evidence-cards Render one reviewable Markdown card per + conformance/dataflow-obligations.tsv cell under + conformance/evidence-cards/ and check it against what + is checked in; exits 1 if stale. Never recomputes any + ledger -- purely a rendering of already-checked-in + facts for a human or reviewing agent to read. + --write-evidence-cards Rewrite conformance/evidence-cards/. + --engine-gate-inventory Recompute the FailureReason-keyed engine-gate inventory + (mechanically scanned raise sites + a traced engine + sweep for witness evidence) and check it against + conformance/engine-gate-inventory.tsv; exits 1 if stale. + --write-engine-gate-inventory Rewrite conformance/engine-gate-inventory.tsv. + --gate-obligations Recompute the gate-keyed MC/DC obligation ledger + (Blocked/Control arm per FailureReason gate) from + engine-gate-inventory.tsv, interface-witness.tsv, and + fieldworks-producibility.tsv (falling back to a fresh + severance run only where those do not already cover an + attribute) and check it against + conformance/gate-obligations.tsv; exits 1 if stale. + --write-gate-obligations Rewrite conformance/gate-obligations.tsv. + --repository-root Repository root for the flags above. + (default: /constructs.txt). + --propose Self-check only: on a signature mismatch, print + the words.yaml patch that would reconcile it. Never + writes any file. + """ + ); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/Properties/AssemblyInfo.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d8e979b31 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("SIL.Machine.Morphology.HermitCrab.Tests")] diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/ProposePatchWriter.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/ProposePatchWriter.cs new file mode 100644 index 000000000..af14fd97d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/ProposePatchWriter.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.IO; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// --propose: on a self-check signature mismatch, prints the words.yaml patch that +/// would reconcile the fixture with what the oracle actually produced, for a human to accept by +/// hand. This class only ever writes to the +/// it is given -- it has no file-write call anywhere, by construction, so +/// there is no code path here that could accidentally start writing words.yaml back out. +/// +public static class ProposePatchWriter +{ + public static void WriteSignatureProposal( + TextWriter output, + Fixture fixture, + WordEntry word, + List actualEntries + ) + { + output.WriteLine(); + output.WriteLine($"# --propose: {fixture.Id}/words.yaml -- word '{word.Word}' signature mismatch"); + output.WriteLine("# Proposed replacement entry (rules:/gloss: left as-is; fill in by hand):"); + if (actualEntries.Count == 0) + { + output.WriteLine($" - word: {word.Word}"); + output.WriteLine($" note: {word.Note}"); + output.WriteLine(" expect_fail: true"); + } + else + { + output.WriteLine($" - word: {word.Word}"); + output.WriteLine($" note: {word.Note}"); + output.WriteLine(" parses:"); + foreach (string entry in actualEntries) + { + output.WriteLine($" - signature: \"{entry}\""); + output.WriteLine(" rules: [] # TODO: fill in from the trace"); + } + } + output.WriteLine(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/RequiresDerivation.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/RequiresDerivation.cs new file mode 100644 index 000000000..4fccaf13e --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/RequiresDerivation.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Mechanically derives a fixture's "requires" capability list from its grammar.xml, per +/// conformance/PROTOCOL.md section 5: today the only defined capability is "phonology", meaning +/// the grammar contains at least one PhonologicalRule or MetathesisRule element. +/// validates every fixture's words.yaml "requires" (and +/// the materialized manifest.json equivalent) against this +/// derivation, so the field can never silently drift from what the grammar actually contains +/// (conformance/README.md's own growth-policy instructions already say to determine this by +/// inspecting the grammar, not by hand-guessing -- this makes that mechanical, not just advisory). +/// +public static class RequiresDerivation +{ + public static List Derive(string grammarPath) + { + // DtdProcessing.Ignore: this only needs element names, not the HermitCrabInput.dtd itself + // (which XmlLanguageLoader resolves via an embedded-resource resolver elsewhere) -- ignoring + // it here avoids taking on that dependency for a check this narrow. + var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }; + using XmlReader reader = XmlReader.Create(grammarPath, settings); + XDocument doc = XDocument.Load(reader); + + bool hasPhonology = doc.Descendants() + .Any(e => e.Name.LocalName == "PhonologicalRule" || e.Name.LocalName == "MetathesisRule"); + + return hasPhonology ? new List { "phonology" } : new List(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/Runner.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Runner.cs new file mode 100644 index 000000000..dd547dbf5 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/Runner.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +public class RunReport +{ + public List Results { get; } = new(); + public int ExcludedPathologicalCount { get; set; } + + public int Passed => Results.Count(r => r.Outcome == FixtureOutcome.Passed); + public int Failed => Results.Count(r => r.Outcome == FixtureOutcome.Failed); + public int Skipped => Results.Count(r => r.Outcome == FixtureOutcome.Skipped); +} + +/// +/// Runs fixtures under conformance/languages and conformance/edge-cases. Self-check mode is a +/// custom, in-process loop (it needs per-word signature-SET comparison against words.yaml and +/// traced-rules verification, neither of which / +/// does). Adapter mode instead materializes each fixture onto disk and hands it to +/// + -- see . +/// +public static class Runner +{ + public static RunReport RunSelfCheck( + List fixtures, + bool includePathological, + IReadOnlySet engineCapabilities, + bool propose, + TextWriter proposeOutput + ) + { + var report = new RunReport(); + foreach (Fixture fixture in fixtures) + { + FixtureResult result = RunOneSelfCheck( + fixture, + includePathological, + engineCapabilities, + propose, + proposeOutput + ); + if (result == null) + report.ExcludedPathologicalCount++; + else + report.Results.Add(result); + } + return report; + } + + private static FixtureResult RunOneSelfCheck( + Fixture fixture, + bool includePathological, + IReadOnlySet engineCapabilities, + bool propose, + TextWriter proposeOutput + ) + { + var result = new FixtureResult { FixtureId = fixture.Id }; + + // Mechanical requires-check against the words.yaml front matter (see PROTOCOL.md section 5 / + // RequiresDerivation) -- a hand-authored drift here is a words.yaml bug. + List derivedRequires = RequiresDerivation.Derive(fixture.GrammarPath); + if ( + !new HashSet(derivedRequires, StringComparer.Ordinal).SetEquals( + new HashSet(fixture.Words.Requires, StringComparer.Ordinal) + ) + ) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = + $"words.yaml error: requires [{string.Join(",", fixture.Words.Requires)}] does not match " + + $"grammar-derived [{string.Join(",", derivedRequires)}]"; + return result; + } + + bool isPathological = fixture.Words.BudgetMs.HasValue; + if (isPathological && !includePathological) + return null; + + List missingCapabilities = fixture.Words.Requires.Where(r => !engineCapabilities.Contains(r)).ToList(); + if (missingCapabilities.Count > 0) + { + result.Outcome = FixtureOutcome.Skipped; + result.Reason = + $"requires [{string.Join(",", fixture.Words.Requires)}], missing [{string.Join(",", missingCapabilities)}]"; + return result; + } + + var sw = Stopwatch.StartNew(); + try + { + RunWithBudget(fixture, result, propose, proposeOutput); + sw.Stop(); + result.ElapsedMs = sw.ElapsedMilliseconds; + + if (fixture.Words.ExpectCrash) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = "expected crash, engine produced output"; + } + else + { + bool overBudget = fixture.Words.BudgetMs.HasValue && result.ElapsedMs > fixture.Words.BudgetMs.Value; + if (overBudget) + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = $"exceeded wall-clock budget ({result.ElapsedMs}ms > {fixture.Words.BudgetMs}ms)"; + } + else if (result.WordResults.All(w => w.Passed)) + { + result.Outcome = FixtureOutcome.Passed; + } + else + { + result.Outcome = FixtureOutcome.Failed; + // Name the words. A bare count cannot be diagnosed from a CI log on a machine you cannot reach. + + WordResult[] mismatched = result.WordResults.Where(word => !word.Passed).ToArray(); + + string named = string.Join( + "; ", + mismatched.Take(5).Select(word => $"{word.Word}: {Truncate(word.Detail)}") + ); + + result.Reason = + mismatched.Length > 5 + ? $"{mismatched.Length}/{ +result.WordResults +.Count} word(s) mismatched: {named}; and {mismatched.Length - 5} more" + : $"{mismatched.Length}/{ +result.WordResults +.Count} word(s) mismatched: {named}"; + } + } + } + catch (Exception ex) + { + sw.Stop(); + result.ElapsedMs = sw.ElapsedMilliseconds; + if (fixture.Words.ExpectCrash) + { + result.Outcome = FixtureOutcome.Passed; + result.Reason = $"engine crashed as expected (words.yaml expect_crash: true): {ex.Message}"; + } + else + { + result.Outcome = FixtureOutcome.Failed; + result.Reason = $"engine crashed: {ex.Message}"; + } + } + + return result; + } + + // Mirrors MaterializedRunner.RunWithBudget's watchdog shape (see that method's doc comment) -- a + // budgeted fixture gets the same "background thread + Task.Wait" timeout enforcement. + private static void RunWithBudget(Fixture fixture, FixtureResult result, bool propose, TextWriter proposeOutput) + { + if (!fixture.Words.BudgetMs.HasValue) + { + RunAllWords(fixture, result, propose, proposeOutput); + return; + } + + long budgetMs = fixture.Words.BudgetMs.Value; + Task task = Task.Run(() => RunAllWords(fixture, result, propose, proposeOutput)); + long marginMs = Math.Max(budgetMs / 5, 1000); + bool completed; + try + { + completed = task.Wait((int)(budgetMs + marginMs)); + } + catch (AggregateException ex) when (ex.InnerException != null) + { + throw ex.InnerException; + } + if (!completed) + throw new TimeoutException("watchdog timed out waiting for self-check engine"); + } + + private static void RunAllWords(Fixture fixture, FixtureResult result, bool propose, TextWriter proposeOutput) + { + Language language = XmlLanguageLoader.Load(fixture.GrammarPath); + var traceManager = new TraceManager { IsTracing = true }; + var morpher = new Morpher(traceManager, language); + GrammarRuleIndex ruleIndex = GrammarRuleIndex.Load(fixture.GrammarPath); + + foreach (WordEntry word in fixture.Words.Words) + { + bool guessRoot = word.Parses.Any(p => p.Guess); + List results; + object trace; + bool wasSkipped = false; + try + { + results = morpher.ParseWord(word.Word, out trace, guessRoot).ToList(); + } + catch (InvalidShapeException) + { + // The engine SKIPS this word (an undeclared segment, etc.) rather than returning a + // zero-parse "ok" -- the adapter contract's "SKIPPED" status. Distinguished from a + // genuine 0-parse below so expect_fail (ok) and expect_skip (SKIPPED) each verify the + // status the materialized expected.tsv (and any real adapter) will actually diff on. + wasSkipped = true; + results = new List(); + trace = null; + } + + string actualSignature = SignatureFormat.BuildSignature(results); + string expectedSignature = FixtureMaterializer.BuildExpectedSignature(word); + List actualEntries = SignatureTsv.SplitSignature(actualSignature); + List expectedEntries = SignatureTsv.SplitSignature(expectedSignature); + + bool signatureMatches = actualEntries.SequenceEqual(expectedEntries, StringComparer.Ordinal); + if (!signatureMatches) + { + result.WordResults.Add( + new WordResult + { + Word = word.Word, + Passed = false, + Detail = + $"expected [{string.Join(" | ", expectedEntries)}] got [{string.Join(" | ", actualEntries)}]", + } + ); + if (propose) + ProposePatchWriter.WriteSignatureProposal(proposeOutput, fixture, word, actualEntries); + continue; + } + + if (word.ExpectSkip) + { + // Declared SKIPPED: PASS iff the engine actually threw InvalidShapeException. A word + // that instead produced a genuine empty parse set (status "ok") is mis-declared -- it + // would diff as ok-vs-SKIPPED against a real adapter, so fail it here too. + result.WordResults.Add( + new WordResult + { + Word = word.Word, + Passed = wasSkipped, + Detail = wasSkipped + ? "ok (skipped: InvalidShapeException)" + : "declared expect_skip but engine produced a zero-parse 'ok' without skipping", + } + ); + continue; + } + + if (word.ExpectFail) + { + // Declared genuine zero-parse "ok": PASS iff the engine did NOT skip. A word that was + // actually SKIPPED (InvalidShapeException) is mis-declared and should be expect_skip -- + // it would diff as SKIPPED-vs-ok against a real adapter (adapter mode materializes "ok" + // for expect_fail). Keeping self-check strict here keeps the two modes consistent. + result.WordResults.Add( + new WordResult + { + Word = word.Word, + Passed = !wasSkipped, + Detail = !wasSkipped + ? "ok (0 parses)" + : "declared expect_fail (status ok) but engine SKIPPED it (InvalidShapeException) -- use expect_skip", + } + ); + continue; + } + + // Signature set matched; now verify the traced "rules:" list per parse. Group actual + // results by their own individual signature so an ambiguous word's N declared parses + // can each be matched to the one result that produced it (signatureMatches above already + // proved this is a 1:1 correspondence at the SET level; duplicate signature strings + // across parses are not expected and, if they occurred, would just re-check the same + // result against every parse sharing that signature). + Dictionary> actualBySignature = results + .GroupBy(w => SignatureFormat.BuildSignature(new[] { w })) + .ToDictionary(g => g.Key, g => g.ToList()); + HashSet wordLevelRuleIds = TraceRuleAttributor.WordLevelRuleIds(trace, ruleIndex); + + bool wordRulesOk = true; + var ruleDetails = new List(); + foreach (ParseEntry parse in word.Parses) + { + if (!actualBySignature.TryGetValue(parse.Signature, out List matches) || matches.Count == 0) + continue; // can't happen given signatureMatches, but stay defensive + foreach (Word match in matches) + { + HashSet actualRuleIds = TraceRuleAttributor.MorphologicalRuleIds(match, ruleIndex); + actualRuleIds.UnionWith(wordLevelRuleIds); + var declaredRuleIds = new HashSet(parse.Rules, StringComparer.Ordinal); + if (!actualRuleIds.SetEquals(declaredRuleIds)) + { + wordRulesOk = false; + ruleDetails.Add( + $"parse '{parse.Signature}': declared rules [{string.Join(",", parse.Rules)}] " + + $"!= traced [{string.Join(",", actualRuleIds.OrderBy(x => x, StringComparer.Ordinal))}]" + ); + } + } + } + + result.WordResults.Add( + new WordResult + { + Word = word.Word, + Passed = wordRulesOk, + Detail = wordRulesOk ? "ok" : string.Join("; ", ruleDetails), + } + ); + } + } + + // ---- Adapter mode: materialize onto disk + reuse MaterializedRunner/AdapterEngine, unmodified. ---- + + public static RunReport RunAdapter(List fixtures, IEngine engine, bool includePathological) + { + var report = new RunReport(); + foreach (Fixture fixture in fixtures) + { + MaterializedFixture materialized = FixtureMaterializer.Materialize(fixture); + try + { + MaterializedRunReport oneReport = MaterializedRunner.Run( + new List { materialized }, + engine, + includePathological + ); + report.ExcludedPathologicalCount += oneReport.ExcludedPathologicalCount; + foreach (FixtureResult r in oneReport.Results) + { + r.FixtureId = fixture.Id; // already fixture.Id (came from the synthetic manifest); kept explicit for clarity + report.Results.Add(r); + } + } + finally + { + FixtureMaterializer.Cleanup(materialized); + } + } + return report; + } + + /// Shortens a per-word detail so a fixture reason stays readable in a log. + /// The word detail, which may carry every expected and actual parse. + private static string Truncate(string detail) + { + const int Limit = 160; + if (string.IsNullOrEmpty(detail) || detail.Length <= Limit) + { + return detail; + } + + return detail[..Limit] + "..."; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SIL.Machine.Morphology.HermitCrab.Conformance.csproj b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SIL.Machine.Morphology.HermitCrab.Conformance.csproj new file mode 100644 index 000000000..67ffb89ec --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SIL.Machine.Morphology.HermitCrab.Conformance.csproj @@ -0,0 +1,32 @@ + + + + Exe + net10.0 + SIL.Machine.Morphology.HermitCrab.Conformance + hc-conformance + Engine-agnostic conformance test harness for the HermitCrab grammar model (see conformance/PROTOCOL.md). + SIL.Machine.Morphology.HermitCrab.Conformance + true + true + true + $(NoWarn);CS1591;CS1573 + + + + + + + + + + + + + + + + + diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SelfCheckEngine.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SelfCheckEngine.cs new file mode 100644 index 000000000..5a786bb9e --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SelfCheckEngine.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Runs a fixture against the live C# HermitCrab engine, in-process: loads grammar.xml via +/// , builds a , parses every word in +/// words.txt, and computes the exact same signature that +/// BatchCommand's oracle uses -- byte-identical, since it's the same shared code, not a +/// reimplementation. This is what catches a fixture going stale when the oracle itself changes +/// (the lesson the plan doc cites from LT-22613). +/// +/// +/// Lets a caller override the reference engine's normal full-capability declaration -- e.g. +/// --capabilities "", which is how the harness's own capability-filtering skip path gets +/// exercised against the live oracle without needing a second, capability-limited engine on hand. +/// Null (the default) means the full set. +/// +public class SelfCheckEngine(IReadOnlySet capabilities = null) : IEngine +{ + private static readonly IReadOnlySet DefaultCapabilities = new HashSet { "phonology" }; + + public string Name => "self-check"; + + // The reference C# engine implements every capability the suite currently knows about, unless + // overridden above. + public IReadOnlySet Capabilities { get; } = capabilities ?? DefaultCapabilities; + + public List Run(MaterializedFixture fixture) + { + Language language; + Morpher morpher; + try + { + language = XmlLanguageLoader.Load(fixture.GrammarPath); + morpher = new Morpher(new TraceManager(), language); + } + catch (Exception ex) + { + throw new EngineCrashException( + $"self-check engine crashed loading grammar for fixture '{fixture.Id}': {ex.Message}", + ex + ); + } + + string[] words = SignatureFormat.LoadWords(fixture.WordsPath); + + var rows = new List(words.Length); + for (int i = 0; i < words.Length; i++) + { + string word = words[i]; + try + { + // SignatureFormat.ParseOneWord only catches InvalidShapeException itself (yielding + // "SKIPPED"); anything else it lets propagate is a genuine engine crash, wrapped + // here the same way grammar-load failures are above. + (string status, long elapsedMs, string signature) = SignatureFormat.ParseOneWord(morpher, word); + rows.Add(new TsvRow(i, word, elapsedMs, status, signature)); + } + catch (Exception ex) + { + throw new EngineCrashException( + $"self-check engine crashed parsing word '{word}' in fixture '{fixture.Id}': {ex.Message}", + ex + ); + } + } + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/AnalyzerMetadataInspector.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/AnalyzerMetadataInspector.cs new file mode 100644 index 000000000..c9ad2a152 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/AnalyzerMetadataInspector.cs @@ -0,0 +1,222 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Security.Cryptography; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record AnalyzerMetadataInspection( + string Path, + bool IsSourceGenerator, + bool LoadedAssembly, + string AssemblyIdentity, + string Sha256, + AnalyzerDisposition Disposition, + string? ReferencePackVersion +); + +internal static class AnalyzerMetadataInspector +{ + internal static AnalyzerMetadataInspection Inspect( + string path, + IReadOnlyCollection? admittedSdkAnalyzerDirectories = null + ) + { + try + { + string fullPath = Path.GetFullPath(path); + string assemblyIdentity = + AssemblyName.GetAssemblyName(fullPath).FullName + ?? throw new BadImageFormatException("Analyzer has no assembly identity."); + string sha256; + using (FileStream hashStream = File.OpenRead(fullPath)) + sha256 = Convert.ToHexString(SHA256.HashData(hashStream)).ToLowerInvariant(); + + using FileStream stream = File.OpenRead(fullPath); + using var pe = new PEReader(stream); + if (!pe.HasMetadata) + throw new BadImageFormatException("Analyzer has no CLI metadata."); + MetadataReader metadata = pe.GetMetadataReader(); + var interfaces = new HashSet(StringComparer.Ordinal); + foreach (TypeDefinitionHandle handle in metadata.TypeDefinitions) + { + TypeDefinition type = metadata.GetTypeDefinition(handle); + foreach (InterfaceImplementationHandle implementationHandle in type.GetInterfaceImplementations()) + { + string? interfaceName = TryGetTypeName( + metadata, + metadata.GetInterfaceImplementation(implementationHandle).Interface + ); + if (interfaceName is not null) + interfaces.Add(interfaceName); + } + + foreach (CustomAttributeHandle attributeHandle in type.GetCustomAttributes()) + { + string? attributeName = TryGetAttributeTypeName( + metadata, + metadata.GetCustomAttribute(attributeHandle) + ); + if (attributeName == "Microsoft.CodeAnalysis.GeneratorAttribute") + { + return CreateInspection( + fullPath, + true, + assemblyIdentity, + sha256, + admittedSdkAnalyzerDirectories + ); + } + } + } + + bool generator = + interfaces.Contains("Microsoft.CodeAnalysis.ISourceGenerator") + || interfaces.Contains("Microsoft.CodeAnalysis.IIncrementalGenerator"); + return CreateInspection(fullPath, generator, assemblyIdentity, sha256, admittedSdkAnalyzerDirectories); + } + catch (Exception exception) + when (exception + is IOException + or UnauthorizedAccessException + or BadImageFormatException + or InvalidOperationException + ) + { + throw new CompilerInputException( + "analyzer-metadata-diagnostic", + $"Cannot inspect analyzer metadata '{path}'.", + exception + ); + } + } + + private static AnalyzerMetadataInspection CreateInspection( + string path, + bool isSourceGenerator, + string assemblyIdentity, + string sha256, + IReadOnlyCollection? admittedSdkAnalyzerDirectories + ) + { + string? referencePackVersion = TryGetReferencePackVersion(path); + string? simpleAssemblyName = new AssemblyName(assemblyIdentity).Name; + AnalyzerDisposition disposition = + isSourceGenerator + && referencePackVersion is not null + && IsKnownSdkGenerator(Path.GetFileName(path), simpleAssemblyName) + && IsAdmittedDirectory(path, admittedSdkAnalyzerDirectories) + ? AnalyzerDisposition.SdkOwnedSourceGeneratorPendingProbe + : AnalyzerDisposition.Ordinary; + return new AnalyzerMetadataInspection( + path, + isSourceGenerator, + false, + assemblyIdentity, + sha256, + disposition, + referencePackVersion + ); + } + + private static bool IsAdmittedDirectory(string path, IReadOnlyCollection? admittedDirectories) + { + if (admittedDirectories is null) + return false; + string directory = Path.TrimEndingDirectorySeparator(Path.GetDirectoryName(path)!); + StringComparison comparison = OperatingSystem.IsWindows() + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + return admittedDirectories.Any(candidate => + directory.Equals(Path.TrimEndingDirectorySeparator(Path.GetFullPath(candidate)), comparison) + ); + } + + private static string? TryGetReferencePackVersion(string path) + { + DirectoryInfo? directory = new(Path.GetDirectoryName(path)!); + if (!string.Equals(directory.Name, "cs", StringComparison.OrdinalIgnoreCase)) + return null; + directory = directory.Parent; + if (directory is null || !string.Equals(directory.Name, "dotnet", StringComparison.OrdinalIgnoreCase)) + return null; + directory = directory.Parent; + if (directory is null || !string.Equals(directory.Name, "analyzers", StringComparison.OrdinalIgnoreCase)) + return null; + directory = directory.Parent; + if ( + directory is null + || !string.Equals(directory.Parent?.Name, "Microsoft.NETCore.App.Ref", StringComparison.OrdinalIgnoreCase) + || !string.Equals(directory.Parent?.Parent?.Name, "packs", StringComparison.OrdinalIgnoreCase) + ) + { + return null; + } + return directory.Name; + } + + private static bool IsKnownSdkGenerator(string fileName, string? simpleAssemblyName) + { + string expectedName = Path.GetFileNameWithoutExtension(fileName); + if (!string.Equals(expectedName, simpleAssemblyName, StringComparison.Ordinal)) + return false; + return fileName switch + { + "Microsoft.Interop.ComInterfaceGenerator.dll" => true, + "Microsoft.Interop.JavaScript.JSImportGenerator.dll" => true, + "Microsoft.Interop.LibraryImportGenerator.dll" => true, + "System.Text.Json.SourceGeneration.dll" => true, + "System.Text.RegularExpressions.Generator.dll" => true, + _ => false, + }; + } + + private static string? TryGetTypeName(MetadataReader metadata, EntityHandle handle) + { + return handle.Kind switch + { + HandleKind.TypeReference => GetTypeReferenceName( + metadata, + metadata.GetTypeReference((TypeReferenceHandle)handle) + ), + HandleKind.TypeDefinition => GetTypeDefinitionName( + metadata, + metadata.GetTypeDefinition((TypeDefinitionHandle)handle) + ), + HandleKind.TypeSpecification => null, + _ => throw new BadImageFormatException("Analyzer interface metadata is not a type."), + }; + } + + private static string? TryGetAttributeTypeName(MetadataReader metadata, CustomAttribute attribute) + { + EntityHandle declaringType = attribute.Constructor.Kind switch + { + HandleKind.MemberReference => metadata + .GetMemberReference((MemberReferenceHandle)attribute.Constructor) + .Parent, + HandleKind.MethodDefinition => metadata + .GetMethodDefinition((MethodDefinitionHandle)attribute.Constructor) + .GetDeclaringType(), + _ => throw new BadImageFormatException("Analyzer custom-attribute constructor is invalid."), + }; + return TryGetTypeName(metadata, declaringType); + } + + private static string GetTypeReferenceName(MetadataReader metadata, TypeReference reference) => + GetNamespace(metadata, reference.Namespace) + metadata.GetString(reference.Name); + + private static string GetTypeDefinitionName(MetadataReader metadata, TypeDefinition definition) => + GetNamespace(metadata, definition.Namespace) + metadata.GetString(definition.Name); + + private static string GetNamespace(MetadataReader metadata, StringHandle handle) + { + string value = metadata.GetString(handle); + return string.IsNullOrEmpty(value) ? string.Empty : value + "."; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpCommandLineInputParser.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpCommandLineInputParser.cs new file mode 100644 index 000000000..b07569777 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpCommandLineInputParser.cs @@ -0,0 +1,314 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal static class CSharpCommandLineInputParser +{ + internal static CompilerInputModel Parse( + CapturedCompilerInputs captured, + string repositoryRoot, + string projectDirectory, + string intermediateDirectory, + IReadOnlyList? profileSymbols = null, + CompilerToolchainIdentity? queriedToolchain = null + ) + { + ArgumentNullException.ThrowIfNull(captured); + if ( + captured.Items.TryGetValue("Using", out IReadOnlyList? usingItems) + && usingItems.Count != 0 + ) + { + throw new CompilerInputException( + "unsupported-implicit-global-using", + "Implicit global using inputs are not supported." + ); + } + CompilerInputModel model = Parse( + captured.Items["CscCommandLineArgs"].Select(item => item.Identity).ToArray(), + projectDirectory, + profileSymbols, + queriedToolchain, + AdmittedSdkAnalyzerDirectories(captured.Items["ReferencePathWithRefAssemblies"]) + ); + var classifier = new CompilerSourceClassifier( + repositoryRoot, + projectDirectory, + intermediateDirectory, + captured.Properties["GeneratedAssemblyInfoFile"], + captured.Properties["TargetFrameworkMonikerAssemblyAttributesPath"] + ); + var compileItems = captured.Items["Compile"]; + StringComparer pathComparer = OperatingSystem.IsWindows() + ? StringComparer.OrdinalIgnoreCase + : StringComparer.Ordinal; + var byIdentity = new Dictionary(pathComparer); + foreach (CapturedCompilerItem item in compileItems) + { + string itemPath = item.Metadata.TryGetValue("FullPath", out string? fullPath) ? fullPath : item.Identity; + itemPath = Path.GetFullPath(itemPath, projectDirectory); + if (!byIdentity.TryAdd(itemPath, item)) + { + throw new CompilerInputException( + "duplicate-compiler-source", + $"Compiler source '{item.Identity}' occurs more than once." + ); + } + } + var sources = new List(); + var parsedSourcePaths = new HashSet(pathComparer); + for (int sourceIndex = 0; sourceIndex < model.Arguments.SourceFiles.Length; sourceIndex++) + { + string source = model.Arguments.SourceFiles[sourceIndex].Path; + string sourcePath = Path.GetFullPath(source, projectDirectory); + if (!parsedSourcePaths.Add(sourcePath)) + { + throw new CompilerInputException( + "duplicate-compiler-source", + $"Compiler source '{source}' occurs more than once in compiler arguments." + ); + } + if (!byIdentity.TryGetValue(sourcePath, out CapturedCompilerItem? item)) + { + throw new CompilerInputException( + "unsupported-compiler-source", + $"Compiler source '{source}' has no captured Compile item." + ); + } + sources.Add( + new CompilerSourceClassification( + sourcePath, + classifier.Classify(sourcePath, item.Metadata), + model.Sources[sourceIndex].Content + ) + ); + } + if (sources.Count != compileItems.Count || !parsedSourcePaths.SetEquals(byIdentity.Keys)) + { + throw new CompilerInputException( + "unsupported-compiler-source", + "Captured Compile items and parsed source files differ." + ); + } + return model with { Sources = sources }; + } + + internal static CompilerInputModel Parse( + IReadOnlyList commandLine, + string baseDirectory, + IReadOnlyList? profileSymbols = null, + CompilerToolchainIdentity? queriedToolchain = null, + IReadOnlyCollection? admittedSdkAnalyzerDirectories = null + ) + { + ArgumentNullException.ThrowIfNull(commandLine); + ArgumentException.ThrowIfNullOrWhiteSpace(baseDirectory); + baseDirectory = Path.GetFullPath(baseDirectory); + if (queriedToolchain is not null) + VerifyToolchain(queriedToolchain); + + CommandLineArguments parsed; + try + { + parsed = CSharpCommandLineParser.Default.Parse(commandLine, baseDirectory, null, null); + } + catch (Exception exception) when (exception is ArgumentException or InvalidOperationException) + { + throw new CompilerInputException("compiler-parser-diagnostic", exception.Message, exception); + } + + if (parsed.Errors.Length != 0) + { + throw new CompilerInputException( + ClassifyParserError(parsed.Errors), + string.Join("; ", parsed.Errors.Select(error => error.ToString())) + ); + } + + var symbols = new SortedSet(StringComparer.Ordinal); + AddSymbols(symbols, parsed.ParseOptions.PreprocessorSymbolNames); + if (profileSymbols is not null) + { + string[] missingSymbols = profileSymbols.Where(symbol => !symbols.Contains(symbol)).ToArray(); + if (missingSymbols.Length != 0) + { + throw new CompilerInputException( + "compiler-profile-symbol-mismatch", + $"Compiler arguments are missing profile symbols: {string.Join(", ", missingSymbols)}." + ); + } + } + + var sources = parsed + .SourceFiles.Select(source => new CompilerSourceClassification( + source.Path, + CompilerSourceKind.Owned, + ReadSourceContent(source.Path) + )) + .ToArray(); + var analyzers = parsed + .AnalyzerReferences.Select(reference => + AnalyzerMetadataInspector.Inspect(reference.FilePath, admittedSdkAnalyzerDirectories) + ) + .ToArray(); + string[] sourceGenerators = analyzers + .Where(analyzer => + analyzer.IsSourceGenerator + && analyzer.Disposition != AnalyzerDisposition.SdkOwnedSourceGeneratorPendingProbe + ) + .Select(analyzer => analyzer.Path) + .ToArray(); + if (sourceGenerators.Length != 0) + { + throw new CompilerInputException( + "unsupported-source-generator", + $"Source-generator analyzers are not supported: {string.Join(", ", sourceGenerators)}." + ); + } + + CompilerAuxiliaryInput[] additionalFiles = parsed + .AdditionalFiles.Select(file => ReadAuxiliaryInput(file.Path)) + .ToArray(); + CompilerAuxiliaryInput[] analyzerConfigs = parsed.AnalyzerConfigPaths.Select(ReadAuxiliaryInput).ToArray(); + return new CompilerInputModel(parsed, symbols.ToArray(), sources, analyzers, additionalFiles, analyzerConfigs); + } + + private static void VerifyToolchain(CompilerToolchainIdentity queried) + { + string csharpParserPath = typeof(CSharpCommandLineParser).Assembly.Location; + string commonParserPath = typeof(CommandLineArguments).Assembly.Location; + string directory = queried.CompilerDirectory; + if ( + string.IsNullOrWhiteSpace(directory) + || !Path.IsPathFullyQualified(directory) + || !Directory.Exists(directory) + ) + { + throw new CompilerInputException( + "incompatible-compiler-toolchain", + $"Queried compiler directory '{directory}' is not an existing absolute directory; parser is '{csharpParserPath}'." + ); + } + VerifyCompilerAssembly(directory, "Microsoft.CodeAnalysis.CSharp.dll", csharpParserPath); + VerifyCompilerAssembly(directory, "Microsoft.CodeAnalysis.dll", commonParserPath); + } + + private static void VerifyCompilerAssembly(string directory, string fileName, string parserPath) + { + string queriedPath = Path.Combine(directory, fileName); + if (!File.Exists(queriedPath) || !SameAssemblyContent(parserPath, queriedPath)) + { + throw new CompilerInputException( + "incompatible-compiler-toolchain", + $"Queried compiler '{queriedPath}' does not match parser '{parserPath}'." + ); + } + } + + private static bool SameAssemblyContent(string left, string right) + { + try + { + using FileStream leftStream = File.OpenRead(left); + using FileStream rightStream = File.OpenRead(right); + byte[] leftHash = SHA256.HashData(leftStream); + byte[] rightHash = SHA256.HashData(rightStream); + return leftHash.AsSpan().SequenceEqual(rightHash); + } + catch (Exception exception) when (exception is IOException or UnauthorizedAccessException) + { + return false; + } + } + + private static string ClassifyParserError(System.Collections.Immutable.ImmutableArray errors) => + errors.Any(error => + error.Id is "CS0006" or "CS0009" + || error.GetMessage().Contains("reference", StringComparison.OrdinalIgnoreCase) + || error.GetMessage().Contains("metadata file", StringComparison.OrdinalIgnoreCase) + ) + ? "reference-parser-diagnostic" + : errors.Any(error => + error.GetMessage().Contains("unrecognized", StringComparison.OrdinalIgnoreCase) + || error.GetMessage().Contains("unknown", StringComparison.OrdinalIgnoreCase) + ) + ? "unknown-compiler-switch" + : "compiler-parser-diagnostic"; + + private static void AddSymbols(ISet destination, IEnumerable symbols) + { + foreach (string symbol in symbols.Where(symbol => !string.IsNullOrWhiteSpace(symbol))) + destination.Add(symbol); + } + + private static ImmutableArray ReadSourceContent(string path) + { + try + { + return File.ReadAllBytes(path).ToImmutableArray(); + } + catch (Exception exception) when (exception is IOException or UnauthorizedAccessException) + { + throw new CompilerInputException( + "compiler-source-read-diagnostic", + $"Cannot read compiler source '{path}'.", + exception + ); + } + } + + private static CompilerAuxiliaryInput ReadAuxiliaryInput(string path) + { + try + { + string fullPath = Path.GetFullPath(path); + return new CompilerAuxiliaryInput(fullPath, File.ReadAllBytes(fullPath).ToImmutableArray()); + } + catch (Exception exception) when (exception is IOException or UnauthorizedAccessException) + { + throw new CompilerInputException( + "compiler-auxiliary-read-diagnostic", + $"Cannot read compiler auxiliary input '{path}'.", + exception + ); + } + } + + private static IReadOnlyCollection AdmittedSdkAnalyzerDirectories( + IReadOnlyList references + ) + { + var directories = new HashSet( + OperatingSystem.IsWindows() ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal + ); + foreach (CapturedCompilerItem reference in references) + { + string path = reference.Metadata.TryGetValue("FullPath", out string? fullPath) + ? fullPath + : reference.Identity; + string canonical = Path.GetFullPath(path); + string marker = + $"{Path.DirectorySeparatorChar}packs{Path.DirectorySeparatorChar}Microsoft.NETCore.App.Ref{Path.DirectorySeparatorChar}"; + int markerIndex = canonical.IndexOf( + marker, + OperatingSystem.IsWindows() ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal + ); + if (markerIndex < 0) + continue; + string packRoot = canonical[..(markerIndex + marker.Length)]; + string remainder = canonical[(markerIndex + marker.Length)..]; + string version = remainder.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)[0]; + if (!string.IsNullOrWhiteSpace(version)) + directories.Add(Path.Combine(packRoot, version, "analyzers", "dotnet", "cs")); + } + return directories; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpCompilationProfile.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpCompilationProfile.cs new file mode 100644 index 000000000..cdfa6b14f --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpCompilationProfile.cs @@ -0,0 +1,180 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Single authority for the references and identity used by the C# census. +internal sealed class CSharpCompilationProfile +{ + private readonly IReadOnlyList _references; + + private CSharpCompilationProfile(IReadOnlyList references, IReadOnlyList unresolved) + { + _references = references; + _unresolvedReferences = unresolved; + } + + private readonly IReadOnlyList _unresolvedReferences; + + public static CSharpCompilationProfile Create() => Create(Array.Empty()); + + /// Builds the census reference set, omitting every project in + /// . + /// A project whose sources are compiled in full must not also be referenced as a built + /// assembly, or every type it declares exists twice. A partially censused project must keep its + /// reference, because the files the source set omits are only there. + public static CSharpCompilationProfile Create(IReadOnlyCollection completeProjects) + { + ArgumentNullException.ThrowIfNull(completeProjects); + var censusedAssemblies = new HashSet(completeProjects, StringComparer.OrdinalIgnoreCase); + var paths = new HashSet(StringComparer.OrdinalIgnoreCase); + var assemblies = new HashSet(StringComparer.OrdinalIgnoreCase); + var unresolved = new SortedSet(StringComparer.Ordinal); + var queue = new Queue( + new[] + { + typeof(object).Assembly, + typeof(System.Xml.Linq.XElement).Assembly, + typeof(XmlLanguageLoader).Assembly, + typeof(SIL.Machine.Rules.IRule<,>).Assembly, + typeof(CSharpInventoryReader).Assembly, + } + ); + + while (queue.Count != 0) + { + Assembly assembly = queue.Dequeue(); + string identity = assembly.FullName ?? assembly.GetName().Name ?? ""; + if (!assemblies.Add(identity)) + continue; + + if ( + !string.IsNullOrEmpty(assembly.Location) + && File.Exists(assembly.Location) + && !censusedAssemblies.Contains(assembly.GetName().Name ?? string.Empty) + ) + { + paths.Add(Path.GetFullPath(assembly.Location)); + } + + foreach (AssemblyName name in assembly.GetReferencedAssemblies()) + { + try + { + queue.Enqueue(Assembly.Load(name)); + } + catch (FileNotFoundException) + { + unresolved.Add(name.FullName ?? name.Name ?? ""); + } + catch (FileLoadException) + { + unresolved.Add(name.FullName ?? name.Name ?? ""); + } + catch (BadImageFormatException) + { + unresolved.Add(name.FullName ?? name.Name ?? ""); + } + } + } + + if (AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string trustedPlatformAssemblies) + { + foreach (string path in trustedPlatformAssemblies.Split(Path.PathSeparator)) + { + string name = Path.GetFileNameWithoutExtension(path); + if (File.Exists(path) && IsFrameworkReference(name)) + paths.Add(Path.GetFullPath(path)); + } + } + + var references = paths + .OrderBy(path => path, StringComparer.OrdinalIgnoreCase) + .Select(ReferenceIdentity.Read) + .OrderBy(reference => reference.Identity, StringComparer.Ordinal) + .ThenBy(reference => reference.Path, StringComparer.OrdinalIgnoreCase) + .ToArray(); + if (references.Length == 0) + throw new InvalidOperationException("The C# census compilation profile contains no metadata references."); + return new CSharpCompilationProfile(references, unresolved.ToArray()); + } + + public IEnumerable CreateMetadataReferences() => + _references.Select(reference => MetadataReference.CreateFromFile(reference.Path)); + + public string Fingerprint() + { + var text = new StringBuilder() + .Append("runtime=") + .Append(RuntimeInformation.FrameworkDescription) + .Append('\n') + .Append("runtime-version=") + .Append(Environment.Version) + .Append('\n') + .Append("compiler=") + .Append(typeof(Microsoft.CodeAnalysis.CSharp.CSharpCompilation).Assembly.FullName) + .Append('\n') + .Append("analyzer-implementation=") + .Append(typeof(CSharpInventoryReader).Assembly.FullName) + .Append("|mvid=") + .Append(ModuleVersionId(typeof(CSharpInventoryReader).Assembly)) + .Append('\n'); + foreach (ReferenceIdentity reference in _references) + { + text.Append("metadata-reference=") + .Append(reference.Identity) + .Append("|mvid=") + .Append(reference.Mvid) + .Append('\n'); + } + foreach (string unresolved in _unresolvedReferences) + text.Append("unresolved-reference=").Append(unresolved).Append('\n'); + return text.ToString(); + } + + private static bool IsFrameworkReference(string name) => + name is "mscorlib" or "netstandard" or "System.Private.CoreLib" + || name.StartsWith("System.", StringComparison.Ordinal) + || name.StartsWith("Microsoft.", StringComparison.Ordinal); + + private static Guid ModuleVersionId(Assembly assembly) => assembly.ManifestModule.ModuleVersionId; + + private sealed record ReferenceIdentity(string Path, string Identity, Guid Mvid) + { + public static ReferenceIdentity Read(string path) + { + AssemblyName assemblyName; + Guid mvid; + try + { + assemblyName = AssemblyName.GetAssemblyName(path); + using var stream = File.OpenRead(path); + using var pe = new PEReader(stream); + MetadataReader metadata = pe.GetMetadataReader(); + mvid = metadata.GetGuid(metadata.GetModuleDefinition().Mvid); + } + catch (Exception ex) when (ex is IOException or BadImageFormatException or UnauthorizedAccessException) + { + throw new InvalidOperationException( + $"Cannot inspect C# metadata reference '{System.IO.Path.GetFileName(path)}'.", + ex + ); + } + + return new ReferenceIdentity( + path, + assemblyName.FullName ?? assemblyName.Name ?? System.IO.Path.GetFileName(path), + mvid + ); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpInventoryReader.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpInventoryReader.cs new file mode 100644 index 000000000..f011c69e5 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CSharpInventoryReader.cs @@ -0,0 +1,2647 @@ +#pragma warning disable IDE0011, IDE0200 +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal static class CSharpInventoryReader +{ + private const string Profile = "sil.machine.hc-semantic-catalog/v1"; + private const string XElementMetadata = "System.Xml.Linq.XElement"; + private const string XContainerMetadata = "System.Xml.Linq.XContainer"; + private const string XNameMetadata = "System.Xml.Linq.XName"; + private const string HcRuleMetadata = "SIL.Machine.Morphology.HermitCrab.IHCRule"; + private const string PhonRuleMetadata = "SIL.Machine.Morphology.HermitCrab.IPhonologicalRule"; + private const string MorphRuleMetadata = "SIL.Machine.Morphology.HermitCrab.IMorphologicalRule"; + private const string MachineRuleMetadata = "SIL.Machine.Rules.IRule`2"; + + private static readonly HashSet XmlNames = new(StringComparer.Ordinal) + { + "Element", + "Elements", + "Attribute", + }; + private static readonly HashSet DeclarationKinds = new() + { + SyntaxKind.ClassDeclaration, + SyntaxKind.StructDeclaration, + SyntaxKind.InterfaceDeclaration, + SyntaxKind.RecordDeclaration, + SyntaxKind.RecordStructDeclaration, + SyntaxKind.EnumDeclaration, + SyntaxKind.DelegateDeclaration, + SyntaxKind.MethodDeclaration, + SyntaxKind.ConstructorDeclaration, + SyntaxKind.DestructorDeclaration, + SyntaxKind.OperatorDeclaration, + SyntaxKind.ConversionOperatorDeclaration, + SyntaxKind.PropertyDeclaration, + SyntaxKind.IndexerDeclaration, + SyntaxKind.EventDeclaration, + SyntaxKind.EventFieldDeclaration, + SyntaxKind.FieldDeclaration, + SyntaxKind.VariableDeclarator, + SyntaxKind.GetAccessorDeclaration, + SyntaxKind.SetAccessorDeclaration, + SyntaxKind.AddAccessorDeclaration, + SyntaxKind.RemoveAccessorDeclaration, + SyntaxKind.InitAccessorDeclaration, + SyntaxKind.EnumMemberDeclaration, + SyntaxKind.LocalFunctionStatement, + }; + + public static SemanticInventory Read(IReadOnlyList inputs) => + Read(inputs, Array.Empty()); + + public static SemanticInventory Read( + IReadOnlyList inputs, + IReadOnlyCollection completeProjects + ) + { + ArgumentNullException.ThrowIfNull(inputs); + ArgumentNullException.ThrowIfNull(completeProjects); + SourceInput[] sources = inputs + .Select(input => input ?? throw new ArgumentException("C# source input cannot be null.", nameof(inputs))) + .Select(input => new SourceInput( + NormalizePath(input.RelativePath), + NormalizeSource(input.SourceText), + input.AuditedScopes + )) + .OrderBy(source => source.Path, StringComparer.Ordinal) + .ToArray(); + string[] duplicates = sources + .GroupBy(source => source.Path, StringComparer.Ordinal) + .Where(group => group.Count() > 1) + .Select(group => group.Key) + .OrderBy(path => path, StringComparer.Ordinal) + .ToArray(); + if (duplicates.Length != 0) + throw new ArgumentException($"Duplicate C# source paths: {string.Join(", ", duplicates)}", nameof(inputs)); + + ValidateScopePatterns(sources); + IReadOnlyList configurations = Configurations(); + CSharpCompilationProfile compilationProfile = CSharpCompilationProfile.Create(completeProjects); + var units = new List(configurations.Count); + foreach (CensusConfiguration configuration in configurations) + { + var parseOptions = CSharpParseOptions.Default.WithPreprocessorSymbols(configuration.Symbols); + SyntaxTree[] trees = sources + .Select(source => CSharpSyntaxTree.ParseText(source.Text, parseOptions, source.Path)) + .ToArray(); + foreach (SyntaxTree tree in trees) + { + Diagnostic? error = tree.GetDiagnostics() + .FirstOrDefault(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); + if (error is not null) + throw SyntaxError(error); + } + + CSharpCompilation compilation = CSharpCompilation.Create( + "HermitCrabSemanticCoverage_" + HashSources(sources)[..16], + trees, + compilationProfile.CreateMetadataReferences(), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + units.Add(new CensusUnit(configuration, compilation, sources, trees)); + } + + return Census(units, configurations, sources, compilationProfile.Fingerprint(), completeProjects.Count != 0); + } + + private static SemanticInventory Census( + IReadOnlyList units, + IReadOnlyList configurations, + SourceInput[] allSources, + string compilationFingerprint, + bool referencesAreExact + ) + { + var known = new HashSet(StringComparer.Ordinal); + var models = new Dictionary>(StringComparer.Ordinal); + var xml = new Dictionary>(StringComparer.Ordinal); + var decisions = new Dictionary>(StringComparer.Ordinal); + var diagnostics = new Dictionary>(StringComparer.Ordinal); + + foreach (CensusUnit unit in units) + { + CensusConfiguration configuration = unit.Configuration; + CSharpCompilation compilation = unit.Compilation; + SourceInput[] sources = unit.Sources; + var context = new SemanticContext(compilation, sources, unit.Trees, referencesAreExact); + context.BuildDeclarations(); + known.UnionWith(context.KnownSymbolIds()); + Diagnostic[] semanticErrors = compilation + .GetDiagnostics() + .Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + if (semanticErrors.Any(context.IsActionableCompilationError)) + context.AddCompilationErrors(semanticErrors); + else + context.BuildExecutionClosure(); + + var configured = new List(); + var configuredIds = new HashSet(StringComparer.Ordinal); + context.CollectModelSurfaces(configured, configuredIds); + foreach (InventorySurface surface in configured) + Merge(models, surface.Id, surface, configuration.Name); + foreach (ResolvedXml candidate in context.CollectXmlCandidates()) + Merge(xml, candidate.Key, candidate, configuration.Name); + foreach (ResolvedDecision candidate in context.CollectDecisionCandidates()) + Merge(decisions, candidate.Key, candidate, configuration.Name); + foreach (InventoryDiagnostic diagnostic in context.Diagnostics) + { + string key = $"{diagnostic.Code}\0{diagnostic.SubjectId}\0{diagnostic.Message}\0{diagnostic.Location}"; + Merge(diagnostics, key, diagnostic, configuration.Name); + } + } + + ValidateScopesResolve(allSources, known); + var surfaces = new List(); + var ids = new HashSet(StringComparer.Ordinal); + foreach ( + Availability entry in models.Values.OrderBy(item => item.Value.Id, StringComparer.Ordinal) + ) + Add(surfaces, ids, entry.Value with { Configurations = entry.Names }); + EmitXml(surfaces, ids, xml.Values); + EmitDecisions(surfaces, ids, decisions.Values); + InventoryDiagnostic[] orderedDiagnostics = diagnostics + .Values.OrderBy(entry => entry.Value.Code, StringComparer.Ordinal) + .ThenBy(entry => entry.Value.SubjectId, StringComparer.Ordinal) + .ThenBy(entry => entry.Value.Location, StringComparer.Ordinal) + .ThenBy(entry => entry.Value.Message, StringComparer.Ordinal) + .Select(entry => entry.Value with { Configurations = entry.Names }) + .ToArray(); + return new SemanticInventory( + Profile, + HashSources(allSources, configurations, compilationFingerprint, orderedDiagnostics), + InventorySurfaceFactory.Sort(surfaces), + orderedDiagnostics + ); + } + + private sealed record CensusUnit( + CensusConfiguration Configuration, + CSharpCompilation Compilation, + SourceInput[] Sources, + SyntaxTree[] Trees + ); + + /// Censuses the compilations the pinned compiler actually produced. + /// Every node of is already built from captured compiler + /// inputs with owned projects bound as compilation references, so no reference set is + /// approximated here and no error id is tolerated. + internal static SemanticInventory ReadFromGraph( + RoslynCompilationGraph graph, + RepositoryCompilationGraph captured, + string repositoryRoot, + IReadOnlyList censusedProjectIds, + IReadOnlyList auditedScopes + ) + { + ArgumentNullException.ThrowIfNull(graph); + ArgumentNullException.ThrowIfNull(captured); + ArgumentException.ThrowIfNullOrWhiteSpace(repositoryRoot); + ArgumentNullException.ThrowIfNull(censusedProjectIds); + ArgumentNullException.ThrowIfNull(auditedScopes); + if (censusedProjectIds.Count == 0) + throw new ArgumentException("At least one censused project is required.", nameof(censusedProjectIds)); + if (auditedScopes.Count == 0) + throw new ArgumentException("At least one audited scope is required.", nameof(auditedScopes)); + + string root = System.IO.Path.TrimEndingDirectorySeparator(System.IO.Path.GetFullPath(repositoryRoot)); + var configurations = new List(); + var units = new List(); + var allSources = new Dictionary(StringComparer.Ordinal); + + foreach (BuildProfile profile in captured.Profiles) + { + CensusConfiguration configuration = ConfigurationFor(profile); + configurations.Add(configuration); + bool scopesAssigned = false; + foreach (string projectId in censusedProjectIds) + { + RepositoryGraphNode node = + captured.Nodes.FirstOrDefault(item => + StringComparer.Ordinal.Equals(item.ProjectId, projectId) + && StringComparer.Ordinal.Equals(item.Profile.Id, profile.Id) + ) + ?? throw new ArgumentException( + $"The compilation graph has no node for project '{projectId}' in profile '{profile.Id}'.", + nameof(censusedProjectIds) + ); + + CSharpCompilation compilation = graph[node.Key].Compilation; + SyntaxTree[] trees = compilation.SyntaxTrees.ToArray(); + var sources = new SourceInput[trees.Length]; + for (int index = 0; index < trees.Length; index++) + { + IReadOnlyList scopes = + !scopesAssigned && index == 0 ? auditedScopes : Array.Empty(); + sources[index] = new SourceInput( + RepositoryRelativePath(trees[index].FilePath, root), + NormalizeSource(trees[index].GetText().ToString()), + scopes + ); + allSources[sources[index].Path] = sources[index]; + } + + scopesAssigned = true; + units.Add(new CensusUnit(configuration, compilation, sources, trees)); + } + } + + SourceInput[] ordered = allSources.Values.OrderBy(source => source.Path, StringComparer.Ordinal).ToArray(); + ValidateScopePatterns(ordered); + return Census(units, configurations, ordered, captured.Hashes.GraphHash, referencesAreExact: true); + } + + private static CensusConfiguration ConfigurationFor(BuildProfile profile) + { + string[] symbols = profile.AdditionalSymbols.OrderBy(symbol => symbol, StringComparer.Ordinal).ToArray(); + return new CensusConfiguration(symbols.Length == 0 ? "base" : string.Join("+", symbols), symbols); + } + + private static string RepositoryRelativePath(string path, string repositoryRoot) + { + string full = System.IO.Path.GetFullPath(path); + return NormalizePath( + full.StartsWith(repositoryRoot, StringComparison.OrdinalIgnoreCase) + ? System.IO.Path.GetRelativePath(repositoryRoot, full) + : full + ); + } + + // HermitCrab compiles under these symbols, so a single-configuration census cannot + // see a decision that exists only when one is defined. + private static readonly string[] ConditionalSymbols = { "OUTPUT_ANALYSES", "SINGLE_THREADED" }; + + private static IReadOnlyList Configurations() + { + var configurations = new List(); + for (int mask = 0; mask < 1 << ConditionalSymbols.Length; mask++) + { + string[] symbols = ConditionalSymbols + .Where((_, index) => (mask & (1 << index)) != 0) + .OrderBy(symbol => symbol, StringComparer.Ordinal) + .ToArray(); + configurations.Add( + new CensusConfiguration(symbols.Length == 0 ? "base" : string.Join("+", symbols), symbols) + ); + } + return configurations.OrderBy(configuration => configuration.Name, StringComparer.Ordinal).ToArray(); + } + + private static void ValidateScopePatterns(IEnumerable sources) + { + foreach (SourceInput source in sources) + foreach (string scope in source.Scopes) + if (ScopeValidation.HasPattern(scope)) + throw new ArgumentException($"Audited scope '{scope}' must be exact; patterns are not allowed."); + } + + // A scope naming a symbol that exists in only one configuration is still exact. + private static void ValidateScopesResolve(IEnumerable sources, HashSet known) + { + foreach (SourceInput source in sources) + foreach (string scope in source.Scopes) + if (!known.Contains(scope)) + throw new ArgumentException($"{source.Path}: unknown audited source scope '{scope}'."); + } + + private static void Add(List surfaces, HashSet ids, InventorySurface surface) + { + if (!ids.Add(surface.Id)) + throw new InvalidOperationException($"Duplicate generated surface ID '{surface.Id}'."); + surfaces.Add(surface); + } + + private static void Merge(Dictionary> merged, string key, T value, string configuration) + { + if (merged.TryGetValue(key, out Availability? existing)) + existing.Add(configuration); + else + merged.Add(key, new Availability(value, configuration)); + } + + private static void EmitXml( + List surfaces, + HashSet ids, + IEnumerable> entries + ) + { + var counters = new Dictionary(StringComparer.Ordinal); + foreach ( + Availability entry in entries + .OrderBy(item => item.Value.Parent, StringComparer.Ordinal) + .ThenBy(item => item.Value.Method, StringComparer.Ordinal) + .ThenBy(item => item.Value.Path, StringComparer.Ordinal) + .ThenBy(item => item.Value.SpanStart) + ) + { + ResolvedXml candidate = entry.Value; + string group = $"{candidate.Parent}\0{candidate.Method}"; + int ordinal = counters.TryGetValue(group, out int used) ? used : 0; + counters[group] = ordinal + 1; + string id = candidate.Kind switch + { + "xml-read" => + $"loader:{candidate.Parent}/{candidate.Method}/{CanonicalIdCodec.Encode(candidate.Constant!)}#{ordinal}", + "xml-all-elements" => $"loader:{candidate.Parent}/{candidate.Method}/xml-all-elements#{ordinal}", + "dynamic-xml-access" => $"source:dynamic-xml-access/{candidate.Parent}/{candidate.Method}#{ordinal}", + _ => $"source:unresolved-xml-access/{candidate.Parent}/{candidate.Method}#{ordinal}", + }; + Add( + surfaces, + ids, + new InventorySurface( + id, + candidate.Kind, + candidate.Constant ?? candidate.Method, + candidate.Parent, + candidate.Location, + candidate.Value, + entry.Names + ) + ); + } + } + + private static void EmitDecisions( + List surfaces, + HashSet ids, + IEnumerable> entries + ) + { + var counters = new Dictionary(StringComparer.Ordinal); + foreach ( + Availability entry in entries + .OrderBy(item => item.Value.Parent, StringComparer.Ordinal) + .ThenBy(item => item.Value.Kind, StringComparer.Ordinal) + .ThenBy(item => item.Value.Path, StringComparer.Ordinal) + .ThenBy(item => item.Value.SpanStart) + .ThenBy(item => item.Value.Branch, StringComparer.Ordinal) + ) + { + ResolvedDecision candidate = entry.Value; + string group = $"{candidate.Parent}\0{candidate.Kind}"; + int ordinal = counters.TryGetValue(group, out int used) ? used : 0; + counters[group] = ordinal + 1; + Add( + surfaces, + ids, + new InventorySurface( + $"decision:{candidate.Parent}/{candidate.Kind}/{candidate.Branch}#{ordinal}-{candidate.Fingerprint}", + // The branch is part of the canonical ID and name, but the surface kind denotes + // the audited construct. This keeps the two outcomes of one if/switch decision + // together for catalog policies while retaining both obligations exactly once. + $"decision-{candidate.Kind}", + $"{candidate.Parent}/{candidate.Kind}/{candidate.Branch}", + candidate.Parent, + candidate.Location, + null, + entry.Names + ) + ); + } + } + + private static string NormalizePath(string path) => path.Replace('\\', '/'); + + private static string NormalizeSource(string source) => + source.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n'); + + private static string HashSources(IEnumerable sources) => + HashSources(sources, Array.Empty(), string.Empty, Array.Empty()); + + // The configuration set is part of what the census covered, so widening it must + // change the hash the staleness gate compares. + private static string HashSources( + IEnumerable sources, + IReadOnlyList configurations, + string compilationFingerprint, + IReadOnlyList diagnostics + ) + { + var text = new StringBuilder(); + foreach (SourceInput source in sources.OrderBy(item => item.Path, StringComparer.Ordinal)) + { + text.Append(source.Path).Append('\0').Append(source.Text).Append('\0'); + foreach (string scope in source.Scopes.OrderBy(value => value, StringComparer.Ordinal)) + text.Append(scope).Append('\0'); + } + foreach (CensusConfiguration configuration in configurations) + text.Append(configuration.Name).Append('\0'); + text.Append("compilation\0").Append(compilationFingerprint).Append('\0'); + foreach ( + InventoryDiagnostic diagnostic in diagnostics + .OrderBy(item => item.Code, StringComparer.Ordinal) + .ThenBy(item => item.SubjectId, StringComparer.Ordinal) + .ThenBy(item => item.Location, StringComparer.Ordinal) + .ThenBy(item => item.Message, StringComparer.Ordinal) + ) + { + text.Append("diagnostic\0") + .Append(diagnostic.Code) + .Append('\0') + .Append(diagnostic.SubjectId) + .Append('\0') + .Append(diagnostic.Message) + .Append('\0') + .Append(diagnostic.Configurations) + .Append('\0') + .Append(diagnostic.Location) + .Append('\0'); + } + return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(text.ToString()))).ToLowerInvariant(); + } + + private static FormatException SyntaxError(Diagnostic diagnostic) + { + FileLinePositionSpan span = diagnostic.Location.GetLineSpan(); + string path = string.IsNullOrEmpty(span.Path) ? "" : span.Path; + return new FormatException( + $"{path}:{span.StartLinePosition.Line + 1}:{span.StartLinePosition.Character + 1}: {diagnostic.GetMessage()}" + ); + } + + private sealed record CensusConfiguration(string Name, IReadOnlyList Symbols); + + private sealed class Availability(T value, string configuration) + { + private readonly SortedSet _configurations = new(StringComparer.Ordinal) { configuration }; + + public T Value { get; } = value; + + public string Names => string.Join(",", _configurations); + + public void Add(string name) => _configurations.Add(name); + } + + private sealed record ResolvedXml( + string Parent, + string Method, + string? Constant, + string Kind, + string Path, + int SpanStart, + string Location, + string? Value + ) + { + public string Key => $"{Path}\0{SpanStart}\0{Parent}\0{Method}\0{Kind}\0{Constant}"; + } + + private sealed record ResolvedDecision( + string Parent, + string Kind, + string Branch, + string Path, + int SpanStart, + string Fingerprint, + string Location + ) + { + public string Key => $"{Path}\0{SpanStart}\0{Parent}\0{Kind}\0{Branch}\0{Fingerprint}"; + } + + private sealed record SourceInput(string Path, string Text, IReadOnlyList Scopes); + + private sealed record Declaration(ISymbol Symbol, SyntaxNode Node, SourceInput Source, SemanticModel Model); + + private sealed record DelegateTarget(ISymbol Symbol, string Location); + + private sealed record XmlCandidate( + string Parent, + string Method, + string? Constant, + string Kind, + SyntaxNode Node, + SourceInput Source, + string? Value + ); + + private sealed record DecisionCandidate( + string Parent, + string Kind, + string Branch, + SyntaxNode Node, + SourceInput Source + ); + + private sealed class SemanticContext + { + private readonly CSharpCompilation _compilation; + private readonly SourceInput[] _sources; + private readonly Dictionary _sourceByTree = new(); + private readonly Dictionary _models = new(); + private readonly List _declarations = new(); + private readonly Dictionary _symbolsById = new(StringComparer.Ordinal); + private readonly Dictionary _symbolIds = new(SymbolEqualityComparer.Default); + private readonly Dictionary _typeIds = new(SymbolEqualityComparer.Default); + private readonly Dictionary _localFunctionOrdinals = new(SymbolEqualityComparer.Default); + private readonly Dictionary _anonymousFunctionOrdinals = new(StringComparer.Ordinal); + private readonly List _xml = new(); + private readonly List _decisions = new(); + private readonly HashSet _reachable = new(StringComparer.Ordinal); + private readonly List _diagnostics = new(); + private readonly Dictionary _localDelegates = new(SymbolEqualityComparer.Default); + private readonly Dictionary _parameterDelegates = new(StringComparer.Ordinal); + private readonly HashSet _escapedLocals = new(SymbolEqualityComparer.Default); + private readonly bool _referencesAreExact; + + /// Errors a partial source set provokes by resolving against built assemblies + /// instead of the files it omits. Meaningless as defect signal there, and never tolerated + /// once the source set carries whole projects. + private static readonly HashSet ApproximationOnlyErrorIds = new(StringComparer.Ordinal) + { + "CS0122", + "CS0126", + "CS0200", + "CS0246", + "CS0311", + "CS0535", + "CS1061", + "CS1503", + }; + + private bool HasAuditedScopes => _sources.Any(source => source.Scopes.Count != 0); + + public IReadOnlyList Diagnostics => _diagnostics; + + public SemanticContext( + CSharpCompilation compilation, + SourceInput[] sources, + SyntaxTree[] trees, + bool referencesAreExact + ) + { + _compilation = compilation; + _sources = sources; + _referencesAreExact = referencesAreExact; + for (int i = 0; i < trees.Length; i++) + { + _sourceByTree.Add(trees[i], sources[i]); + _models.Add(trees[i], compilation.GetSemanticModel(trees[i], ignoreAccessibility: false)); + } + } + + public void BuildDeclarations() + { + foreach ( + (SyntaxTree tree, SourceInput source) in _sourceByTree.OrderBy( + pair => pair.Value.Path, + StringComparer.Ordinal + ) + ) + { + SemanticModel model = _models[tree]; + foreach (SyntaxNode node in tree.GetRoot().DescendantNodesAndSelf()) + { + if (!DeclarationKinds.Contains(node.Kind())) + continue; + ISymbol? symbol = model.GetDeclaredSymbol(node); + if (symbol is null || !IsSourceSymbol(symbol)) + continue; + _declarations.Add(new Declaration(symbol, node, source, model)); + } + + // Anonymous functions are executable source symbols too. They are registered + // separately because Roslyn does not expose them through GetDeclaredSymbol on + // every compiler version, while their IOperation always carries the symbol. + foreach ( + AnonymousFunctionExpressionSyntax lambda in tree.GetRoot() + .DescendantNodes() + .OfType() + ) + { + if ( + model.GetOperation(lambda) is not IAnonymousFunctionOperation operation + || !IsSourceSymbol(operation.Symbol) + ) + continue; + if ( + !_declarations.Any(item => SymbolEqualityComparer.Default.Equals(item.Symbol, operation.Symbol)) + ) + _declarations.Add(new Declaration(operation.Symbol, lambda, source, model)); + } + } + // Expression-bodied and auto properties expose compiler-generated accessors whose + // declared syntax is the property itself. Register those source accessors against + // that declaration so a property reference can enter the getter body exactly like an + // explicit accessor declaration. + foreach (Declaration declaration in _declarations.ToArray()) + { + switch (declaration.Symbol) + { + case IPropertySymbol property: + AddSyntheticAccessor(property.GetMethod, declaration); + AddSyntheticAccessor(property.SetMethod, declaration); + break; + case IEventSymbol @event: + AddSyntheticAccessor(@event.AddMethod, declaration); + AddSyntheticAccessor(@event.RemoveMethod, declaration); + break; + } + } + AssignLocalFunctionOrdinals(); + // Register every source symbol, not just types. Exact audits may target an + // overload, accessor, operator, destructor, or local function. + foreach ( + ISymbol symbol in _declarations + .Select(item => item.Symbol) + .Distinct(SymbolEqualityComparer.Default) + .OrderBy(CanonicalSymbolId, StringComparer.Ordinal) + ) + { + string id = CanonicalSymbolId(symbol); + if (_symbolsById.TryGetValue(id, out ISymbol? existing)) + { + if (AreMergedPartialSymbols(existing, symbol)) + continue; + throw new InvalidOperationException($"Duplicate canonical C# symbol ID '{id}'."); + } + + _symbolsById.Add(id, symbol); + } + ValidateRelevantRuleBases(); + } + + private void AddSyntheticAccessor(IMethodSymbol? accessor, Declaration propertyDeclaration) + { + if ( + accessor is null + || !IsSourceSymbol(accessor) + || _declarations.Any(item => SymbolEqualityComparer.Default.Equals(item.Symbol, accessor)) + ) + return; + _declarations.Add(propertyDeclaration with { Symbol = accessor }); + } + + private void ValidateRelevantRuleBases() + { + foreach ( + (SyntaxTree tree, SourceInput source) in _sourceByTree.OrderBy( + pair => pair.Value.Path, + StringComparer.Ordinal + ) + ) + { + SemanticModel model = _models[tree]; + foreach (BaseTypeSyntax baseType in tree.GetRoot().DescendantNodes().OfType()) + { + string terminal = baseType.Type.ToString().Split('.').Last().Split('<').First(); + bool relevant = + terminal is "IHCRule" or "IPhonologicalRule" or "IMorphologicalRule" or "IRule" + || IsUnresolvedAlias( + model, + baseType.Type, + "IHCRule", + "IPhonologicalRule", + "IMorphologicalRule", + "IRule" + ); + if (relevant && IsUnresolvedSymbol(model.GetSymbolInfo(baseType.Type).Symbol)) + throw new FormatException( + $"{source.Path}: unresolved relevant rule interface '{baseType.Type}'." + ); + } + } + } + + private void AssignLocalFunctionOrdinals() + { + IMethodSymbol[] localFunctions = _declarations + .Select(declaration => declaration.Symbol) + .OfType() + .Where(method => method.MethodKind == MethodKind.LocalFunction) + .Distinct(SymbolEqualityComparer.Default) + .Cast() + .ToArray(); + foreach ( + IGrouping level in localFunctions + .GroupBy(LocalFunctionNestingDepth) + .OrderBy(group => group.Key) + ) + { + foreach ( + IGrouping collision in level + .GroupBy(LocalFunctionBaseId, StringComparer.Ordinal) + .Where(group => group.Count() > 1) + ) + { + int ordinal = 0; + foreach ( + IMethodSymbol method in collision + .OrderBy(LocalFunctionSourcePath, StringComparer.Ordinal) + .ThenBy(LocalFunctionSourceStart) + ) + { + _localFunctionOrdinals.Add(method, ordinal++); + } + } + } + + IMethodSymbol[] anonymousFunctions = _declarations + .Select(declaration => declaration.Symbol) + .OfType() + .Where(method => method.MethodKind == MethodKind.AnonymousFunction) + .Distinct(SymbolEqualityComparer.Default) + .Cast() + .ToArray(); + foreach ( + IGrouping level in anonymousFunctions + .Where(method => method.ContainingSymbol is not null) + .GroupBy(AnonymousFunctionNestingDepth) + .OrderBy(group => group.Key) + ) + { + foreach ( + IGrouping group in level.GroupBy( + method => CanonicalSymbolId(method.ContainingSymbol!), + StringComparer.Ordinal + ) + ) + { + int ordinal = 0; + foreach ( + IMethodSymbol method in group + .OrderBy(LocalFunctionSourcePath, StringComparer.Ordinal) + .ThenBy(LocalFunctionSourceStart) + ) + _anonymousFunctionOrdinals[AnonymousFunctionKey(method)] = ordinal++; + } + } + } + + private static int AnonymousFunctionNestingDepth(IMethodSymbol method) + { + int depth = 0; + for ( + ISymbol? current = method.ContainingSymbol; + current is IMethodSymbol containing && containing.MethodKind == MethodKind.AnonymousFunction; + current = current.ContainingSymbol + ) + depth++; + return depth; + } + + private string AnonymousFunctionKey(IMethodSymbol method) => + $"{CanonicalSymbolId(method.ContainingSymbol!)}\0{LocalFunctionSourcePath(method)}\0{LocalFunctionSourceStart(method)}"; + + private static int LocalFunctionNestingDepth(IMethodSymbol method) + { + int depth = 0; + for ( + ISymbol? current = method.ContainingSymbol; + current is IMethodSymbol containing && containing.MethodKind == MethodKind.LocalFunction; + current = current.ContainingSymbol + ) + depth++; + return depth; + } + + private string LocalFunctionBaseId(IMethodSymbol method) => + $"{CanonicalSymbolId(method.ContainingSymbol)}/local/{CallableName(method)}({Parameters(method)})"; + + private static string LocalFunctionSourcePath(IMethodSymbol method) => + method + .Locations.Where(location => location.IsInSource) + .Select(location => location.SourceTree?.FilePath ?? string.Empty) + .OrderBy(path => path, StringComparer.Ordinal) + .FirstOrDefault() + ?? string.Empty; + + private static int LocalFunctionSourceStart(IMethodSymbol method) => + method + .Locations.Where(location => location.IsInSource) + .Select(location => location.SourceSpan.Start) + .DefaultIfEmpty(-1) + .Min(); + + private static bool AreMergedPartialSymbols(ISymbol left, ISymbol right) + { + if (left is IMethodSymbol leftMethod && right is IMethodSymbol rightMethod) + { + return leftMethod.PartialDefinitionPart is not null + || leftMethod.PartialImplementationPart is not null + || rightMethod.PartialDefinitionPart is not null + || rightMethod.PartialImplementationPart is not null; + } + + if (left is not INamedTypeSymbol || right is not INamedTypeSymbol) + return false; + return left.DeclaringSyntaxReferences.Any(IsPartialTypeDeclaration) + && right.DeclaringSyntaxReferences.Any(IsPartialTypeDeclaration); + } + + private static bool IsPartialTypeDeclaration(SyntaxReference reference) => + reference.GetSyntax() is TypeDeclarationSyntax declaration + && declaration.Modifiers.Any(SyntaxKind.PartialKeyword); + + public IEnumerable KnownSymbolIds() => _symbolsById.Keys; + + public bool IsActionableCompilationError(Diagnostic diagnostic) => + diagnostic.Location.IsInSource + && diagnostic.Location.SourceTree is not null + && IsInsideAuditedScope(diagnostic) + && (_referencesAreExact || !ApproximationOnlyErrorIds.Contains(diagnostic.Id)); + + /// The model for , or null when the tree belongs to a + /// referenced compilation rather than this one. + /// Owned projects are bound as compilation references, so a symbol reached from + /// this compilation can carry syntax this context has no model for. Such a symbol is + /// outside the censused source and is not followed. + private SemanticModel? ModelOrNull(SyntaxTree tree) => + _models.TryGetValue(tree, out SemanticModel? model) ? model : null; + + private bool IsInsideAuditedScope(Diagnostic diagnostic) + { + if (!diagnostic.Location.IsInSource || diagnostic.Location.SourceTree is null) + return false; + SemanticModel? model = ModelOrNull(diagnostic.Location.SourceTree); + if (model is null) + return false; + ISymbol? containing = model.GetEnclosingSymbol(diagnostic.Location.SourceSpan.Start); + while (containing is not null) + { + string containingId = CanonicalSymbolId(containing); + foreach (string scope in _sources.SelectMany(source => source.Scopes)) + { + if (StringComparer.Ordinal.Equals(scope, containingId)) + return true; + if ( + _symbolsById.TryGetValue(scope, out ISymbol? root) + && root is INamedTypeSymbol rootType + && IsWithinType(containing, rootType) + ) + return true; + } + + containing = containing.ContainingSymbol; + } + + return false; + } + + public void AddCompilationErrors(IEnumerable errors) + { + foreach (Diagnostic error in errors) + { + if (!IsActionableCompilationError(error)) + continue; + string location = error.Location.IsInSource + ? Location( + error.Location.SourceTree!, + error.Location.SourceSpan, + _sourceByTree[error.Location.SourceTree!] + ) + : ""; + AddDiagnostic("compilation-error", "compilation", error.GetMessage(), location); + } + } + + public void BuildExecutionClosure() + { + if (!HasAuditedScopes) + return; + var pending = new SortedSet(StringComparer.Ordinal); + foreach (string scope in _sources.SelectMany(source => source.Scopes).Distinct(StringComparer.Ordinal)) + { + if (_symbolsById.TryGetValue(scope, out ISymbol? symbol)) + AddReachable(symbol, pending, expandType: symbol is INamedTypeSymbol); + } + + while (pending.Count != 0) + { + string id = pending.Min!; + pending.Remove(id); + if (!_symbolsById.TryGetValue(id, out ISymbol? symbol)) + continue; + ProcessReachableSymbol(symbol, pending); + } + } + + private void ProcessReachableSymbol(ISymbol symbol, SortedSet pending) + { + foreach ( + Declaration declaration in _declarations + .Where(item => + StringComparer.Ordinal.Equals(CanonicalSymbolId(item.Symbol), CanonicalSymbolId(symbol)) + ) + .OrderBy(item => item.Source.Path, StringComparer.Ordinal) + .ThenBy(item => item.Node.SpanStart) + ) + { + _localDelegates.Clear(); + _escapedLocals.Clear(); + SeedParameterDelegates(symbol); + IOperation? operation = ExecutableOperation(declaration); + if (operation is IAnonymousFunctionOperation anonymous) + operation = anonymous.Body; + if (operation is not null) + ProcessOperation(operation, CanonicalSymbolId(symbol), pending); + if (symbol is IMethodSymbol { MethodKind: MethodKind.Constructor } constructorSymbol) + { + ProcessInstanceInitializers(constructorSymbol.ContainingType, CanonicalSymbolId(symbol), pending); + AddConstructorEdges(constructorSymbol, pending); + } + else if (symbol is IMethodSymbol { MethodKind: MethodKind.StaticConstructor } staticConstructor) + { + ProcessStaticInitializers(staticConstructor.ContainingType, CanonicalSymbolId(symbol), pending); + } + } + } + + private void SeedParameterDelegates(ISymbol symbol) + { + if (symbol is not IMethodSymbol method) + return; + foreach (IParameterSymbol parameter in method.Parameters) + { + if (_parameterDelegates.TryGetValue(ParameterBindingKey(method, parameter), out DelegateTarget? target)) + _localDelegates[parameter] = target; + } + } + + private void ProcessStaticInitializers(INamedTypeSymbol? type, string callerId, SortedSet pending) + { + if (type is null) + return; + foreach ( + Declaration declaration in _declarations + .Where(item => + item.Symbol switch + { + IFieldSymbol field => field.IsStatic + && SymbolEqualityComparer.Default.Equals( + field.ContainingType?.OriginalDefinition, + type.OriginalDefinition + ), + IPropertySymbol property => property.IsStatic + && SymbolEqualityComparer.Default.Equals( + property.ContainingType?.OriginalDefinition, + type.OriginalDefinition + ), + _ => false, + } + ) + .OrderBy(item => item.Source.Path, StringComparer.Ordinal) + .ThenBy(item => item.Node.SpanStart) + ) + { + AddReachable(declaration.Symbol, pending); + IOperation? initializer = ExecutableOperation(declaration); + if (initializer is not null) + ProcessOperation(initializer, callerId, pending); + } + } + + private void AddStaticInitialization(INamedTypeSymbol? type, SortedSet pending) + { + if (type is null) + return; + foreach ( + IMethodSymbol constructor in _symbolsById + .Values.OfType() + .Where(method => + method.MethodKind == MethodKind.StaticConstructor + && SymbolEqualityComparer.Default.Equals( + method.ContainingType?.OriginalDefinition, + type.OriginalDefinition + ) + ) + ) + { + AddReachable(constructor, pending); + } + } + + private void ProcessInstanceInitializers(INamedTypeSymbol? type, string callerId, SortedSet pending) + { + if (type is null) + return; + foreach ( + Declaration declaration in _declarations + .Where(item => + item.Symbol switch + { + IFieldSymbol field => !field.IsStatic + && SymbolEqualityComparer.Default.Equals( + field.ContainingType?.OriginalDefinition, + type.OriginalDefinition + ), + IPropertySymbol property => !property.IsStatic + && SymbolEqualityComparer.Default.Equals( + property.ContainingType?.OriginalDefinition, + type.OriginalDefinition + ), + _ => false, + } + ) + .OrderBy(item => item.Source.Path, StringComparer.Ordinal) + .ThenBy(item => item.Node.SpanStart) + ) + { + AddReachable(declaration.Symbol, pending); + IOperation? initializer = ExecutableOperation(declaration); + if (initializer is not null) + ProcessOperation(initializer, callerId, pending); + } + } + + private void AddConstructorEdges(IMethodSymbol constructor, SortedSet pending) + { + ConstructorDeclarationSyntax? syntax = constructor + .DeclaringSyntaxReferences.Select(reference => reference.GetSyntax()) + .OfType() + .FirstOrDefault(node => ModelOrNull(node.SyntaxTree) is not null); + ConstructorInitializerSyntax? initializer = syntax?.Initializer; + IMethodSymbol? explicitTarget = initializer is null + ? null + : ModelOrNull(initializer.SyntaxTree)?.GetSymbolInfo(initializer).Symbol as IMethodSymbol; + if (explicitTarget is not null) + { + // Both this(...) and base(...) constructor initializers are exact calls. + if (initializer is not null) + foreach (ArgumentSyntax argument in initializer.ArgumentList.Arguments) + ProcessOperation( + ModelOrNull(argument.SyntaxTree)!.GetOperation(argument.Expression)!, + CanonicalSymbolId(constructor), + pending + ); + AddReachable(explicitTarget, pending); + return; + } + + INamedTypeSymbol? baseType = constructor.ContainingType?.BaseType; + if (baseType is null || baseType.SpecialType == SpecialType.System_Object) + return; + foreach ( + IMethodSymbol baseConstructor in _symbolsById + .Values.OfType() + .Where(candidate => + candidate.MethodKind == MethodKind.Constructor + && candidate.Parameters.Length == 0 + && candidate.ContainingType is not null + && SymbolEqualityComparer.Default.Equals( + candidate.ContainingType.OriginalDefinition, + baseType.OriginalDefinition + ) + ) + .OrderBy(CanonicalSymbolId, StringComparer.Ordinal) + ) + AddReachable(baseConstructor, pending); + } + + private static IOperation? ExecutableOperation(Declaration declaration) => + declaration.Node switch + { + MethodDeclarationSyntax method when method.Body is not null => declaration.Model.GetOperation( + method.Body + ), + MethodDeclarationSyntax method when method.ExpressionBody is not null => declaration.Model.GetOperation( + method.ExpressionBody.Expression + ), + ConstructorDeclarationSyntax constructor when constructor.Body is not null => + declaration.Model.GetOperation(constructor.Body), + ConstructorDeclarationSyntax constructor when constructor.ExpressionBody is not null => + declaration.Model.GetOperation(constructor.ExpressionBody.Expression), + DestructorDeclarationSyntax destructor when destructor.Body is not null => + declaration.Model.GetOperation(destructor.Body), + OperatorDeclarationSyntax op when op.Body is not null => declaration.Model.GetOperation(op.Body), + OperatorDeclarationSyntax op when op.ExpressionBody is not null => declaration.Model.GetOperation( + op.ExpressionBody.Expression + ), + ConversionOperatorDeclarationSyntax conversion when conversion.Body is not null => + declaration.Model.GetOperation(conversion.Body), + ConversionOperatorDeclarationSyntax conversion when conversion.ExpressionBody is not null => + declaration.Model.GetOperation(conversion.ExpressionBody.Expression), + AccessorDeclarationSyntax accessor when accessor.Body is not null => declaration.Model.GetOperation( + accessor.Body + ), + AccessorDeclarationSyntax accessor when accessor.ExpressionBody is not null => + declaration.Model.GetOperation(accessor.ExpressionBody.Expression), + PropertyDeclarationSyntax property when property.ExpressionBody is not null => + declaration.Model.GetOperation(property.ExpressionBody.Expression), + IndexerDeclarationSyntax indexer when indexer.ExpressionBody is not null => + declaration.Model.GetOperation(indexer.ExpressionBody.Expression), + PropertyDeclarationSyntax property when property.Initializer is not null => + declaration.Model.GetOperation(property.Initializer.Value), + LocalFunctionStatementSyntax local when local.Body is not null => declaration.Model.GetOperation( + local.Body + ), + LocalFunctionStatementSyntax local when local.ExpressionBody is not null => + declaration.Model.GetOperation(local.ExpressionBody.Expression), + AnonymousFunctionExpressionSyntax lambda => declaration.Model.GetOperation(lambda), + VariableDeclaratorSyntax variable when variable.Initializer is not null => + declaration.Model.GetOperation(variable.Initializer.Value), + VariableDeclaratorSyntax variable => declaration.Model.GetOperation(variable), + _ => null, + }; + + private void ProcessOperation(IOperation operation, string callerId, SortedSet pending) + { + // Nested functions are declarations, not execution edges. They are entered only by + // a delegate invocation or a source-bound method group handled below. + if (operation.Kind is OperationKind.AnonymousFunction or OperationKind.LocalFunction) + return; + + switch (operation) + { + case IInvocationOperation invocation: + if (invocation.Instance is not null) + ProcessOperation(invocation.Instance, callerId, pending); + foreach (IArgumentOperation argument in invocation.Arguments) + { + if (argument.Parameter?.Type is ITypeSymbol parameterType && IsDelegateType(parameterType)) + { + if (!IsSourceMethod(invocation.TargetMethod)) + FollowDelegateValue(argument.Value, callerId, pending, invocation); + else if ( + BindDelegateArgumentToConsumers( + invocation.TargetMethod, + invocation.Instance, + argument.Parameter, + argument.Value, + callerId, + invocation, + pending + ) + ) + { + // The consumed delegate is bound to each concrete implementation. + } + else + { + // Even an ignored delegate argument evaluates its factory or + // other non-direct expression, but its returned callback is not + // itself invoked. + if (!IsDirectDelegateValue(argument.Value)) + ProcessOperation(argument.Value, callerId, pending); + } + } + else + ProcessOperation(argument.Value, callerId, pending); + } + ResolveInvocation(invocation, callerId, pending); + return; + + case IObjectCreationOperation creation: + if (creation.Constructor is not null) + { + AddStaticInitialization(creation.Constructor.ContainingType, pending); + AddMethodTarget(creation.Constructor, creation, creation, callerId, pending); + if ( + creation.Constructor.MethodKind == MethodKind.Constructor + && !_symbolsById.ContainsKey(CanonicalSymbolId(creation.Constructor)) + ) + { + ProcessInstanceInitializers(creation.Constructor.ContainingType, callerId, pending); + AddConstructorEdges(creation.Constructor, pending); + } + } + foreach (IArgumentOperation argument in creation.Arguments) + ProcessOperation(argument.Value, callerId, pending); + if (creation.Initializer is not null) + ProcessOperation(creation.Initializer, callerId, pending); + return; + + case IPropertyReferenceOperation property: + if (property.Instance is not null) + ProcessOperation(property.Instance, callerId, pending); + if (property.Property.IsStatic) + AddStaticInitialization(property.Property.ContainingType, pending); + foreach (IArgumentOperation argument in property.Arguments) + ProcessOperation(argument.Value, callerId, pending); + bool writes = IsWriteAccess(property); + bool reads = !writes || IsReadWriteAccess(property); + if (reads && property.Property.GetMethod is IMethodSymbol getter) + AddExactOrDispatchTarget(getter, property.Instance, property, callerId, pending); + if (writes && property.Property.SetMethod is IMethodSymbol setter) + AddExactOrDispatchTarget(setter, property.Instance, property, callerId, pending); + if ( + (reads && property.Property.GetMethod is null) + || (writes && property.Property.SetMethod is null) + ) + AddDiagnostic( + "unresolved-interface-dispatch", + callerId, + "interface property accessor has no concrete source implementation", + property + ); + return; + + case IEventReferenceOperation @event: + if (@event.Instance is not null) + ProcessOperation(@event.Instance, callerId, pending); + if (@event.Event.IsStatic) + AddStaticInitialization(@event.Event.ContainingType, pending); + IMethodSymbol? eventAccessor = EventAccessor(@event); + if (eventAccessor is not null) + AddExactOrDispatchTarget(eventAccessor, @event.Instance, @event, callerId, pending); + return; + + case IFieldReferenceOperation field: + if (field.Instance is not null) + ProcessOperation(field.Instance, callerId, pending); + if (field.Field.IsStatic) + AddStaticInitialization(field.Field.ContainingType, pending); + AddReachable(field.Field, pending); + return; + + case IDynamicMemberReferenceOperation dynamicMember: + if (dynamicMember.Instance is not null) + ProcessOperation(dynamicMember.Instance, callerId, pending); + AddDiagnostic( + "unresolved-dynamic-member", + callerId, + $"dynamic member '{dynamicMember.MemberName}' cannot be closed statically", + dynamicMember + ); + return; + + case IDynamicIndexerAccessOperation dynamicIndexer: + ProcessOperation(dynamicIndexer.Operation, callerId, pending); + foreach (IOperation argument in dynamicIndexer.Arguments) + ProcessOperation(argument, callerId, pending); + AddDiagnostic( + "unresolved-dynamic-member", + callerId, + "dynamic indexer access cannot be closed statically", + dynamicIndexer + ); + return; + + case IDynamicInvocationOperation dynamicInvocation: + ProcessOperation(dynamicInvocation.Operation, callerId, pending); + foreach (IArgumentOperation argument in dynamicInvocation.Arguments) + ProcessOperation(argument.Value, callerId, pending); + if ( + dynamicInvocation.Operation is IDynamicMemberReferenceOperation member + && member.Instance is not null + ) + AddDiagnostic( + "unresolved-call-dispatch", + callerId, + "dynamic invocation receiver cannot be closed statically", + member.Instance + ); + else + AddDiagnostic( + "unresolved-call-dispatch", + callerId, + "dynamic invocation cannot be closed statically", + dynamicInvocation + ); + return; + + case IDynamicObjectCreationOperation dynamicCreation: + foreach (IArgumentOperation argument in dynamicCreation.Arguments) + ProcessOperation(argument.Value, callerId, pending); + if (dynamicCreation.Initializer is not null) + ProcessOperation(dynamicCreation.Initializer, callerId, pending); + AddDiagnostic( + "open-construction-dispatch", + callerId, + "dynamic object construction cannot be closed statically", + dynamicCreation + ); + return; + + case ITypeParameterObjectCreationOperation typeParameterCreation: + if (typeParameterCreation.Initializer is not null) + ProcessOperation(typeParameterCreation.Initializer, callerId, pending); + AddDiagnostic( + "open-construction-dispatch", + callerId, + "type-parameter construction cannot be closed statically", + typeParameterCreation + ); + return; + + case ISimpleAssignmentOperation assignment: + if (assignment.Target is ILocalReferenceOperation local && IsDelegateType(local.Local.Type)) + { + if (!IsDirectDelegateValue(assignment.Value)) + ProcessOperation(assignment.Value, callerId, pending); + RememberDelegate(local.Local, assignment.Value); + return; + } + ProcessOperation(assignment.Target, callerId, pending); + ProcessOperation(assignment.Value, callerId, pending); + return; + + case IVariableDeclaratorOperation variable when variable.Initializer is not null: + if (IsDelegateType(variable.Symbol.Type)) + { + if (!IsDirectDelegateValue(variable.Initializer.Value)) + ProcessOperation(variable.Initializer.Value, callerId, pending); + RememberDelegate(variable.Symbol, variable.Initializer.Value); + } + else + ProcessOperation(variable.Initializer.Value, callerId, pending); + return; + + case IDelegateCreationOperation delegateCreation: + // Delegate creation produces a value. Its body is entered only when a + // consuming callsite binds and invokes the delegate. + return; + + case IMethodReferenceOperation: + case ILocalFunctionOperation: + case IAnonymousFunctionOperation: + return; + + case IConditionalOperation conditional: + ProcessOperation(conditional.Condition, callerId, pending); + if (TryGetConstantBoolean(conditional.Condition, out bool condition)) + { + IOperation? selected = condition ? conditional.WhenTrue : conditional.WhenFalse; + if (selected is not null) + ProcessOperation(selected, callerId, pending); + } + else + { + if (conditional.WhenTrue is not null) + ProcessOperation(conditional.WhenTrue, callerId, pending); + if (conditional.WhenFalse is not null) + ProcessOperation(conditional.WhenFalse, callerId, pending); + } + return; + + case IBinaryOperation binary: + ProcessOperation(binary.LeftOperand, callerId, pending); + ProcessOperation(binary.RightOperand, callerId, pending); + if (binary.OperatorMethod is IMethodSymbol binaryMethod) + AddMethodTarget(binaryMethod, binary.LeftOperand, binary, callerId, pending); + return; + + case IUnaryOperation unary: + ProcessOperation(unary.Operand, callerId, pending); + if (unary.OperatorMethod is IMethodSymbol unaryMethod) + AddMethodTarget(unaryMethod, unary.Operand, unary, callerId, pending); + return; + + case IConversionOperation conversion: + ProcessOperation(conversion.Operand, callerId, pending); + if (conversion.Conversion.MethodSymbol is IMethodSymbol conversionMethod) + AddMethodTarget(conversionMethod, conversion.Operand, conversion, callerId, pending); + return; + + case IIncrementOrDecrementOperation increment: + ProcessOperation(increment.Target, callerId, pending); + if (increment.OperatorMethod is IMethodSymbol incrementMethod) + AddMethodTarget(incrementMethod, increment.Target, increment, callerId, pending); + return; + + case ICompoundAssignmentOperation compound: + ProcessOperation(compound.Target, callerId, pending); + ProcessOperation(compound.Value, callerId, pending); + if (compound.OperatorMethod is IMethodSymbol compoundMethod) + AddMethodTarget(compoundMethod, compound.Target, compound, callerId, pending); + return; + + default: + ReportUnresolvedInvocationSyntax(operation.Syntax, callerId); + foreach (IOperation child in operation.ChildOperations) + ProcessOperation(child, callerId, pending); + return; + } + } + + private void ResolveInvocation(IInvocationOperation invocation, string callerId, SortedSet pending) + { + IMethodSymbol method = invocation.TargetMethod; + if (IsDynamicInvocation(invocation)) + { + AddDiagnostic( + "unresolved-call-dispatch", + callerId, + "dynamic invocation target cannot be closed statically", + invocation + ); + return; + } + if (method.MethodKind == MethodKind.DelegateInvoke || method.ContainingType?.TypeKind == TypeKind.Delegate) + { + FollowDelegateValue(invocation.Instance, callerId, pending, invocation); + return; + } + + if (method is null || method.ContainingType?.TypeKind == TypeKind.Error) + { + AddDiagnostic( + "unresolved-call-dispatch", + callerId, + "invocation target cannot be closed statically", + invocation + ); + return; + } + + if (method.IsStatic && method.MethodKind != MethodKind.StaticConstructor) + AddStaticInitialization(method.ContainingType, pending); + + if (IsBaseReceiver(invocation)) + { + // A base-qualified call is an exact nonvirtual edge, even when the + // selected member is declared virtual. It must not fan out to overrides. + AddReachable(method, pending); + return; + } + + AddMethodTarget(method, invocation.Instance, invocation, callerId, pending); + } + + private void ReportUnresolvedInvocationSyntax(SyntaxNode node, string callerId) + { + foreach ( + InvocationExpressionSyntax syntax in node.DescendantNodesAndSelf().OfType() + ) + { + SemanticModel? model = ModelOrNull(syntax.SyntaxTree); + if (model is null || model.GetSymbolInfo(syntax).Symbol is not null) + continue; + if (IsDynamicSyntaxInvocation(syntax)) + { + AddDiagnostic( + "unresolved-call-dispatch", + callerId, + "dynamic invocation target cannot be closed statically", + syntax + ); + continue; + } + AddDiagnostic( + "unresolved-call-dispatch", + callerId, + "invocation target cannot be closed statically", + syntax + ); + } + } + + private static bool IsBaseReceiver(IInvocationOperation invocation) => + invocation.Syntax + is InvocationExpressionSyntax + { + Expression: MemberAccessExpressionSyntax { Expression: BaseExpressionSyntax } + }; + + private bool IsDynamicInvocation(IInvocationOperation invocation) + { + if (invocation.Instance?.Type?.TypeKind == TypeKind.Dynamic) + return true; + if (invocation.Syntax is not InvocationExpressionSyntax syntax) + return false; + ExpressionSyntax? receiver = syntax.Expression switch + { + MemberAccessExpressionSyntax member => member.Expression, + MemberBindingExpressionSyntax => syntax + .Ancestors() + .OfType() + .FirstOrDefault() + ?.Expression, + _ => null, + }; + return receiver is not null + && ModelOrNull(syntax.SyntaxTree)?.GetTypeInfo(receiver).Type?.TypeKind == TypeKind.Dynamic; + } + + private bool IsDynamicSyntaxInvocation(InvocationExpressionSyntax syntax) + { + ExpressionSyntax? receiver = syntax.Expression switch + { + MemberAccessExpressionSyntax member => member.Expression, + MemberBindingExpressionSyntax => syntax + .Ancestors() + .OfType() + .FirstOrDefault() + ?.Expression, + _ => null, + }; + return receiver is not null + && ModelOrNull(syntax.SyntaxTree)?.GetTypeInfo(receiver).Type?.TypeKind == TypeKind.Dynamic; + } + + private void AddMethodTarget( + IMethodSymbol method, + IOperation? receiver, + IOperation callsite, + string callerId, + SortedSet pending + ) + { + if ( + method.ContainingType?.TypeKind == TypeKind.Interface + || method.IsVirtual + || method.IsOverride + || method.IsAbstract + ) + { + IReadOnlyList targets = DispatchTargets(method, receiver); + if (targets.Count == 0) + { + string code = + method.ContainingType?.TypeKind == TypeKind.Interface + ? "unresolved-interface-dispatch" + : "external-virtual-dispatch"; + AddDiagnostic(code, callerId, "callsite has no concrete source dispatch target", callsite); + return; + } + foreach (IMethodSymbol target in targets) + AddReachable(target, pending); + if (method.ContainingType?.TypeKind == TypeKind.Interface) + MarkConcreteInterfaceReceivers(method, receiver, pending); + return; + } + + AddReachable(method, pending); + } + + private void MarkConcreteInterfaceReceivers( + IMethodSymbol interfaceMethod, + IOperation? receiver, + SortedSet pending + ) + { + INamedTypeSymbol? receiverType = receiver?.Type as INamedTypeSymbol; + IEnumerable types = _symbolsById + .Values.OfType() + .Where(type => type.TypeKind is TypeKind.Class or TypeKind.Struct && !type.IsAbstract); + if ( + receiverType is not null + && receiverType.TypeKind is TypeKind.Class or TypeKind.Struct + && !receiverType.IsAbstract + && _symbolsById.ContainsKey(CanonicalSymbolId(receiverType)) + ) + types = types.Where(type => IsSameOrDerived(type, receiverType)); + + foreach (INamedTypeSymbol type in types) + { + IMethodSymbol? implementation = + type.FindImplementationForInterfaceMember(interfaceMethod) as IMethodSymbol; + if ( + implementation is not null + && IsSourceSymbol(implementation) + && _symbolsById.ContainsKey(CanonicalSymbolId(implementation)) + ) + AddReachable(type, pending); + } + } + + private IReadOnlyList DispatchTargets(IMethodSymbol method, IOperation? receiver) + { + INamedTypeSymbol? receiverType = receiver?.Type as INamedTypeSymbol; + IEnumerable types = _symbolsById + .Values.OfType() + .Where(type => type.TypeKind is TypeKind.Class or TypeKind.Struct && !type.IsAbstract); + if ( + receiverType is not null + && receiverType.TypeKind is TypeKind.Class or TypeKind.Struct + && !receiverType.IsAbstract + && _symbolsById.ContainsKey(CanonicalSymbolId(receiverType)) + ) + types = types.Where(type => IsSameOrDerived(type, receiverType)); + + var targets = new Dictionary(StringComparer.Ordinal); + foreach (INamedTypeSymbol type in types.OrderBy(CanonicalTypeId, StringComparer.Ordinal)) + { + IMethodSymbol? target = + method.ContainingType?.TypeKind == TypeKind.Interface + ? type.FindImplementationForInterfaceMember(method) as IMethodSymbol + : FindOverride(type, method); + if ( + target is not null + && IsSourceSymbol(target) + && _symbolsById.ContainsKey(CanonicalSymbolId(target)) + && !target.IsAbstract + ) + targets[CanonicalSymbolId(target)] = target; + } + return targets.Values.OrderBy(CanonicalSymbolId, StringComparer.Ordinal).ToArray(); + } + + private static bool IsSameOrDerived(INamedTypeSymbol type, INamedTypeSymbol baseType) + { + for (INamedTypeSymbol? current = type; current is not null; current = current.BaseType) + if (SymbolEqualityComparer.Default.Equals(current.OriginalDefinition, baseType.OriginalDefinition)) + return true; + return false; + } + + private static IMethodSymbol? FindOverride(INamedTypeSymbol type, IMethodSymbol method) + { + foreach (IMethodSymbol candidate in type.GetMembers(method.Name).OfType()) + { + for (IMethodSymbol? current = candidate; current is not null; current = current.OverriddenMethod) + if (SymbolEqualityComparer.Default.Equals(current.OriginalDefinition, method.OriginalDefinition)) + return candidate; + } + return + method.ContainingType is not null + && SymbolEqualityComparer.Default.Equals( + type.OriginalDefinition, + method.ContainingType.OriginalDefinition + ) + ? method + : null; + } + + private void RememberDelegate(ILocalSymbol local, IOperation value) + { + if (TryGetDelegateTarget(value, out DelegateTarget? target)) + { + if (_localDelegates.ContainsKey(local)) + { + _localDelegates.Remove(local); + _escapedLocals.Add(local); + } + else if (!_escapedLocals.Contains(local)) + _localDelegates[local] = target!; + return; + } + _localDelegates.Remove(local); + _escapedLocals.Add(local); + } + + private bool IsDirectDelegateValue(IOperation value) => TryGetDelegateTarget(value, out _); + + private bool IsSourceMethod(IMethodSymbol method) => _symbolsById.ContainsKey(CanonicalSymbolId(method)); + + private bool SourceMethodConsumesDelegate(IMethodSymbol method, IParameterSymbol parameter) + { + foreach ( + Declaration declaration in _declarations.Where(item => + SymbolEqualityComparer.Default.Equals(item.Symbol, method) + || StringComparer.Ordinal.Equals(CanonicalSymbolId(item.Symbol), CanonicalSymbolId(method)) + ) + ) + { + IOperation? body = ExecutableOperation(declaration); + if (body is not null && OperationConsumesDelegate(body, parameter)) + return true; + } + + return false; + } + + private static bool OperationConsumesDelegate(IOperation operation, IParameterSymbol parameter) + { + if (operation.Kind is OperationKind.AnonymousFunction or OperationKind.LocalFunction) + return false; + if (operation is IInvocationOperation invocation) + { + if ( + invocation.Instance is IParameterReferenceOperation instance + && SymbolEqualityComparer.Default.Equals(instance.Parameter, parameter) + ) + return true; + if ( + invocation.Arguments.Any(argument => + argument.Value is IParameterReferenceOperation reference + && SymbolEqualityComparer.Default.Equals(reference.Parameter, parameter) + ) + ) + return true; + } + + return operation.ChildOperations.Any(child => OperationConsumesDelegate(child, parameter)); + } + + private bool BindDelegateArgumentToConsumers( + IMethodSymbol method, + IOperation? receiver, + IParameterSymbol parameter, + IOperation value, + string callerId, + IOperation callsite, + SortedSet pending + ) + { + IMethodSymbol[] targets = + method.ContainingType?.TypeKind == TypeKind.Interface + || method.IsVirtual + || method.IsOverride + || method.IsAbstract + ? DispatchTargets(method, receiver).ToArray() + : new[] { method }; + bool consumed = false; + foreach (IMethodSymbol target in targets) + { + if (!SourceMethodConsumesDelegate(target, DelegateParameter(target, parameter))) + continue; + consumed = true; + if (TryResolveDelegateValue(value, out DelegateTarget? delegateTarget)) + { + _parameterDelegates[ParameterBindingKey(target, DelegateParameter(target, parameter))] = + delegateTarget!; + AddReachable(delegateTarget!.Symbol, pending); + } + else + AddDelegateDiagnostic(callerId, callsite); + } + + return consumed; + } + + private static IParameterSymbol DelegateParameter(IMethodSymbol target, IParameterSymbol sourceParameter) => + target.Parameters.FirstOrDefault(parameter => parameter.Ordinal == sourceParameter.Ordinal) + ?? sourceParameter; + + private void AddExactOrDispatchTarget( + IMethodSymbol method, + IOperation? receiver, + IOperation callsite, + string callerId, + SortedSet pending + ) + { + if (IsBaseMemberAccess(callsite)) + { + AddReachable(method, pending); + return; + } + + AddMethodTarget(method, receiver, callsite, callerId, pending); + } + + private bool TryGetDelegateTarget(IOperation value, out DelegateTarget? target) + { + switch (value) + { + case IDelegateCreationOperation creation: + return TryGetDelegateTarget(creation.Target, out target); + case IAnonymousFunctionOperation anonymous: + target = new DelegateTarget(anonymous.Symbol, Location(anonymous)); + return true; + case IMethodReferenceOperation method: + target = new DelegateTarget(method.Method, Location(method)); + return true; + case IConversionOperation conversion: + return TryGetDelegateTarget(conversion.Operand, out target); + case IParenthesizedOperation parenthesized: + return TryGetDelegateTarget(parenthesized.Operand, out target); + default: + target = null; + return false; + } + } + + private void FollowDelegateValue( + IOperation? value, + string callerId, + SortedSet pending, + IOperation callsite + ) + { + if (value is null) + { + AddDelegateDiagnostic(callerId, callsite); + return; + } + value = Unwrap(value); + if ( + value is ILocalReferenceOperation local + && _localDelegates.TryGetValue(local.Local, out DelegateTarget? target) + ) + { + AddReachable(target.Symbol, pending); + return; + } + if ( + value is IParameterReferenceOperation parameter + && _localDelegates.TryGetValue(parameter.Parameter, out target) + ) + { + AddReachable(target.Symbol, pending); + return; + } + if (TryGetDelegateTarget(value, out DelegateTarget? direct)) + { + AddReachable(direct!.Symbol, pending); + return; + } + AddDelegateDiagnostic(callerId, callsite); + } + + private bool TryResolveDelegateValue(IOperation value, out DelegateTarget? target) + { + value = Unwrap(value); + if (value is ILocalReferenceOperation local && _localDelegates.TryGetValue(local.Local, out target)) + return true; + if ( + value is IParameterReferenceOperation parameter + && _localDelegates.TryGetValue(parameter.Parameter, out target) + ) + return true; + return TryGetDelegateTarget(value, out target); + } + + private string ParameterBindingKey(IMethodSymbol method, IParameterSymbol parameter) => + $"{CanonicalSymbolId(method)}\0{parameter.Ordinal}"; + + private static IOperation Unwrap(IOperation value) + { + while (value is IConversionOperation conversion) + value = conversion.Operand; + return value is IParenthesizedOperation parenthesized ? Unwrap(parenthesized.Operand) : value; + } + + private static bool IsWriteAccess(IOperation operation) => + operation.Syntax.Parent is AssignmentExpressionSyntax assignment + && assignment.Left.Span.Contains(operation.Syntax.SpanStart) + || operation.Syntax.Parent is PrefixUnaryExpressionSyntax prefix + && prefix.Kind() is SyntaxKind.PreIncrementExpression or SyntaxKind.PreDecrementExpression + || operation.Syntax.Parent is PostfixUnaryExpressionSyntax postfix + && postfix.Kind() is SyntaxKind.PostIncrementExpression or SyntaxKind.PostDecrementExpression; + + private static bool IsReadWriteAccess(IOperation operation) => + operation.Syntax.Parent is AssignmentExpressionSyntax assignment + && assignment.Kind() + is SyntaxKind.AddAssignmentExpression + or SyntaxKind.SubtractAssignmentExpression + or SyntaxKind.MultiplyAssignmentExpression + or SyntaxKind.DivideAssignmentExpression + or SyntaxKind.ModuloAssignmentExpression + or SyntaxKind.AndAssignmentExpression + or SyntaxKind.ExclusiveOrAssignmentExpression + or SyntaxKind.OrAssignmentExpression + or SyntaxKind.LeftShiftAssignmentExpression + or SyntaxKind.RightShiftAssignmentExpression + or SyntaxKind.CoalesceAssignmentExpression + || operation.Syntax.Parent is PrefixUnaryExpressionSyntax prefix + && prefix.Kind() is SyntaxKind.PreIncrementExpression or SyntaxKind.PreDecrementExpression + || operation.Syntax.Parent is PostfixUnaryExpressionSyntax postfix + && postfix.Kind() is SyntaxKind.PostIncrementExpression or SyntaxKind.PostDecrementExpression; + + private static bool IsBaseMemberAccess(IOperation operation) => + operation.Syntax is MemberAccessExpressionSyntax { Expression: BaseExpressionSyntax } + || operation.Syntax is MemberBindingExpressionSyntax binding + && binding.Ancestors().OfType().FirstOrDefault()?.Expression + is BaseExpressionSyntax; + + private static bool TryGetConstantBoolean(IOperation operation, out bool value) + { + if (operation.ConstantValue is { HasValue: true, Value: bool constant }) + { + value = constant; + return true; + } + + value = false; + return false; + } + + private static IMethodSymbol? EventAccessor(IEventReferenceOperation operation) + { + if (operation.Syntax.Parent is AssignmentExpressionSyntax assignment) + return assignment.Kind() == SyntaxKind.SubtractAssignmentExpression + ? operation.Event.RemoveMethod + : operation.Event.AddMethod; + return operation.Event.AddMethod; + } + + private static bool IsDelegateType(ITypeSymbol type) => type.TypeKind == TypeKind.Delegate; + + private void AddDelegateDiagnostic(string callerId, IOperation callsite) => + AddDiagnostic( + "unresolved-delegate-dispatch", + callerId, + "mutable or escaped delegate target cannot be closed statically", + callsite + ); + + private void AddDiagnostic(string code, string subjectId, string message, IOperation callsite) => + AddDiagnostic(code, subjectId, message, Location(callsite)); + + private void AddDiagnostic(string code, string subjectId, string message, SyntaxNode callsite) => + AddDiagnostic(code, subjectId, message, Location(callsite, _sourceByTree[callsite.SyntaxTree])); + + private void AddDiagnostic(string code, string subjectId, string message, string location) + { + if ( + _diagnostics.Any(item => + item.Code == code + && item.SubjectId == subjectId + && item.Location == location + && item.Message == message + ) + ) + return; + _diagnostics.Add(new InventoryDiagnostic(code, subjectId, message, "", location)); + } + + private void AddReachable(ISymbol symbol, SortedSet pending, bool expandType = false) + { + if (!IsSourceSymbol(symbol)) + return; + string id = CanonicalSymbolId(symbol); + if (!_symbolsById.ContainsKey(id)) + return; + if (!_reachable.Add(id)) + return; + if (symbol.ContainingType is INamedTypeSymbol containingType) + _reachableTypes.Add(CanonicalTypeId(containingType)); + if (symbol is INamedTypeSymbol type) + _reachableTypes.Add(CanonicalTypeId(type)); + if (expandType && symbol is INamedTypeSymbol rootType) + { + foreach (Declaration declaration in _declarations.Where(item => IsWithinType(item.Symbol, rootType))) + AddReachable(declaration.Symbol, pending); + } + pending.Add(id); + } + + private readonly HashSet _reachableTypes = new(StringComparer.Ordinal); + + private bool IsWithinType(ISymbol symbol, INamedTypeSymbol root) + { + for ( + INamedTypeSymbol? current = symbol.ContainingType; + current is not null; + current = current.ContainingType + ) + if (StringComparer.Ordinal.Equals(CanonicalTypeId(current), CanonicalTypeId(root))) + return true; + return symbol is INamedTypeSymbol type + && StringComparer.Ordinal.Equals(CanonicalTypeId(type), CanonicalTypeId(root)); + } + + private bool IsReachable(ISymbol symbol) => !HasAuditedScopes || _reachable.Contains(CanonicalSymbolId(symbol)); + + private bool IsReachableType(INamedTypeSymbol type) => + !HasAuditedScopes || _reachableTypes.Contains(CanonicalTypeId(type)); + + public void CollectModelSurfaces(List surfaces, HashSet ids) + { + // Callable declarations are the internal symbol graph used to resolve scopes and to + // attach decisions, XML accesses, and markers to canonical parents. A declaration is + // not itself a grammar-observable surface: emitting every method would make the + // catalog denominator a noisy census of implementation details. + foreach ( + IFieldSymbol member in _symbolsById + .Values.OfType() + .Where(field => + field.ContainingType?.TypeKind == TypeKind.Enum && IsReachableType(field.ContainingType) + ) + .OrderBy(CanonicalSymbolId, StringComparer.Ordinal) + ) + { + string parent = CanonicalSymbolId(member.ContainingType!); + Add( + surfaces, + ids, + new InventorySurface( + $"model:enum/{parent}/{CanonicalIdCodec.Encode(member.Name)}", + "enum-member", + member.Name, + parent, + Location(member), + member.ConstantValue?.ToString() + ) + ); + } + + foreach ( + INamedTypeSymbol type in _symbolsById + .Values.OfType() + .Where(type => type.TypeKind != TypeKind.Interface && !type.IsAbstract && IsReachableType(type)) + .Distinct(SymbolEqualityComparer.Default) + .Cast() + .OrderBy(CanonicalSymbolId, StringComparer.Ordinal) + ) + { + foreach (string rule in RuleNames(type)) + { + string typeId = CanonicalSymbolId(type); + Add( + surfaces, + ids, + new InventorySurface( + $"model:rule/{typeId}/{rule}", + "rule-implementation", + typeId, + null, + Location(type), + rule + ) + ); + } + } + } + + public IReadOnlyList CollectXmlCandidates() + { + foreach ( + (SyntaxTree tree, SourceInput source) in _sourceByTree.OrderBy( + pair => pair.Value.Path, + StringComparer.Ordinal + ) + ) + { + SemanticModel model = _models[tree]; + foreach ( + InvocationExpressionSyntax invocation in tree.GetRoot() + .DescendantNodes() + .OfType() + ) + { + if (HasAuditedScopes && !Audited(model, invocation)) + continue; + string? name = InvocationName(invocation); + if (name is not null && XmlNames.Contains(name)) + CollectXml(model, source, invocation, name); + } + } + + return _xml.Select(candidate => new ResolvedXml( + candidate.Parent, + candidate.Method, + candidate.Constant, + candidate.Kind, + candidate.Source.Path, + candidate.Node.SpanStart, + Location(candidate.Node, candidate.Source), + candidate.Value + )) + .ToArray(); + } + + public IReadOnlyList CollectDecisionCandidates() + { + foreach ( + (SyntaxTree tree, SourceInput source) in _sourceByTree.OrderBy( + pair => pair.Value.Path, + StringComparer.Ordinal + ) + ) + { + SemanticModel model = _models[tree]; + foreach (SyntaxNode node in tree.GetRoot().DescendantNodes()) + { + if (!Audited(model, node)) + continue; + switch (node) + { + case IfStatementSyntax: + Decision(model, source, node, "if", "true"); + Decision(model, source, node, "if", "false"); + break; + case SwitchStatementSyntax statement: + foreach ( + SwitchLabelSyntax label in statement.Sections.SelectMany(section => section.Labels) + ) + Decision( + model, + source, + label, + "switch", + label is DefaultSwitchLabelSyntax ? "default" : label.ToString() + ); + break; + case SwitchExpressionSyntax expression: + foreach (SwitchExpressionArmSyntax arm in expression.Arms) + Decision(model, source, arm, "switch-expression", arm.Pattern.ToString()); + break; + case ConditionalExpressionSyntax: + Decision(model, source, node, "conditional", "true"); + Decision(model, source, node, "conditional", "false"); + break; + case ConditionalAccessExpressionSyntax: + Decision(model, source, node, "conditional-access", "present"); + Decision(model, source, node, "conditional-access", "null"); + break; + case BinaryExpressionSyntax binary when binary.IsKind(SyntaxKind.CoalesceExpression): + Decision(model, source, node, "coalesce", "left-nonnull"); + Decision(model, source, node, "coalesce", "right"); + break; + case CatchClauseSyntax clause: + Decision(model, source, node, "catch", "true"); + Decision(model, source, node, "catch", "false"); + if (clause.Filter is not null) + { + Decision(model, source, clause.Filter, "catch-filter", "true"); + Decision(model, source, clause.Filter, "catch-filter", "false"); + } + break; + case ForStatementSyntax + or ForEachStatementSyntax + or ForEachVariableStatementSyntax + or WhileStatementSyntax + or DoStatementSyntax: + Decision(model, source, node, "loop", "natural-exit"); + break; + case BreakStatementSyntax when NearestLoop(node) is not null: + Decision(model, source, node, "loop", "break"); + break; + case ContinueStatementSyntax when NearestLoop(node) is not null: + Decision(model, source, node, "loop", "continue"); + break; + } + } + } + + return _decisions + .Select(candidate => new ResolvedDecision( + candidate.Parent, + candidate.Kind, + candidate.Branch, + candidate.Source.Path, + candidate.Node.SpanStart, + Fingerprint(candidate.Node), + Location(candidate.Node, candidate.Source) + )) + .ToArray(); + } + + // ToString() drops surrounding trivia; a disabled #if block is leading trivia of the + // next statement, so ToFullString() would fingerprint one node differently per configuration. + private static string Fingerprint(SyntaxNode node) => + Convert + .ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(node.NormalizeWhitespace().ToString()))) + .ToLowerInvariant()[..16]; + + private void CollectXml(SemanticModel model, SourceInput source, InvocationExpressionSyntax node, string name) + { + IMethodSymbol? method = model.GetSymbolInfo(node).Symbol as IMethodSymbol; + ExpressionSyntax? receiver = + (node.Expression as MemberAccessExpressionSyntax)?.Expression + ?? ( + node.Expression is MemberBindingExpressionSyntax + ? node.Ancestors().OfType().FirstOrDefault()?.Expression + : null + ); + ITypeSymbol? receiverType = receiver is null ? null : model.GetTypeInfo(receiver).Type; + bool receiverIsXml = IsXmlReceiver(receiverType); + bool receiverIsUnresolvedXml = + receiverType is IErrorTypeSymbol errorType && (errorType.Name is "XElement" or "XContainer") + || receiver is not null && IsUnresolvedAliasReceiver(model, receiver, "XElement", "XContainer"); + if (!IsXml(method, name)) + { + if (receiverType is not null && !receiverIsXml && !receiverIsUnresolvedXml) + return; + if (receiverType is null && method is not null) + return; + } + string? constant = null; + string kind; + string? value = null; + if (IsXml(method, name)) + { + if (name == "Elements" && node.ArgumentList.Arguments.Count == 0) + { + constant = "xml-all-elements"; + kind = "xml-all-elements"; + } + else if (node.ArgumentList.Arguments.Count == 1) + { + constant = ConstantString(model, node.ArgumentList.Arguments[0].Expression); + kind = constant is null ? "dynamic-xml-access" : "xml-read"; + value = constant is null ? node.ArgumentList.Arguments[0].Expression.ToString() : name; + } + else + { + kind = "unresolved-xml-access"; + value = node.ToString(); + } + } + else + { + kind = "unresolved-xml-access"; + value = node.ToString(); + } + _xml.Add(new XmlCandidate(ContainingId(model, node), name, constant, kind, node, source, value)); + } + + private void Decision(SemanticModel model, SourceInput source, SyntaxNode node, string kind, string branch) + { + string parent = ContainingId(model, node); + _decisions.Add(new DecisionCandidate(parent, kind, branch, node, source)); + } + + private bool Audited(SemanticModel model, SyntaxNode node) + { + if (_sources.All(source => source.Scopes.Count == 0)) + return false; + ISymbol? containing = model.GetEnclosingSymbol(node.SpanStart); + return containing is not null && IsReachable(containing); + } + + private string ContainingId(SemanticModel model, SyntaxNode node) + { + for ( + ISymbol? current = model.GetEnclosingSymbol(node.SpanStart); + current is not null; + current = current.ContainingSymbol + ) + if (IsSourceSymbol(current)) + return CanonicalSymbolId(current); + return ""; + } + + private string CanonicalSymbolId(ISymbol symbol) + { + if (_symbolIds.TryGetValue(symbol, out string? value)) + return value; + string id = symbol switch + { + INamedTypeSymbol type => CanonicalTypeId(type), + IMethodSymbol method => CanonicalMethodId(method), + IPropertySymbol property => CanonicalPropertyId(property), + IFieldSymbol field => $"{CanonicalTypeId(field.ContainingType!)}.{field.Name}", + IEventSymbol @event => $"{CanonicalTypeId(@event.ContainingType!)}.{@event.Name}", + _ => CleanGlobal(symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)), + }; + _symbolIds[symbol] = id; + return id; + } + + private string CanonicalTypeId(INamedTypeSymbol type) + { + INamedTypeSymbol definition = type.OriginalDefinition; + if (!_typeIds.TryGetValue(definition, out string? id)) + { + string name = definition.Name + (definition.Arity == 0 ? string.Empty : $"`{definition.Arity}"); + id = + definition.ContainingType is not null ? $"{CanonicalTypeId(definition.ContainingType)}.{name}" + : definition.ContainingNamespace is { IsGlobalNamespace: false } ns + ? $"{CleanGlobal(ns.ToDisplayString())}.{name}" + : name; + _typeIds[definition] = id; + } + + if (SymbolEqualityComparer.Default.Equals(type, definition) || type.TypeArguments.Length == 0) + return id; + + return $"{id}<{string.Join(",", type.TypeArguments.Select(TypeDisplay))}>"; + } + + private string CanonicalMethodId(IMethodSymbol method) + { + IMethodSymbol definition = method.OriginalDefinition; + if (definition.MethodKind == MethodKind.LocalFunction && definition.ContainingSymbol is not null) + { + string id = LocalFunctionBaseId(definition); + return _localFunctionOrdinals.TryGetValue(definition, out int ordinal) ? $"{id}#{ordinal}" : id; + } + + if (definition.MethodKind == MethodKind.AnonymousFunction && definition.ContainingSymbol is not null) + { + // Disabled preprocessor regions still occupy source spans. A source-location + // identity therefore remains stable when another configuration adds or removes + // a gated lambda before this one; ordinal-by-visible-lambdas does not. + return $"{CanonicalSymbolId(definition.ContainingSymbol)}/lambda@{CanonicalIdCodec.Encode(LocalFunctionSourcePath(definition))}:{LocalFunctionSourceStart(definition)}"; + } + + if ( + definition.AssociatedSymbol is IPropertySymbol property + && definition.MethodKind is MethodKind.PropertyGet or MethodKind.PropertySet + ) + { + return $"{CanonicalPropertyId(property)}/{(definition.MethodKind == MethodKind.PropertyGet ? "get" : "set")}"; + } + + if ( + definition.AssociatedSymbol is IEventSymbol @event + && definition.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove + ) + { + return $"{CanonicalEventId(@event)}/{(definition.MethodKind == MethodKind.EventAdd ? "add" : "remove")}"; + } + + return MethodSignature(definition); + } + + private string MethodSignature(IMethodSymbol method) + { + string prefix = method.ContainingType is null ? string.Empty : CanonicalTypeId(method.ContainingType) + "."; + return $"{prefix}{CallableName(method)}({Parameters(method)})"; + } + + private static string CallableName(IMethodSymbol method) + { + string name = method.MethodKind switch + { + MethodKind.Constructor => ".ctor", + MethodKind.StaticConstructor => ".cctor", + MethodKind.Destructor => ".dtor", + MethodKind.UserDefinedOperator => "operator-" + method.MetadataName, + MethodKind.Conversion => "conversion-" + method.MetadataName, + _ => method.Name, + }; + if (method.Arity > 0) + name += "`" + method.Arity; + return name; + } + + private string Parameters(IMethodSymbol method) => + string.Join(",", method.Parameters.Select(parameter => RefPrefix(parameter) + TypeDisplay(parameter.Type))); + + private string CanonicalPropertyId(IPropertySymbol property) + { + string prefix = property.ContainingType is null + ? string.Empty + : CanonicalTypeId(property.ContainingType) + "."; + if (!property.IsIndexer) + return prefix + property.Name; + return $"{prefix}this({string.Join(",", property.Parameters.Select(parameter => RefPrefix(parameter) + TypeDisplay(parameter.Type)))})"; + } + + private string CanonicalEventId(IEventSymbol @event) => + $"{CanonicalTypeId(@event.ContainingType!)}.{@event.Name}"; + + private static string RefPrefix(IParameterSymbol parameter) + { + if (parameter.IsParams) + return "params "; + return parameter.RefKind switch + { + RefKind.Ref => "ref ", + RefKind.Out => "out ", + RefKind.In => "in ", + RefKind.RefReadOnlyParameter => "ref readonly ", + _ => string.Empty, + }; + } + + private string TypeDisplay(ITypeSymbol type) + { + if (type is ITypeParameterSymbol typeParameter) + { + return (typeParameter.TypeParameterKind == TypeParameterKind.Method ? "!!" : "!") + + typeParameter.Ordinal; + } + if (type is IArrayTypeSymbol array) + { + string rank = array.Rank == 1 ? "[]" : $"[{new string(',', array.Rank - 1)}]"; + return TypeDisplay(array.ElementType) + rank; + } + if (type is IPointerTypeSymbol pointer) + return TypeDisplay(pointer.PointedAtType) + "*"; + if (type is INamedTypeSymbol named) + return CanonicalTypeId(named); + + string? special = type.SpecialType switch + { + SpecialType.System_Boolean => "System.Boolean", + SpecialType.System_Byte => "System.Byte", + SpecialType.System_Char => "System.Char", + SpecialType.System_Decimal => "System.Decimal", + SpecialType.System_Double => "System.Double", + SpecialType.System_Int16 => "System.Int16", + SpecialType.System_Int32 => "System.Int32", + SpecialType.System_Int64 => "System.Int64", + SpecialType.System_Object => "System.Object", + SpecialType.System_SByte => "System.SByte", + SpecialType.System_Single => "System.Single", + SpecialType.System_String => "System.String", + SpecialType.System_UInt16 => "System.UInt16", + SpecialType.System_UInt32 => "System.UInt32", + SpecialType.System_UInt64 => "System.UInt64", + _ => null, + }; + return special ?? CleanGlobal(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); + } + + private static string CleanGlobal(string value) => value.Replace("global::", "", StringComparison.Ordinal); + + private IReadOnlyList RuleNames(INamedTypeSymbol type) + { + var names = new HashSet(StringComparer.Ordinal); + INamedTypeSymbol? hc = _compilation.GetTypeByMetadataName(HcRuleMetadata); + INamedTypeSymbol? phon = _compilation.GetTypeByMetadataName(PhonRuleMetadata); + INamedTypeSymbol? morph = _compilation.GetTypeByMetadataName(MorphRuleMetadata); + INamedTypeSymbol? machine = _compilation.GetTypeByMetadataName(MachineRuleMetadata); + foreach (INamedTypeSymbol implemented in type.AllInterfaces) + { + INamedTypeSymbol original = implemented.OriginalDefinition; + if (hc is not null && SymbolEqualityComparer.Default.Equals(original, hc)) + names.Add("IHCRule"); + if (phon is not null && SymbolEqualityComparer.Default.Equals(original, phon)) + names.Add("IPhonologicalRule"); + if (morph is not null && SymbolEqualityComparer.Default.Equals(original, morph)) + names.Add("IMorphologicalRule"); + if (machine is not null && SymbolEqualityComparer.Default.Equals(original, machine)) + names.Add("IRule"); + } + return names.OrderBy(value => value, StringComparer.Ordinal).ToArray(); + } + + private bool IsXml(IMethodSymbol? method, string name) + { + if (method is null || method.Name != name) + return false; + INamedTypeSymbol? owner = method.ContainingType?.OriginalDefinition; + INamedTypeSymbol? element = _compilation.GetTypeByMetadataName(XElementMetadata); + INamedTypeSymbol? container = _compilation.GetTypeByMetadataName(XContainerMetadata); + if (name == "Attribute") + { + if (element is null || !SymbolEqualityComparer.Default.Equals(owner, element)) + return false; + } + else if ( + name == "Element" + && (container is null || !SymbolEqualityComparer.Default.Equals(owner, container)) + ) + { + return false; + } + else if ( + name == "Elements" + && (container is null || !SymbolEqualityComparer.Default.Equals(owner, container)) + ) + { + return false; + } + INamedTypeSymbol? xname = _compilation.GetTypeByMetadataName(XNameMetadata); + if (name == "Elements" && method.Parameters.Length == 0) + return true; + return method.Parameters.Length == 1 + && xname is not null + && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, xname); + } + + private static bool IsXmlReceiver(ITypeSymbol? type) + { + if (type is null) + return false; + string value = CleanGlobal( + type.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + ); + return value is XElementMetadata or XContainerMetadata; + } + + private static bool IsUnresolvedAliasReceiver( + SemanticModel model, + ExpressionSyntax receiver, + params string[] targetNames + ) + { + ISymbol? receiverSymbol = model.GetSymbolInfo(receiver).Symbol; + TypeSyntax? declaredType = receiverSymbol + ?.DeclaringSyntaxReferences.Select(reference => reference.GetSyntax()) + .Select(node => + node switch + { + ParameterSyntax parameter => parameter.Type, + VariableDeclaratorSyntax variable + when variable.Parent?.Parent is VariableDeclarationSyntax declaration => declaration.Type, + _ => null, + } + ) + .FirstOrDefault(type => type is not null); + return declaredType is not null && IsUnresolvedAlias(model, declaredType, targetNames); + } + + private static bool IsUnresolvedAlias(SemanticModel model, SyntaxNode use, params string[] targetNames) + { + string? alias = use switch + { + IdentifierNameSyntax identifier => identifier.Identifier.ValueText, + GenericNameSyntax generic => generic.Identifier.ValueText, + _ => null, + }; + return alias is not null + && IsUnresolvedAlias(model, use, alias, targetNames, new HashSet(StringComparer.Ordinal)); + } + + private static bool IsUnresolvedAlias( + SemanticModel model, + SyntaxNode use, + string alias, + IReadOnlyCollection targetNames, + HashSet visited + ) + { + if (!visited.Add(alias)) + return false; + foreach ( + UsingDirectiveSyntax usingDirective in model + .SyntaxTree.GetRoot() + .DescendantNodes() + .OfType() + .Where(directive => + directive.Alias?.Name.Identifier.ValueText == alias + && directive.Name is not null + && IsUsingApplicable(directive, use) + ) + ) + { + NameSyntax target = usingDirective.Name!; + if ( + IsUnresolvedSymbol(model.GetSymbolInfo(target).Symbol) + && targetNames.Contains(TerminalName(target), StringComparer.Ordinal) + ) + return true; + if ( + target is IdentifierNameSyntax nested + && IsUnresolvedAlias(model, use, nested.Identifier.ValueText, targetNames, visited) + ) + return true; + } + return false; + } + + private static bool IsUsingApplicable(UsingDirectiveSyntax usingDirective, SyntaxNode use) => + usingDirective.Parent is CompilationUnitSyntax + || usingDirective.Parent is BaseNamespaceDeclarationSyntax owner + && use.AncestorsAndSelf().Any(ancestor => ReferenceEquals(ancestor, owner)); + + private static bool IsUnresolvedSymbol(ISymbol? symbol) => + symbol is null or IErrorTypeSymbol || symbol is IAliasSymbol { Target: IErrorTypeSymbol }; + + private static string TerminalName(NameSyntax name) => + name switch + { + QualifiedNameSyntax qualified => TerminalName(qualified.Right), + AliasQualifiedNameSyntax aliasQualified => TerminalName(aliasQualified.Name), + GenericNameSyntax generic => generic.Identifier.ValueText, + IdentifierNameSyntax identifier => identifier.Identifier.ValueText, + _ => name.ToString().Split('.').Last(), + }; + + private static string? ConstantString(SemanticModel model, ExpressionSyntax? expression) + { + if (expression is null) + return null; + Optional constant = model.GetConstantValue(expression); + return constant.HasValue && constant.Value is string value ? value : null; + } + + private static string? InvocationName(InvocationExpressionSyntax node) => + node.Expression switch + { + MemberAccessExpressionSyntax member => member.Name.Identifier.ValueText, + MemberBindingExpressionSyntax binding => binding.Name.Identifier.ValueText, + IdentifierNameSyntax identifier => identifier.Identifier.ValueText, + GenericNameSyntax generic => generic.Identifier.ValueText, + _ => null, + }; + + private static bool IsSourceSymbol(ISymbol symbol) => + symbol switch + { + INamedTypeSymbol => true, + IMethodSymbol method => method.MethodKind + is MethodKind.Ordinary + or MethodKind.Constructor + or MethodKind.StaticConstructor + or MethodKind.Destructor + or MethodKind.UserDefinedOperator + or MethodKind.Conversion + or MethodKind.LocalFunction + or MethodKind.AnonymousFunction + or MethodKind.PropertyGet + or MethodKind.PropertySet + or MethodKind.EventAdd + or MethodKind.EventRemove, + IPropertySymbol or IFieldSymbol or IEventSymbol => true, + _ => false, + }; + + private string Location(IOperation operation) => + Location(operation.Syntax, _sourceByTree[operation.Syntax.SyntaxTree]); + + private string Location(ISymbol symbol) + { + Location? location = symbol + .Locations.Where(item => item.IsInSource) + .OrderBy(item => item.SourceTree?.FilePath, StringComparer.Ordinal) + .ThenBy(item => item.SourceSpan.Start) + .FirstOrDefault(); + return location?.SourceTree is null + ? "" + : Location(location.SourceTree, location.SourceSpan, _sourceByTree[location.SourceTree]); + } + + private static string Location(SyntaxNode node, SourceInput source) => + Location(node.SyntaxTree, node.Span, source); + + private static string Location(SyntaxTree tree, TextSpan span, SourceInput source) + { + FileLinePositionSpan line = tree.GetLineSpan(span); + return $"{source.Path}:{line.StartLinePosition.Line + 1}:{line.StartLinePosition.Character + 1}-{line.EndLinePosition.Line + 1}:{line.EndLinePosition.Character + 1}"; + } + + private static SyntaxNode? NearestLoop(SyntaxNode node) => + node.Ancestors() + .FirstOrDefault(ancestor => + ancestor + is ForStatementSyntax + or ForEachStatementSyntax + or ForEachVariableStatementSyntax + or WhileStatementSyntax + or DoStatementSyntax + ); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CanonicalJson.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CanonicalJson.cs new file mode 100644 index 000000000..c01c95a22 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CanonicalJson.cs @@ -0,0 +1,109 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.Json; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Produces compact UTF-8 JSON with recursively ordinal-sorted object keys. +internal static class CanonicalJson +{ + private static readonly JsonSerializerOptions SerializerOptions = new() + { + WriteIndented = false, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DictionaryKeyPolicy = null, + }; + + internal static byte[] SerializeUtf8(T value) + { + ArgumentNullException.ThrowIfNull(value); + using JsonDocument document = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(value, SerializerOptions)); + using var stream = new MemoryStream(); + using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = false })) + WriteElement(document.RootElement, writer); + return stream.ToArray(); + } + + internal static string Serialize(T value) => Encoding.UTF8.GetString(SerializeUtf8(value)); + + internal static byte[] NormalizeJson(ReadOnlySpan utf8) + { + using JsonDocument document = JsonDocument.Parse(utf8.ToArray()); + using var stream = new MemoryStream(); + using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = false })) + WriteElement(document.RootElement, writer); + return stream.ToArray(); + } + + private static void WriteElement(JsonElement element, Utf8JsonWriter writer) + { + switch (element.ValueKind) + { + case JsonValueKind.Object: + writer.WriteStartObject(); + var properties = new List(); + var propertyNames = new HashSet(StringComparer.Ordinal); + foreach (JsonProperty property in element.EnumerateObject()) + { + if (!propertyNames.Add(property.Name)) + throw new InvalidDataException($"Duplicate JSON property '{property.Name}'."); + properties.Add(property); + } + properties.Sort((left, right) => StringComparer.Ordinal.Compare(left.Name, right.Name)); + foreach (JsonProperty property in properties) + { + writer.WritePropertyName(property.Name); + WriteElement(property.Value, writer); + } + writer.WriteEndObject(); + break; + case JsonValueKind.Array: + writer.WriteStartArray(); + foreach (JsonElement item in element.EnumerateArray()) + WriteElement(item, writer); + writer.WriteEndArray(); + break; + case JsonValueKind.String: + writer.WriteStringValue(NormalizeString(element.GetString()!)); + break; + case JsonValueKind.Number: + if ( + !decimal.TryParse( + element.GetRawText(), + NumberStyles.Float, + CultureInfo.InvariantCulture, + out decimal decimalValue + ) + ) + { + throw new InvalidDataException( + $"JSON number '{element.GetRawText()}' is outside the supported canonical range." + ); + } + writer.WriteRawValue( + decimalValue.ToString("G29", CultureInfo.InvariantCulture), + skipInputValidation: true + ); + break; + case JsonValueKind.True: + writer.WriteBooleanValue(true); + break; + case JsonValueKind.False: + writer.WriteBooleanValue(false); + break; + case JsonValueKind.Null: + writer.WriteNullValue(); + break; + default: + throw new InvalidDataException($"Unsupported JSON value kind '{element.ValueKind}'."); + } + } + + private static string NormalizeString(string value) => + value.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n'); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CatalogBootstrap.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CatalogBootstrap.cs new file mode 100644 index 000000000..b7bbc3572 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CatalogBootstrap.cs @@ -0,0 +1,236 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Generates a catalog that maps every generated surface exactly once, so the audit runs against the +/// real inventory instead of only against literals in tests. Grammar-observable surfaces are grouped +/// per DTD element and left unclassified: the bootstrap states plainly that no human has judged +/// them rather than inventing phase effects to satisfy the audit. Everything else is classified by +/// kind, which is where the surfaces a grammar author cannot write are accounted for by name. +/// +public static class CatalogBootstrap +{ + public const string CatalogRelativePath = "conformance/semantic-catalog.yaml"; + + private sealed record KindPolicy(string Disposition, string Reason); + + private static readonly Dictionary KindPolicies = new(StringComparer.Ordinal) + { + ["attribute"] = new( + "loader", + "An attribute declaration itself; its enumerated values are the unit a grammar can choose, and those are classified separately." + ), + ["attribute-type"] = new( + "metadata", + "The declared XML type of an attribute. Schema bookkeeping with no parse behaviour of its own." + ), + ["attribute-default"] = new( + "metadata", + "The declared default of an attribute. Which value is in effect is observable; the declaration of the default is not." + ), + ["default"] = new("metadata", "A DTD default declaration. Schema bookkeeping."), + ["content-group"] = new( + "loader", + "A content-model group. Constrains what a document may contain; the loader enforces it before any parse behaviour exists." + ), + ["placement"] = new( + "loader", + "Child occurrence and cardinality within a content model. Genuinely semantic as occurrence multiplicity, but not writable as a value in a grammar, so it is out of reach of the coverage ledger." + ), + ["special-content"] = new("metadata", "An EMPTY or ANY content declaration. Schema bookkeeping."), + ["xml-read"] = new( + "loader", + "A loader read of a named element or attribute. Load-time structure, tracked by the C# census rather than by grammar coverage." + ), + ["xml-all-elements"] = new("loader", "A loader read of every child element. Load-time structure."), + ["dynamic-xml-access"] = new("loader", "A loader read whose name is computed. Load-time structure."), + ["callable"] = new("loader", "A loader method. Load-time structure."), + ["enum-member"] = new("loader", "A C# enum member of the loader model."), + ["rule-implementation"] = new("loader", "A concrete rule type in the engine model."), + ["decision-if"] = new( + "unclassified", + "A conditional branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-switch"] = new( + "unclassified", + "A switch branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-switch-expression"] = new( + "unclassified", + "A switch-expression arm in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-conditional"] = new( + "unclassified", + "A conditional expression branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-conditional-access"] = new( + "unclassified", + "A null-conditional access branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-coalesce"] = new( + "unclassified", + "A null-coalescing branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-catch"] = new( + "unclassified", + "A catch branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-catch-filter"] = new( + "unclassified", + "A catch-filter branch in an audited C# scope; semantic phase effects require human classification." + ), + ["decision-loop"] = new( + "unclassified", + "A loop branch in an audited C# scope; semantic phase effects require human classification." + ), + }; + + public static string Generate(SemanticInventory inventory) => Generate(inventory, Array.Empty()); + + public static string Generate(SemanticInventory inventory, IReadOnlyCollection auditedSourceScopes) + { + ArgumentNullException.ThrowIfNull(inventory); + string[] scopes = NormalizeScopes(auditedSourceScopes); + var observable = GrammarFeatureUsage.Observable(inventory).ToHashSet(StringComparer.Ordinal); + var mappings = new List<(string SurfaceId, string FeatureId)>(); + var elementFeatures = new SortedSet(StringComparer.Ordinal); + var kindFeatures = new SortedSet(StringComparer.Ordinal); + var unknownKinds = new SortedSet(StringComparer.Ordinal); + + foreach (InventorySurface surface in inventory.Surfaces.OrderBy(item => item.Id, StringComparer.Ordinal)) + { + if (observable.Contains(surface.Id) && DeadSchemaDetector.OwningElement(surface.Id) is string element) + { + string featureId = $"grammar/{element}"; + elementFeatures.Add(element); + mappings.Add((surface.Id, featureId)); + continue; + } + + if (!KindPolicies.ContainsKey(surface.Kind)) + unknownKinds.Add(surface.Kind); + string kindFeature = $"schema/{surface.Kind}"; + kindFeatures.Add(surface.Kind); + mappings.Add((surface.Id, kindFeature)); + } + + if (unknownKinds.Count != 0) + { + throw new InvalidOperationException( + $"No catalog policy for surface kind(s): {string.Join(", ", unknownKinds)}. " + + "Add a policy rather than letting a new kind fall through unclassified." + ); + } + + var text = new StringBuilder(); + text.Append(Header(inventory, elementFeatures.Count, kindFeatures.Count, mappings.Count)); + text.Append("profile: ").Append(SemanticCatalogLoader.ExpectedProfile).Append('\n'); + text.Append("auditedSourceScopes: [").Append(string.Join(", ", scopes.Select(QuoteYamlScalar))).Append("]\n"); + text.Append("features:\n"); + foreach (string element in elementFeatures) + { + text.Append($" - id: grammar/{element}\n"); + text.Append(" disposition: unclassified\n"); + text.Append( + $" reason: \"Grammar-observable surfaces of DTD element {element}. Generated by the bootstrap; no human has judged the phase effects yet. Per-surface coverage is tracked in the coverage ledger.\"\n" + ); + text.Append( + " citations: [\"src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd\", \"conformance/semantic-coverage-baseline.txt\"]\n" + ); + } + + foreach (string kind in kindFeatures) + { + KindPolicy policy = KindPolicies[kind]; + text.Append($" - id: schema/{kind}\n"); + text.Append($" disposition: {policy.Disposition}\n"); + text.Append($" reason: \"{policy.Reason}\"\n"); + text.Append(" citations: [\"src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd\"]\n"); + } + + text.Append("surfaceMappings:\n"); + foreach ( + (string surfaceId, string featureId) in mappings.OrderBy(item => item.SurfaceId, StringComparer.Ordinal) + ) + { + text.Append($" - surface: \"{surfaceId}\"\n"); + text.Append($" feature: {featureId}\n"); + } + + return text.ToString(); + } + + /// + /// Writes a bootstrap proposal to the supplied stream. This is deliberately the only write + /// surface: proposals are review material and can never overwrite the curated catalog. + /// + public static void WriteProposal(TextWriter writer, SemanticInventory inventory) => + WriteProposal(writer, inventory, Array.Empty()); + + public static void WriteProposal( + TextWriter writer, + SemanticInventory inventory, + IReadOnlyCollection auditedSourceScopes + ) + { + ArgumentNullException.ThrowIfNull(writer); + ArgumentNullException.ThrowIfNull(inventory); + writer.Write(Generate(inventory, auditedSourceScopes)); + } + + public static SemanticCatalog Load(string repositoryRoot) => + SemanticCatalogLoader.Load( + Path.Combine(repositoryRoot, CatalogRelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + private static string[] NormalizeScopes(IReadOnlyCollection scopes) + { + ArgumentNullException.ThrowIfNull(scopes); + foreach (string? scope in scopes) + { + if (string.IsNullOrWhiteSpace(scope) || ScopeValidation.HasPattern(scope)) + { + throw new ArgumentException( + $"Audited source scope '{scope}' must be one exact canonical symbol ID.", + nameof(scopes) + ); + } + } + + return scopes.Distinct(StringComparer.Ordinal).OrderBy(scope => scope, StringComparer.Ordinal).ToArray(); + } + + private static string QuoteYamlScalar(string value) => + $"\"{value.Replace("\\", "\\\\", StringComparison.Ordinal) + .Replace("\"", "\\\"", StringComparison.Ordinal) + .Replace("\r", "\\r", StringComparison.Ordinal) + .Replace("\n", "\\n", StringComparison.Ordinal) + .Replace("\t", "\\t", StringComparison.Ordinal)}\""; + + private static string Header(SemanticInventory inventory, int elementFeatures, int kindFeatures, int mappings) => + $""" + # HermitCrab semantic catalog + # + # PROPOSAL from hc-conformance --propose-semantic-catalog. Every one of the {inventory.Surfaces.Count} surfaces the + # inventory generates is named by exactly one surfaceMappings row, so a surface added to the DTD + # is unmapped and the audit fails until someone classifies it. That fail-closed property is the + # whole point; regenerating is a deliberate act, not something a build does for you. + # + # {elementFeatures} features group the grammar-observable surfaces by DTD element and are + # `unclassified`: the bootstrap records that no human has judged their phase effects, rather + # than fabricating effects to satisfy the audit. Promoting one to `semantic` means supplying all + # three phase effects, which the audit then requires. + # + # {kindFeatures} features classify the rest by surface kind. This is where the surfaces a grammar + # author cannot write are accounted for by name instead of vanishing into a filter. + # + # {mappings} mapping rows. Wildcards are rejected, not expanded. + + """; +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationDiagnostics.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationDiagnostics.cs new file mode 100644 index 000000000..9f3037ae9 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationDiagnostics.cs @@ -0,0 +1,76 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record CompilationDiagnostic( + string Origin, + DiagnosticSeverity Severity, + bool IsWarningAsError, + string Code, + string Message, + string Location +) +{ + internal bool IsFatal => Severity == DiagnosticSeverity.Error || IsWarningAsError; + + internal static CompilationDiagnostic From(string origin, Diagnostic diagnostic) + { + FileLinePositionSpan span = diagnostic.Location.GetLineSpan(); + string location = string.IsNullOrEmpty(span.Path) + ? string.Empty + : $"{span.Path}:{span.StartLinePosition.Line + 1}:{span.StartLinePosition.Character + 1}"; + return new CompilationDiagnostic( + origin, + diagnostic.Severity, + diagnostic.IsWarningAsError, + diagnostic.Id, + diagnostic.GetMessage(), + location + ); + } +} + +internal sealed class CompilationDiagnostics +{ + private CompilationDiagnostics(IReadOnlyList all) + { + All = new ReadOnlyCollection(all.ToArray()); + Errors = new ReadOnlyCollection(all.Where(item => item.IsFatal).ToArray()); + Warnings = new ReadOnlyCollection( + all.Where(item => item.Severity == DiagnosticSeverity.Warning && !item.IsFatal).ToArray() + ); + } + + internal IReadOnlyList All { get; } + internal IReadOnlyList Errors { get; } + internal IReadOnlyList Warnings { get; } + + internal static CompilationDiagnostics From(string origin, IEnumerable diagnostics) + { + ArgumentException.ThrowIfNullOrWhiteSpace(origin); + ArgumentNullException.ThrowIfNull(diagnostics); + return new CompilationDiagnostics( + diagnostics + .Where(diagnostic => + diagnostic.Severity != DiagnosticSeverity.Hidden && diagnostic.Severity != DiagnosticSeverity.Info + ) + .Select(diagnostic => CompilationDiagnostic.From(origin, diagnostic)) + .ToArray() + ); + } + + internal void ThrowIfFatal() + { + if (Errors.Count == 0) + return; + throw new CompilerInputException( + "compiler-error", + $"Compilation contains {Errors.Count} error(s): {string.Join("; ", Errors.Take(10).Select(error => $"{error.Code} at {error.Location}: {error.Message}"))}" + ); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphHashInputs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphHashInputs.cs new file mode 100644 index 000000000..5b8ca899d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphHashInputs.cs @@ -0,0 +1,482 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal enum GraphHashFileKind +{ + Text, + Json, + Binary, +} + +internal sealed record GraphHashFile +{ + internal GraphHashFile(string logicalPath, ImmutableArray content, GraphHashFileKind kind) + { + if (!LogicalPathTokens.IsLogicalPath(logicalPath)) + throw new ArgumentException("A logical path token is required.", nameof(logicalPath)); + if (content.IsDefault) + throw new ArgumentException("File content must be initialized.", nameof(content)); + if (!Enum.IsDefined(kind)) + throw new ArgumentOutOfRangeException(nameof(kind)); + LogicalPath = logicalPath; + Content = ImmutableArray.CreateRange(content); + Kind = kind; + } + + internal string LogicalPath { get; } + internal ImmutableArray Content { get; } + internal GraphHashFileKind Kind { get; } +} + +internal sealed record OrderedHashValue +{ + internal OrderedHashValue(int ordinal, string value) + { + ArgumentOutOfRangeException.ThrowIfNegative(ordinal); + ArgumentException.ThrowIfNullOrWhiteSpace(value); + Ordinal = ordinal; + Value = value; + } + + internal int Ordinal { get; } + internal string Value { get; } +} + +internal sealed record OrderedGraphHashFile +{ + internal OrderedGraphHashFile(int ordinal, GraphHashFile file) + { + ArgumentOutOfRangeException.ThrowIfNegative(ordinal); + ArgumentNullException.ThrowIfNull(file); + Ordinal = ordinal; + File = file; + } + + internal int Ordinal { get; } + internal GraphHashFile File { get; } +} + +internal sealed record ProjectHashInput +{ + internal ProjectHashInput(string id, string logicalPath, string targetFramework) + { + ArgumentException.ThrowIfNullOrWhiteSpace(id); + if (!LogicalPathTokens.IsLogicalPath(logicalPath)) + throw new ArgumentException("A logical path token is required.", nameof(logicalPath)); + ArgumentException.ThrowIfNullOrWhiteSpace(targetFramework); + Id = id; + LogicalPath = logicalPath; + TargetFramework = targetFramework; + } + + internal string Id { get; } + internal string LogicalPath { get; } + internal string TargetFramework { get; } +} + +internal sealed record ProfileHashInput +{ + internal ProfileHashInput(string id, IReadOnlyList symbols) + { + ArgumentException.ThrowIfNullOrWhiteSpace(id); + ArgumentNullException.ThrowIfNull(symbols); + if (symbols.Any(symbol => string.IsNullOrWhiteSpace(symbol))) + throw new ArgumentException("Profile symbols must be nonempty.", nameof(symbols)); + Id = id; + Symbols = ImmutableArray.CreateRange(symbols); + } + + internal string Id { get; } + internal ImmutableArray Symbols { get; } +} + +internal sealed record ReferenceHashInput +{ + internal ReferenceHashInput( + string identity, + GraphHashFile file, + IReadOnlyList aliases, + bool embedInteropTypes + ) + { + ArgumentException.ThrowIfNullOrWhiteSpace(identity); + ArgumentNullException.ThrowIfNull(file); + ArgumentNullException.ThrowIfNull(aliases); + if (aliases.Any(alias => alias is null)) + throw new ArgumentException("Reference aliases cannot contain null elements.", nameof(aliases)); + Identity = identity; + File = file; + Aliases = ImmutableArray.CreateRange(aliases); + EmbedInteropTypes = embedInteropTypes; + } + + internal string Identity { get; } + internal GraphHashFile File { get; } + internal ImmutableArray Aliases { get; } + internal bool EmbedInteropTypes { get; } +} + +internal sealed record ProjectReferenceHashInput +{ + internal ProjectReferenceHashInput(string projectId, IReadOnlyDictionary? metadata = null) + { + ArgumentException.ThrowIfNullOrWhiteSpace(projectId); + ProjectId = projectId; + if (metadata is not null && metadata.Any(pair => pair.Key is null || pair.Value is null)) + throw new ArgumentException("Project reference metadata cannot contain null elements.", nameof(metadata)); + Metadata = (metadata ?? new Dictionary()).ToImmutableSortedDictionary(StringComparer.Ordinal); + } + + internal string ProjectId { get; } + internal ImmutableSortedDictionary Metadata { get; } +} + +internal sealed record AnalyzerHashInput +{ + internal AnalyzerHashInput(string identity, GraphHashFile file) + { + ArgumentException.ThrowIfNullOrWhiteSpace(identity); + ArgumentNullException.ThrowIfNull(file); + Identity = identity; + File = file; + } + + internal string Identity { get; } + internal GraphHashFile File { get; } +} + +internal sealed record OptionalGraphHashFile +{ + internal OptionalGraphHashFile(bool isPresent, GraphHashFile? file) + { + if (isPresent != (file is not null)) + throw new ArgumentException("Optional file presence must agree with its value."); + IsPresent = isPresent; + File = file; + } + + internal bool IsPresent { get; } + internal GraphHashFile? File { get; } +} + +internal sealed record NodeHashInput +{ + internal NodeHashInput( + RepositoryGraphNodeKey key, + IReadOnlyDictionary settings, + IReadOnlyList arguments, + IReadOnlyList sources, + IReadOnlyList references, + IReadOnlyList projectReferences, + IReadOnlyList analyzers, + IReadOnlyList additionalFiles, + IReadOnlyList editorConfigFiles, + IReadOnlyList usings, + IReadOnlyList assets, + IReadOnlyList imports + ) + { + ArgumentNullException.ThrowIfNull(key); + ValidateKeySegment(key.ProjectId, nameof(key.ProjectId)); + ValidateKeySegment(key.TargetFramework, nameof(key.TargetFramework)); + ValidateKeySegment(key.ProfileId, nameof(key.ProfileId)); + ArgumentNullException.ThrowIfNull(settings); + ArgumentNullException.ThrowIfNull(arguments); + ArgumentNullException.ThrowIfNull(sources); + ArgumentNullException.ThrowIfNull(references); + ArgumentNullException.ThrowIfNull(projectReferences); + ArgumentNullException.ThrowIfNull(analyzers); + ArgumentNullException.ThrowIfNull(additionalFiles); + ArgumentNullException.ThrowIfNull(editorConfigFiles); + ArgumentNullException.ThrowIfNull(usings); + ArgumentNullException.ThrowIfNull(assets); + ArgumentNullException.ThrowIfNull(imports); + RejectNull(arguments, nameof(arguments)); + RejectNull(sources, nameof(sources)); + RejectNull(references, nameof(references)); + RejectNull(projectReferences, nameof(projectReferences)); + RejectNull(analyzers, nameof(analyzers)); + RejectNull(additionalFiles, nameof(additionalFiles)); + RejectNull(editorConfigFiles, nameof(editorConfigFiles)); + RejectNull(usings, nameof(usings)); + RejectNull(assets, nameof(assets)); + RejectNull(imports, nameof(imports)); + Key = key; + Settings = settings.ToImmutableSortedDictionary(StringComparer.Ordinal); + Arguments = ImmutableArray.CreateRange(arguments); + Sources = ImmutableArray.CreateRange(sources); + References = ImmutableArray.CreateRange(references); + ProjectReferences = ImmutableArray.CreateRange(projectReferences); + Analyzers = ImmutableArray.CreateRange(analyzers); + AdditionalFiles = ImmutableArray.CreateRange(additionalFiles); + EditorConfigFiles = ImmutableArray.CreateRange(editorConfigFiles); + Usings = ImmutableArray.CreateRange(usings); + Assets = ImmutableArray.CreateRange(assets); + Imports = ImmutableArray.CreateRange(imports); + ValidateOrdinals(Arguments.Select(argument => argument.Ordinal), nameof(arguments)); + ValidateOrdinals(Sources.Select(source => source.Ordinal), nameof(sources)); + RejectDuplicate(references.Select(reference => reference.Identity), nameof(references)); + RejectDuplicate(projectReferences.Select(reference => reference.ProjectId), nameof(projectReferences)); + RejectDuplicate(analyzers.Select(analyzer => analyzer.Identity), nameof(analyzers)); + ValidateFiles(additionalFiles, nameof(additionalFiles)); + ValidateFiles(editorConfigFiles, nameof(editorConfigFiles)); + ValidateFiles(usings, nameof(usings)); + ValidateFiles(assets, nameof(assets)); + ValidateFiles(imports, nameof(imports)); + } + + internal RepositoryGraphNodeKey Key { get; } + internal ImmutableSortedDictionary Settings { get; } + internal ImmutableArray Arguments { get; } + internal ImmutableArray Sources { get; } + internal ImmutableArray References { get; } + internal ImmutableArray ProjectReferences { get; } + internal ImmutableArray Analyzers { get; } + internal ImmutableArray AdditionalFiles { get; } + internal ImmutableArray EditorConfigFiles { get; } + internal ImmutableArray Usings { get; } + internal ImmutableArray Assets { get; } + internal ImmutableArray Imports { get; } + + private static void ValidateOrdinals(IEnumerable ordinals, string parameterName) + { + int[] actual = ordinals.OrderBy(ordinal => ordinal).ToArray(); + int[] expected = Enumerable.Range(0, actual.Length).ToArray(); + if (!actual.SequenceEqual(expected)) + throw new InvalidDataException($"{parameterName} ordinals must be unique, contiguous, and start at zero."); + } + + private static void ValidateKeySegment(string value, string parameterName) + { + if (string.IsNullOrWhiteSpace(value) || value.Contains('/') || value.Contains('\\')) + { + throw new ArgumentException( + "Node identity segments must be nonempty and contain no path separators.", + parameterName + ); + } + } + + private static void RejectNull(IEnumerable values, string parameterName) + where T : class + { + if (values.Any(value => value is null)) + throw new ArgumentException("Collections cannot contain null elements.", parameterName); + } + + private static void RejectDuplicate(IEnumerable values, string parameterName) + { + if (values.GroupBy(value => value, StringComparer.Ordinal).Any(group => group.Count() > 1)) + throw new InvalidDataException($"Collection '{parameterName}' contains duplicate identities."); + } + + private static void ValidateFiles(IEnumerable values, string parameterName) + { + var paths = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (GraphHashFile file in values) + { + if (!paths.Add(file.LogicalPath)) + throw new InvalidDataException($"Collection '{parameterName}' contains duplicate logical files."); + } + } +} + +internal sealed record ToolchainHashInput +{ + internal ToolchainHashInput( + string sdkVersion, + string msBuildVersion, + string roslynIdentity, + string compilerIdentity, + string loaderIdentity, + IReadOnlyList files + ) + { + ArgumentException.ThrowIfNullOrWhiteSpace(sdkVersion); + ArgumentException.ThrowIfNullOrWhiteSpace(msBuildVersion); + ArgumentException.ThrowIfNullOrWhiteSpace(roslynIdentity); + ArgumentException.ThrowIfNullOrWhiteSpace(compilerIdentity); + ArgumentException.ThrowIfNullOrWhiteSpace(loaderIdentity); + ArgumentNullException.ThrowIfNull(files); + if (files.Any(file => file is null)) + throw new ArgumentException("Toolchain files cannot contain null elements.", nameof(files)); + if (files.Select(file => file.LogicalPath).Distinct(StringComparer.OrdinalIgnoreCase).Count() != files.Count) + throw new InvalidDataException("Toolchain files contain duplicate logical paths."); + SdkVersion = sdkVersion; + MSBuildVersion = msBuildVersion; + RoslynIdentity = roslynIdentity; + CompilerIdentity = compilerIdentity; + LoaderIdentity = loaderIdentity; + Files = ImmutableArray.CreateRange(files); + } + + internal string SdkVersion { get; } + internal string MSBuildVersion { get; } + internal string RoslynIdentity { get; } + internal string CompilerIdentity { get; } + internal string LoaderIdentity { get; } + internal ImmutableArray Files { get; } +} + +internal sealed record CompilationGraphHashInputs +{ + internal CompilationGraphHashInputs( + string schemaVersion, + IReadOnlyList projects, + IReadOnlyList profiles, + IReadOnlyList nodes, + IReadOnlyList edges, + ToolchainHashInput toolchain, + GraphHashFile captureTarget, + OptionalGraphHashFile lockFile + ) + { + ArgumentException.ThrowIfNullOrWhiteSpace(schemaVersion); + ArgumentNullException.ThrowIfNull(projects); + ArgumentNullException.ThrowIfNull(profiles); + ArgumentNullException.ThrowIfNull(nodes); + ArgumentNullException.ThrowIfNull(edges); + ArgumentNullException.ThrowIfNull(toolchain); + ArgumentNullException.ThrowIfNull(captureTarget); + ArgumentNullException.ThrowIfNull(lockFile); + SchemaVersion = schemaVersion; + Projects = ImmutableArray.CreateRange(projects); + Profiles = ImmutableArray.CreateRange(profiles); + Nodes = ImmutableArray.CreateRange(nodes); + Edges = ImmutableArray.CreateRange(edges); + Toolchain = toolchain; + CaptureTarget = captureTarget; + LockFile = lockFile; + RejectNull(Projects, nameof(projects)); + RejectNull(Profiles, nameof(profiles)); + RejectNull(Nodes, nameof(nodes)); + RejectNull(Edges, nameof(edges)); + RejectDuplicate(Projects.Select(project => project.Id), "project IDs"); + RejectDuplicate(Projects.Select(project => project.LogicalPath), "project paths"); + RejectDuplicate(Profiles.Select(profile => profile.Id), "profile IDs"); + RejectDuplicate(Nodes.Select(node => node.Key), "node keys"); + if (Edges.Distinct().Count() != Edges.Length) + throw new InvalidDataException("Edges contain duplicates."); + ValidateLogicalPaths(); + } + + internal string SchemaVersion { get; } + internal ImmutableArray Projects { get; } + internal ImmutableArray Profiles { get; } + internal ImmutableArray Nodes { get; } + internal ImmutableArray Edges { get; } + internal ToolchainHashInput Toolchain { get; } + internal GraphHashFile CaptureTarget { get; } + internal OptionalGraphHashFile LockFile { get; } + + private void ValidateLogicalPaths() + { + var entries = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (ProjectHashInput project in Projects) + { + if (!entries.TryAdd(project.LogicalPath, new LogicalPathEntry(project.LogicalPath))) + { + throw new InvalidDataException( + $"Logical project path '{project.LogicalPath}' collides with another logical path." + ); + } + } + + foreach (GraphHashFile file in EnumerateAllFiles()) + { + if (entries.TryGetValue(file.LogicalPath, out LogicalPathEntry? existing)) + { + if (!string.Equals(existing.LogicalPath, file.LogicalPath, StringComparison.Ordinal)) + { + throw new InvalidDataException($"Logical path '{file.LogicalPath}' has a case-variant collision."); + } + + if (existing.File is null) + { + existing.File = file; + } + else if ( + existing.File.Kind != file.Kind + || !existing.File.Content.AsSpan().SequenceEqual(file.Content.AsSpan()) + ) + { + throw new InvalidDataException( + $"Logical path '{file.LogicalPath}' has conflicting content or kind." + ); + } + } + else + { + entries.Add(file.LogicalPath, new LogicalPathEntry(file)); + } + } + } + + private static void RejectNull(IEnumerable values, string parameterName) + where T : class + { + if (values.Any(value => value is null)) + throw new ArgumentException("Collections cannot contain null elements.", parameterName); + } + + private static void RejectDuplicate(IEnumerable values, string description) + { + if (values.GroupBy(value => value).Any(group => group.Count() > 1)) + throw new InvalidDataException($"Collection contains duplicate {description}."); + } + + private static IEnumerable EnumerateFiles(NodeHashInput node) + { + foreach (OrderedGraphHashFile file in node.Sources) + yield return file.File; + foreach (ReferenceHashInput reference in node.References) + yield return reference.File; + foreach (AnalyzerHashInput analyzer in node.Analyzers) + yield return analyzer.File; + foreach (GraphHashFile file in node.AdditionalFiles) + yield return file; + foreach (GraphHashFile file in node.EditorConfigFiles) + yield return file; + foreach (GraphHashFile file in node.Usings) + yield return file; + foreach (GraphHashFile file in node.Assets) + yield return file; + foreach (GraphHashFile file in node.Imports) + yield return file; + } + + private IEnumerable EnumerateAllFiles() + { + foreach (GraphHashFile file in Nodes.SelectMany(EnumerateFiles)) + yield return file; + foreach (GraphHashFile file in Toolchain.Files) + yield return file; + yield return CaptureTarget; + if (LockFile.IsPresent) + yield return LockFile.File!; + } + + private sealed class LogicalPathEntry + { + internal LogicalPathEntry(string projectPath) + { + LogicalPath = projectPath; + } + + internal LogicalPathEntry(GraphHashFile file) + { + LogicalPath = file.LogicalPath; + File = file; + } + + internal string LogicalPath { get; } + internal GraphHashFile? File { get; set; } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphHashing.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphHashing.cs new file mode 100644 index 000000000..4bf9b5d78 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphHashing.cs @@ -0,0 +1,168 @@ +#nullable enable + +using System; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record GraphHashes(string GraphInputHash, string ToolchainHash, string GraphHash); + +internal static class CompilationGraphHashing +{ + internal static GraphHashes Compute(CompilationGraphHashInputs inputs) + { + ArgumentNullException.ThrowIfNull(inputs); + + byte[] graphInput = CanonicalJson.SerializeUtf8(ToGraphInputDocument(inputs)); + byte[] toolchain = CanonicalJson.SerializeUtf8(ToToolchainDocument(inputs.Toolchain)); + byte[] graph = CanonicalJson.SerializeUtf8(ToGraphDocument(inputs)); + return new GraphHashes(Hash(graphInput), Hash(toolchain), Hash(graph)); + } + + private static object ToGraphInputDocument(CompilationGraphHashInputs inputs) => + new + { + schemaVersion = inputs.SchemaVersion, + projects = inputs + .Projects.OrderBy(project => project.Id, StringComparer.Ordinal) + .Select(project => new + { + id = project.Id, + path = project.LogicalPath, + targetFramework = project.TargetFramework, + }), + profiles = inputs + .Profiles.OrderBy(profile => profile.Id, StringComparer.Ordinal) + .Select(profile => new + { + id = profile.Id, + symbols = profile.Symbols.OrderBy(symbol => symbol, StringComparer.Ordinal), + }), + nodes = inputs.Nodes.OrderBy(node => NodeIdentity(node.Key), StringComparer.Ordinal).Select(ToNodeDocument), + edges = inputs + .Edges.OrderBy(edge => edge.FromProjectId, StringComparer.Ordinal) + .ThenBy(edge => edge.ToProjectId, StringComparer.Ordinal) + .Select(edge => new { from = edge.FromProjectId, to = edge.ToProjectId }), + captureTarget = ToFileDocument(inputs.CaptureTarget), + lockFile = new + { + present = inputs.LockFile.IsPresent, + file = inputs.LockFile.File is null ? null : ToFileDocument(inputs.LockFile.File), + }, + }; + + private static object ToToolchainDocument(ToolchainHashInput toolchain) => + new + { + sdkVersion = toolchain.SdkVersion, + msBuildVersion = toolchain.MSBuildVersion, + roslynIdentity = toolchain.RoslynIdentity, + compilerIdentity = toolchain.CompilerIdentity, + loaderIdentity = toolchain.LoaderIdentity, + files = toolchain.Files.OrderBy(file => file.LogicalPath, StringComparer.Ordinal).Select(ToFileDocument), + }; + + private static object ToGraphDocument(CompilationGraphHashInputs inputs) => + new + { + schemaVersion = inputs.SchemaVersion, + profiles = inputs + .Profiles.OrderBy(profile => profile.Id, StringComparer.Ordinal) + .Select(profile => new + { + id = profile.Id, + symbols = profile.Symbols.OrderBy(symbol => symbol, StringComparer.Ordinal), + }), + nodes = inputs + .Nodes.OrderBy(node => NodeIdentity(node.Key), StringComparer.Ordinal) + .Select(node => new + { + key = NodeIdentity(node.Key), + fingerprint = Hash(CanonicalJson.SerializeUtf8(ToNodeDocument(node))), + }), + edges = inputs + .Edges.OrderBy(edge => edge.FromProjectId, StringComparer.Ordinal) + .ThenBy(edge => edge.ToProjectId, StringComparer.Ordinal) + .Select(edge => new { from = edge.FromProjectId, to = edge.ToProjectId }), + }; + + private static object ToNodeDocument(NodeHashInput node) => + new + { + key = NodeIdentity(node.Key), + settings = node.Settings, + arguments = node + .Arguments.OrderBy(argument => argument.Ordinal) + .Select(argument => new { ordinal = argument.Ordinal, value = argument.Value }), + sources = node + .Sources.OrderBy(source => source.Ordinal) + .Select(source => new { ordinal = source.Ordinal, file = ToFileDocument(source.File) }), + references = node + .References.OrderBy(reference => reference.Identity, StringComparer.Ordinal) + .Select(reference => new + { + identity = reference.Identity, + file = ToFileDocument(reference.File), + aliases = reference.Aliases.OrderBy(alias => alias, StringComparer.Ordinal), + embedInteropTypes = reference.EmbedInteropTypes, + }), + projectReferences = node + .ProjectReferences.OrderBy(reference => reference.ProjectId, StringComparer.Ordinal) + .Select(reference => new { projectId = reference.ProjectId, metadata = reference.Metadata }), + analyzers = node + .Analyzers.OrderBy(analyzer => analyzer.Identity, StringComparer.Ordinal) + .Select(analyzer => new { identity = analyzer.Identity, file = ToFileDocument(analyzer.File) }), + additionalFiles = node + .AdditionalFiles.OrderBy(file => file.LogicalPath, StringComparer.Ordinal) + .Select(ToFileDocument), + editorConfigFiles = node + .EditorConfigFiles.OrderBy(file => file.LogicalPath, StringComparer.Ordinal) + .Select(ToFileDocument), + usings = node.Usings.OrderBy(file => file.LogicalPath, StringComparer.Ordinal).Select(ToFileDocument), + assets = node.Assets.OrderBy(file => file.LogicalPath, StringComparer.Ordinal).Select(ToFileDocument), + imports = node.Imports.OrderBy(file => file.LogicalPath, StringComparer.Ordinal).Select(ToFileDocument), + }; + + private static object ToFileDocument(GraphHashFile file) => + new + { + path = file.LogicalPath, + kind = file.Kind.ToString(), + content = Convert.ToBase64String(NormalizeContent(file)), + }; + + private static byte[] NormalizeContent(GraphHashFile file) + { + if (file.Kind == GraphHashFileKind.Binary) + return file.Content.ToArray(); + + if (file.Kind == GraphHashFileKind.Json) + return CanonicalJson.NormalizeJson(file.Content.AsSpan()); + + string text; + try + { + text = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString( + file.Content.AsSpan() + ); + } + catch (DecoderFallbackException exception) + { + throw new InvalidDataException($"Text file '{file.LogicalPath}' is not valid UTF-8.", exception); + } + return Encoding.UTF8.GetBytes(text.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n')); + } + + private static string NodeIdentity(RepositoryGraphNodeKey key) => + $"{key.ProjectId}/{key.TargetFramework}/{key.ProfileId}"; + + private static string Hash(ReadOnlySpan bytes) + { + Span digest = stackalloc byte[SHA256.HashSizeInBytes]; + SHA256.HashData(bytes, digest); + return Convert.ToHexString(digest).ToLowerInvariant(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphModels.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphModels.cs new file mode 100644 index 000000000..4c7c16282 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilationGraphModels.cs @@ -0,0 +1,467 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record RepositoryRoot +{ + internal RepositoryRoot(string path) + { + ArgumentException.ThrowIfNullOrWhiteSpace(path); + string fullPath = Path.GetFullPath(path); + if (!Path.IsPathFullyQualified(fullPath) || !Directory.Exists(fullPath)) + throw new DirectoryNotFoundException($"Repository root '{fullPath}' does not exist."); + FullPath = Path.TrimEndingDirectorySeparator(fullPath); + } + + internal string FullPath { get; } +} + +/// The closed set of build symbols deliberately exercised by conformance. +internal sealed record BuildProfile +{ + public BuildProfile(string id, IReadOnlyList additionalSymbols) + { + if (string.IsNullOrWhiteSpace(id)) + throw new ArgumentException("A build profile ID is required.", nameof(id)); + ArgumentNullException.ThrowIfNull(additionalSymbols); + if (additionalSymbols.Any(symbol => string.IsNullOrWhiteSpace(symbol))) + throw new ArgumentException("Profile symbols must be nonempty.", nameof(additionalSymbols)); + + Id = id; + AdditionalSymbols = new ReadOnlyCollection(additionalSymbols.ToArray()); + } + + public string Id { get; } + + public IReadOnlyList AdditionalSymbols { get; } +} + +internal sealed record RepositoryProjectDefinition +{ + public RepositoryProjectDefinition( + string id, + string relativePath, + string targetFramework, + IReadOnlyList directOwnedReferences + ) + { + if (string.IsNullOrWhiteSpace(id)) + throw new ArgumentException("A project ID is required.", nameof(id)); + if (string.IsNullOrWhiteSpace(relativePath)) + throw new ArgumentException("A project path is required.", nameof(relativePath)); + if (string.IsNullOrWhiteSpace(targetFramework)) + throw new ArgumentException("A target framework is required.", nameof(targetFramework)); + ArgumentNullException.ThrowIfNull(directOwnedReferences); + + Id = id; + RelativePath = relativePath; + TargetFramework = targetFramework; + DirectOwnedReferences = new ReadOnlyCollection(directOwnedReferences.ToArray()); + } + + public string Id { get; } + + public string RelativePath { get; } + + public string TargetFramework { get; } + + public IReadOnlyList DirectOwnedReferences { get; } +} + +internal sealed record RepositoryGraphNodeKey +{ + internal RepositoryGraphNodeKey(string projectId, string targetFramework, string profileId) + { + Validate(projectId, nameof(projectId)); + Validate(targetFramework, nameof(targetFramework)); + Validate(profileId, nameof(profileId)); + ProjectId = projectId; + TargetFramework = targetFramework; + ProfileId = profileId; + } + + internal string ProjectId { get; } + internal string TargetFramework { get; } + internal string ProfileId { get; } + + private static void Validate(string value, string name) + { + if (string.IsNullOrWhiteSpace(value) || value.Contains('/') || value.Contains('\\')) + { + throw new ArgumentException( + "Node identity segments must be nonempty and contain no path separators.", + name + ); + } + } +} + +internal sealed record RepositoryGraphNode +{ + public RepositoryGraphNode(string projectId, string projectPath, string targetFramework, BuildProfile profile) + { + if (string.IsNullOrWhiteSpace(projectId)) + throw new ArgumentException("A project ID is required.", nameof(projectId)); + if (string.IsNullOrWhiteSpace(projectPath)) + throw new ArgumentException("A project path is required.", nameof(projectPath)); + if (string.IsNullOrWhiteSpace(targetFramework)) + throw new ArgumentException("A target framework is required.", nameof(targetFramework)); + ArgumentNullException.ThrowIfNull(profile); + + ProjectId = projectId; + ProjectPath = projectPath; + TargetFramework = targetFramework; + Profile = profile; + } + + public string ProjectId { get; } + + public string ProjectPath { get; } + + public string TargetFramework { get; } + + public BuildProfile Profile { get; } + + public RepositoryGraphNodeKey Key => new(ProjectId, TargetFramework, Profile.Id); +} + +internal sealed record RepositoryProjectEdge(string FromProjectId, string ToProjectId); + +/// Resolves one target from a multi-target project only when the choice is explicit. +internal static class RepositoryTargetFrameworkSelection +{ + internal static string Select(IReadOnlyList candidates, string? configuredSelection) + { + ArgumentNullException.ThrowIfNull(candidates); + string[] distinct = candidates + .Where(candidate => !string.IsNullOrWhiteSpace(candidate)) + .Distinct(StringComparer.Ordinal) + .ToArray(); + if (distinct.Length == 0) + throw new InvalidDataException("A project must expose at least one target framework."); + if (configuredSelection is null) + { + if (distinct.Length != 1) + { + throw new InvalidDataException( + "Multi-target project selection is ambiguous without an explicit target framework." + ); + } + return distinct[0]; + } + + if (!distinct.Contains(configuredSelection, StringComparer.Ordinal)) + throw new InvalidDataException($"Configured target framework '{configuredSelection}' is not available."); + return configuredSelection; + } +} + +/// Immutable, validated model of the fixed four-project/four-profile graph. +internal sealed class RepositoryCompilationGraph +{ + private static readonly RepositoryProjectDefinition[] FixedProjects = + { + new("machine", "src/SIL.Machine/SIL.Machine.csproj", "netstandard2.0", Array.Empty()), + new( + "hc", + "src/SIL.Machine.Morphology.HermitCrab/SIL.Machine.Morphology.HermitCrab.csproj", + "netstandard2.0", + new[] { "machine" } + ), + new( + "hc-tool", + "src/SIL.Machine.Morphology.HermitCrab.Tool/SIL.Machine.Morphology.HermitCrab.Tool.csproj", + "net10.0", + new[] { "hc" } + ), + new( + "hc-conformance", + "src/SIL.Machine.Morphology.HermitCrab.Conformance/SIL.Machine.Morphology.HermitCrab.Conformance.csproj", + "net10.0", + new[] { "hc", "hc-tool" } + ), + }; + + private static readonly BuildProfile[] FixedProfiles = + { + new("base", Array.Empty()), + new("single-threaded", new[] { "SINGLE_THREADED" }), + new("output-analyses", new[] { "OUTPUT_ANALYSES" }), + new("combined", new[] { "SINGLE_THREADED", "OUTPUT_ANALYSES" }), + }; + + private RepositoryCompilationGraph( + IReadOnlyList projects, + IReadOnlyList profiles, + IReadOnlyList nodes, + IReadOnlyList projectEdges, + IReadOnlyDictionary? captures = null, + IReadOnlyDictionary? compilerInputs = null, + CompilationGraphHashInputs? hashInputs = null, + GraphHashes? hashes = null + ) + { + Projects = new ReadOnlyCollection(projects.ToArray()); + Profiles = new ReadOnlyCollection(profiles.ToArray()); + Nodes = new ReadOnlyCollection(nodes.ToArray()); + ProjectEdges = new ReadOnlyCollection(projectEdges.ToArray()); + Captures = new ReadOnlyDictionary( + new Dictionary( + captures ?? new Dictionary() + ) + ); + CompilerInputs = new ReadOnlyDictionary( + new Dictionary( + compilerInputs ?? new Dictionary() + ) + ); + _hashInputs = hashInputs; + _hashes = hashes; + } + + internal IReadOnlyList Projects { get; } + + internal IReadOnlyList Profiles { get; } + + internal IReadOnlyList Nodes { get; } + + internal IReadOnlyList ProjectEdges { get; } + + internal IReadOnlyDictionary Captures { get; } + + internal IReadOnlyDictionary CompilerInputs { get; } + + private readonly CompilationGraphHashInputs? _hashInputs; + private readonly GraphHashes? _hashes; + + internal CompilationGraphHashInputs HashInputs => + _hashInputs ?? throw new InvalidOperationException("Compilation graph hashes have not been attached."); + + internal GraphHashes Hashes => + _hashes ?? throw new InvalidOperationException("Compilation graph hashes have not been attached."); + + internal static RepositoryCompilationGraph CreateFixed() + { + var nodes = new List(FixedProjects.Length * FixedProfiles.Length); + foreach (RepositoryProjectDefinition project in FixedProjects) + { + foreach (BuildProfile profile in FixedProfiles) + nodes.Add(new RepositoryGraphNode(project.Id, project.RelativePath, project.TargetFramework, profile)); + } + + return Create(nodes, FixedEdges()); + } + + internal static RepositoryCompilationGraph Create( + IEnumerable nodes, + IEnumerable projectEdges + ) + { + ArgumentNullException.ThrowIfNull(nodes); + ArgumentNullException.ThrowIfNull(projectEdges); + RepositoryGraphNode[] nodeArray = nodes.ToArray(); + RepositoryProjectEdge[] edgeArray = projectEdges.ToArray(); + ValidateNodes(nodeArray); + ValidateEdges(edgeArray); + return new RepositoryCompilationGraph(FixedProjects, FixedProfiles, nodeArray, edgeArray); + } + + internal RepositoryCompilationGraph WithCaptures( + IReadOnlyDictionary captures + ) + { + ArgumentNullException.ThrowIfNull(captures); + if (captures.Count != Nodes.Count || !captures.Keys.ToHashSet().SetEquals(Nodes.Select(node => node.Key))) + throw new InvalidDataException("Compiler captures must cover every fixed graph node exactly once."); + return new RepositoryCompilationGraph( + Projects, + Profiles, + Nodes, + ProjectEdges, + captures, + CompilerInputs, + _hashInputs, + _hashes + ); + } + + internal RepositoryCompilationGraph WithCompilerInputs( + IReadOnlyDictionary compilerInputs + ) + { + ArgumentNullException.ThrowIfNull(compilerInputs); + if ( + compilerInputs.Count != Nodes.Count + || !compilerInputs.Keys.ToHashSet().SetEquals(Nodes.Select(node => node.Key)) + ) + { + throw new InvalidDataException( + "Normalized compiler inputs must cover every fixed graph node exactly once." + ); + } + return new RepositoryCompilationGraph( + Projects, + Profiles, + Nodes, + ProjectEdges, + Captures, + compilerInputs, + _hashInputs, + _hashes + ); + } + + internal RepositoryCompilationGraph WithHashInputs(CompilationGraphHashInputs hashInputs) + { + ArgumentNullException.ThrowIfNull(hashInputs); + if (Captures.Count != Nodes.Count || CompilerInputs.Count != Nodes.Count) + throw new InvalidDataException("Hash inputs require complete compiler captures and normalized inputs."); + if ( + hashInputs.Nodes.Length != Nodes.Count + || !hashInputs.Nodes.Select(node => node.Key).ToHashSet().SetEquals(Nodes.Select(node => node.Key)) + ) + { + throw new InvalidDataException("Hash inputs must cover every fixed graph node exactly once."); + } + return new RepositoryCompilationGraph( + Projects, + Profiles, + Nodes, + ProjectEdges, + Captures, + CompilerInputs, + hashInputs, + null + ); + } + + internal RepositoryCompilationGraph WithHashes(GraphHashes hashes) + { + ArgumentNullException.ThrowIfNull(hashes); + if (_hashInputs is null) + throw new InvalidDataException("Graph hashes require hash inputs."); + GraphHashes expected = CompilationGraphHashing.Compute(_hashInputs); + if (!expected.Equals(hashes)) + throw new InvalidDataException("Graph hashes do not match the attached hash inputs."); + return new RepositoryCompilationGraph( + Projects, + Profiles, + Nodes, + ProjectEdges, + Captures, + CompilerInputs, + _hashInputs, + hashes + ); + } + + private static IEnumerable FixedEdges() + { + yield return new RepositoryProjectEdge("hc", "machine"); + yield return new RepositoryProjectEdge("hc-tool", "hc"); + yield return new RepositoryProjectEdge("hc-conformance", "hc"); + yield return new RepositoryProjectEdge("hc-conformance", "hc-tool"); + } + + private static void ValidateNodes(IReadOnlyList nodes) + { + var expected = ( + from project in FixedProjects + from profile in FixedProfiles + select new RepositoryGraphNodeKey(project.Id, project.TargetFramework, profile.Id) + ).ToHashSet(); + var actual = new HashSet(); + foreach (RepositoryGraphNode node in nodes) + { + if (!actual.Add(node.Key)) + { + throw new InvalidDataException($"Duplicate compilation graph node '{node.Key}'."); + } + + RepositoryProjectDefinition? project = FixedProjects.SingleOrDefault(item => item.Id == node.ProjectId); + if ( + project is null + || !string.Equals(project.RelativePath, node.ProjectPath, StringComparison.Ordinal) + || !string.Equals(project.TargetFramework, node.TargetFramework, StringComparison.Ordinal) + ) + { + throw new InvalidDataException( + $"Compilation graph node '{node.Key}' is outside the fixed project table." + ); + } + if ( + !FixedProfiles.Any(profile => + string.Equals(profile.Id, node.Profile.Id, StringComparison.Ordinal) + && profile.AdditionalSymbols.SequenceEqual(node.Profile.AdditionalSymbols, StringComparer.Ordinal) + ) + ) + { + throw new InvalidDataException($"Compilation graph node '{node.Key}' uses an unknown profile."); + } + } + + if (!actual.SetEquals(expected)) + { + throw new InvalidDataException( + "Compilation graph must contain exactly the sixteen fixed project/profile nodes." + ); + } + } + + private static void ValidateEdges(IReadOnlyList edges) + { + if (edges.Count != edges.Distinct().Count()) + throw new InvalidDataException("Compilation graph contains duplicate project edges."); + + HashSet projectIds = FixedProjects.Select(project => project.Id).ToHashSet(StringComparer.Ordinal); + foreach (RepositoryProjectEdge edge in edges) + { + if (!projectIds.Contains(edge.FromProjectId) || !projectIds.Contains(edge.ToProjectId)) + throw new InvalidDataException("Compilation graph contains a project-external edge."); + if (string.Equals(edge.FromProjectId, edge.ToProjectId, StringComparison.Ordinal)) + throw new InvalidDataException("Compilation graph contains a self-cycle."); + } + + var expected = FixedEdges().ToHashSet(); + if (!edges.ToHashSet().SetEquals(expected)) + throw new InvalidDataException("Compilation graph edges do not match the fixed direct-reference table."); + + var outgoing = edges + .GroupBy(edge => edge.FromProjectId) + .ToDictionary( + group => group.Key, + group => group.Select(edge => edge.ToProjectId).ToArray(), + StringComparer.Ordinal + ); + var visiting = new HashSet(StringComparer.Ordinal); + var visited = new HashSet(StringComparer.Ordinal); + foreach (string projectId in projectIds) + Visit(projectId, outgoing, visiting, visited); + } + + private static void Visit( + string projectId, + IReadOnlyDictionary outgoing, + ISet visiting, + ISet visited + ) + { + if (visited.Contains(projectId)) + return; + if (!visiting.Add(projectId)) + throw new InvalidDataException("Compilation graph contains a cycle."); + if (outgoing.TryGetValue(projectId, out string[]? dependencies)) + { + foreach (string dependency in dependencies) + Visit(dependency, outgoing, visiting, visited); + } + visiting.Remove(projectId); + visited.Add(projectId); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilerInputModel.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilerInputModel.cs new file mode 100644 index 000000000..55397f5a6 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilerInputModel.cs @@ -0,0 +1,42 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed class CompilerInputException : Exception +{ + internal CompilerInputException(string code, string message, Exception? inner = null) + : base(message, inner) => Code = code; + + internal string Code { get; } +} + +internal sealed record CompilerToolchainIdentity(string CompilerDirectory); + +internal enum AnalyzerDisposition +{ + Ordinary, + SdkOwnedSourceGeneratorPendingProbe, +} + +internal sealed record CompilerInputModel( + CommandLineArguments Arguments, + IReadOnlyList Symbols, + IReadOnlyList Sources, + IReadOnlyList Analyzers, + IReadOnlyList AdditionalFiles, + IReadOnlyList AnalyzerConfigs +); + +internal sealed record CompilerAuxiliaryInput(string Path, ImmutableArray Content); + +internal enum CompilerSourceKind +{ + Owned, + GeneratedSupport, +} + +internal sealed record CompilerSourceClassification(string Path, CompilerSourceKind Kind, ImmutableArray Content); diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilerSourceClassifier.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilerSourceClassifier.cs new file mode 100644 index 000000000..79f5d8ef8 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CompilerSourceClassifier.cs @@ -0,0 +1,121 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed class CompilerSourceClassifier +{ + private readonly string _repositoryRoot; + private readonly string _projectDirectory; + private readonly string _intermediateDirectory; + private readonly string _assemblyInfoPath; + private readonly string _targetFrameworkAttributesPath; + + internal CompilerSourceClassifier( + string repositoryRoot, + string projectDirectory, + string intermediateDirectory, + string assemblyInfoPath, + string targetFrameworkAttributesPath + ) + { + _repositoryRoot = Canonical(repositoryRoot); + _projectDirectory = Canonical(projectDirectory); + _intermediateDirectory = Canonical(intermediateDirectory); + _assemblyInfoPath = Canonical(assemblyInfoPath); + _targetFrameworkAttributesPath = Canonical(targetFrameworkAttributesPath); + if ( + !IsWithin(_assemblyInfoPath, _intermediateDirectory) + || !IsWithin(_targetFrameworkAttributesPath, _intermediateDirectory) + ) + { + throw new CompilerInputException( + "unsupported-compiler-source", + "MSBuild generated-source paths must remain within the private intermediate directory." + ); + } + } + + internal CompilerSourceKind Classify(string path, IReadOnlyDictionary? metadata = null) + { + string canonical = Canonical(path); + if (IsWithin(canonical, _intermediateDirectory)) + { + if (IsAdmittedGeneratedPath(canonical)) + return CompilerSourceKind.GeneratedSupport; + throw new CompilerInputException( + "unsupported-compiler-source", + $"Generated source '{path}' is not an admitted SDK support input." + ); + } + + if (Path.GetFileName(canonical).Equals("GlobalUsings.g.cs", StringComparison.OrdinalIgnoreCase)) + { + throw new CompilerInputException( + "unsupported-implicit-global-using", + "Implicit global using source is not supported." + ); + } + + if ( + IsWithin(canonical, _projectDirectory) + && IsWithin(canonical, _repositoryRoot) + && !HasGeneratedMetadata(metadata) + && !ContainsBuildDirectory(canonical) + ) + { + return CompilerSourceKind.Owned; + } + + throw new CompilerInputException( + "unsupported-compiler-source", + $"Compiler source '{path}' is outside the admitted source set." + ); + } + + private bool IsAdmittedGeneratedPath(string path) + { + StringComparison comparison = OperatingSystem.IsWindows() + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + return path.Equals(_assemblyInfoPath, comparison) || path.Equals(_targetFrameworkAttributesPath, comparison); + } + + private static bool HasGeneratedMetadata(IReadOnlyDictionary? metadata) => + metadata is not null + && ( + ( + metadata.TryGetValue("Generated", out string? generated) + && generated.Equals("true", StringComparison.OrdinalIgnoreCase) + ) + || ( + metadata.TryGetValue("AutoGen", out string? autoGen) + && autoGen.Equals("true", StringComparison.OrdinalIgnoreCase) + ) + ); + + private bool ContainsBuildDirectory(string path) + { + string relative = Path.GetRelativePath(_projectDirectory, path); + return relative + .Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + .Any(segment => + segment.Equals("bin", StringComparison.OrdinalIgnoreCase) + || segment.Equals("obj", StringComparison.OrdinalIgnoreCase) + ); + } + + private static string Canonical(string path) => Path.TrimEndingDirectorySeparator(Path.GetFullPath(path)); + + private static bool IsWithin(string path, string directory) + { + StringComparison comparison = OperatingSystem.IsWindows() + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + return path.Equals(directory, comparison) + || path.StartsWith(directory + Path.DirectorySeparatorChar, comparison); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConformanceManifestArtifact.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConformanceManifestArtifact.cs new file mode 100644 index 000000000..f65660fda --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConformanceManifestArtifact.cs @@ -0,0 +1,47 @@ +#nullable enable +using System.Collections.Generic; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Provenance and integrity for the conformance fixtures PanGloss imports. +/// Deliberately not a second copy of the ground truth. words.yaml is the single +/// canonical authored format -- it carries the reasoning for each fixture in comments, which no +/// generated JSON can hold -- and grammar.xml is the authoritative grammar. This manifest +/// records what those files are, which format each conforms to, and the hash a consumer verifies +/// them against. +public sealed record ConformanceManifest( + string FormatVersion, + string WordsAuthoringFormatVersion, + string GrammarFormatVersion, + string DtdPath, + string DtdSha256, + string SourceHash, + IReadOnlyList Fixtures +) +{ + public const string ManifestFormat = "hc-conformance-manifest/v1"; + public const string WordsFormat = "hc-conformance-words/v1"; + public const string GrammarFormat = "sil-machine-hermit-crab-input-xml/v1"; +} + +/// Cases authored in words.yaml, so a consumer can detect a partial +/// read without parsing the file. +public sealed record ManifestFixture( + string FixtureId, + string Category, + string DisplayLanguage, + string GrammarPath, + string GrammarSha256, + string WordsPath, + string WordsSha256, + int CaseCount, + bool ExpectedCrash +); + +/// Canonical serialization of the manifest. +public static class ManifestJson +{ + public static string Serialize(ConformanceManifest manifest) => CanonicalJson.Serialize(manifest); + + public static byte[] SerializeUtf8(ConformanceManifest manifest) => CanonicalJson.SerializeUtf8(manifest); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConformanceManifestGenerator.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConformanceManifestGenerator.cs new file mode 100644 index 000000000..1d4fd9475 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConformanceManifestGenerator.cs @@ -0,0 +1,134 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Builds the from the checked-in fixtures. +/// Nothing here interprets a grammar or restates a words file; each contributes a +/// repository-relative path and a hash. The authored files stay the only ground truth. +public static class ConformanceManifestGenerator +{ + /// Files the manifest's own validity depends on, beyond the fixtures themselves. + private static readonly string[] AdditionalSourceFiles = + { + "conformance/constructs.txt", + "conformance/parity-check.py", + "conformance/schema/words.schema.json", + "conformance/schema/conformance-manifest.schema.json", + }; + + public static ConformanceManifest Generate(string repositoryRoot) + { + ArgumentException.ThrowIfNullOrWhiteSpace(repositoryRoot); + string root = Path.TrimEndingDirectorySeparator(Path.GetFullPath(repositoryRoot)); + string dtdRelative = GrammarCoverageGate.DtdRelativePath; + string dtdHash = HashFile(Path.Combine(root, dtdRelative.Replace('/', Path.DirectorySeparatorChar))); + + List fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + var mapped = fixtures + .Select(fixture => MapFixture(fixture, root)) + .OrderBy(fixture => fixture.FixtureId, StringComparer.Ordinal) + .ToArray(); + + return new ConformanceManifest( + ConformanceManifest.ManifestFormat, + ConformanceManifest.WordsFormat, + ConformanceManifest.GrammarFormat, + dtdRelative, + dtdHash, + SourceHash(root, mapped, dtdRelative, dtdHash), + mapped + ); + } + + private static ManifestFixture MapFixture(Fixture fixture, string root) + { + string fixtureId = RelativePath(fixture.Directory, Path.Combine(root, "conformance")); + string grammarPath = "conformance/" + fixtureId + "/grammar.xml"; + string wordsPath = "conformance/" + fixtureId + "/words.yaml"; + WordsYaml words = fixture.Words; + + string[] duplicates = words + .Words.Select(word => word.Word) + .GroupBy(input => input, StringComparer.Ordinal) + .Where(group => group.Count() > 1) + .Select(group => group.Key) + .OrderBy(input => input, StringComparer.Ordinal) + .ToArray(); + if (duplicates.Length != 0) + { + throw new InvalidDataException( + $"Fixture '{fixtureId}' repeats input(s): {string.Join(", ", duplicates)}. Inputs must be unique within a fixture." + ); + } + + if (words.ExpectCrash && words.Words.Count != 1) + { + throw new InvalidDataException( + $"Fixture '{fixtureId}' declares expect_crash and must contain exactly one case, but has {words.Words.Count}." + ); + } + + return new ManifestFixture( + fixtureId, + fixtureId.StartsWith("languages/", StringComparison.Ordinal) ? "language" : "edge-case", + words.Language, + grammarPath, + HashFile(Path.Combine(root, grammarPath.Replace('/', Path.DirectorySeparatorChar))), + wordsPath, + HashFile(Path.Combine(root, wordsPath.Replace('/', Path.DirectorySeparatorChar))), + words.Words.Count, + words.ExpectCrash + ); + } + + private static string RelativePath(string path, string basePath) => + Path.GetRelativePath(basePath, path).Replace('\\', '/'); + + /// Hash of every file the manifest's validity rests on. + /// Path- and EOL-invariant: only repository-relative paths and LF-normalized text + /// participate, so relocating the checkout or changing line endings cannot move it. + private static string SourceHash( + string root, + IReadOnlyList fixtures, + string dtdRelative, + string dtdHash + ) + { + var text = new StringBuilder(); + text.Append(ConformanceManifest.ManifestFormat).Append('\n'); + text.Append(dtdRelative).Append('\0').Append(dtdHash).Append('\n'); + foreach (ManifestFixture fixture in fixtures) + { + text.Append(fixture.FixtureId) + .Append('\0') + .Append(fixture.GrammarSha256) + .Append('\0') + .Append(fixture.WordsSha256) + .Append('\n'); + } + + foreach (string relative in AdditionalSourceFiles.OrderBy(path => path, StringComparer.Ordinal)) + { + string absolute = Path.Combine(root, relative.Replace('/', Path.DirectorySeparatorChar)); + text.Append(relative) + .Append('\0') + .Append(File.Exists(absolute) ? HashFile(absolute) : "") + .Append('\n'); + } + + return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(text.ToString()))).ToLowerInvariant(); + } + + /// SHA-256 of a file's text with line endings normalized to LF. + internal static string HashFile(string path) + { + string content = File.ReadAllText(path).Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n'); + return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(content))).ToLowerInvariant(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConstructClaimCorroboration.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConstructClaimCorroboration.cs new file mode 100644 index 000000000..5e1998b01 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ConstructClaimCorroboration.cs @@ -0,0 +1,296 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Whether a word's/parse's self-reported exercises: claim (a free-text string drawn from +/// conformance/constructs.txt) can be cross-checked against the fixture's own grammar.xml. +/// This is a STRUCTURAL check only -- like , not +/// like -- so a "Confirmed" claim means the named DTD +/// element/attribute is genuinely present in this fixture's grammar, never that the word's parse +/// actually depends on it. +/// +public enum ConstructClaimStatus +{ + /// At least one DTD identifier mapped from the construct's text is present in this + /// fixture's grammar.xml. + Confirmed, + + /// DTD identifiers were mapped from the construct's text, but none of them appear + /// anywhere in this fixture's grammar.xml -- the claim looks wrong. + Contradicted, + + /// The construct's text contains no identifier this mapping can recognize, so the claim + /// cannot be mechanically checked at all (neither confirmed nor contradicted). + Unmapped, +} + +/// +/// Cross-checks every exercises: claim in every fixture's words.yaml against that +/// fixture's own grammar.xml. is the one place judgment +/// enters this generator: a construct string in constructs.txt is free-text prose, not a DTD +/// identifier, so recognizing which DTD element/attribute names it names has to be a text match, not +/// a lookup. Two conservative rules keep that match from just re-finding ordinary English words: +/// element names are matched case-SENSITIVELY (the DTD always capitalizes them, and construct prose +/// does too, so an accidental match would require the exact PascalCase spelling); attribute names are +/// matched only when they contain an internal capital (a real multi-word compound like +/// isActive or requiredStemName) -- a bare single-word attribute like type, +/// name, or feature is excluded outright, because those words appear in ordinary English +/// prose often enough that "confirmed" would stop meaning anything. +/// +public static class ConstructClaimCorroboration +{ + public const string RelativePath = "conformance/construct-claim-corroboration.tsv"; + + private const string NullField = "-"; + private const int ColumnCount = 6; + + public sealed record Row( + string Fixture, + string Word, + string Signature, + string Construct, + ConstructClaimStatus Status, + IReadOnlyList MatchedTokens + ); + + /// Every construct string mapped to the DTD element/attribute names its text names. + public static IReadOnlyDictionary> MapConstructsToDtdTokens( + IReadOnlyList constructs, + SemanticInventory inventory + ) + { + ArgumentNullException.ThrowIfNull(constructs); + ArgumentNullException.ThrowIfNull(inventory); + + string[] elementNames = inventory + .Surfaces.Where(s => s.Kind == "element") + .Select(s => s.Name) + .Distinct(StringComparer.Ordinal) + .ToArray(); + // "an internal capital" = at least one uppercase letter after the first character, which is + // exactly the shape a multi-word camelCase attribute name has and a bare English word does not. + string[] attributeNames = inventory + .Surfaces.Where(s => s.Kind == "attribute") + .Select(s => s.Name) + .Distinct(StringComparer.Ordinal) + .Where(name => name.Length > 1 && name[1..].Any(char.IsUpper)) + .ToArray(); + + var result = new Dictionary>(StringComparer.Ordinal); + foreach (string construct in constructs) + { + var matched = new List(); + foreach (string element in elementNames) + { + if (Regex.IsMatch(construct, $@"\b{Regex.Escape(element)}\b")) + matched.Add(element); + } + foreach (string attribute in attributeNames) + { + if (Regex.IsMatch(construct, $@"\b{Regex.Escape(attribute)}\b", RegexOptions.IgnoreCase)) + matched.Add(attribute); + } + result[construct] = matched + .Distinct(StringComparer.Ordinal) + .OrderBy(t => t, StringComparer.Ordinal) + .ToArray(); + } + return result; + } + + /// Whether carries any element or non-empty attribute named in + /// . + private static bool GrammarContainsAnyToken(XDocument grammar, IReadOnlyList tokens) + { + if (tokens.Count == 0) + return false; + + var tokenSet = new HashSet(tokens, StringComparer.OrdinalIgnoreCase); + foreach (XElement element in grammar.Descendants()) + { + if (tokenSet.Contains(element.Name.LocalName)) + return true; + foreach (XAttribute attribute in element.Attributes()) + { + if (!string.IsNullOrEmpty(attribute.Value) && tokenSet.Contains(attribute.Name.LocalName)) + return true; + } + } + return false; + } + + /// + /// One row per exercises: claim across every fixture -- the same (fixture, word, signature, + /// construct) shape already emits into + /// conformance/coverage.csv, with a corroboration status joined on. Cheap: no reparse, just + /// the DTD (once) and every fixture's already-loaded grammar.xml and words.yaml. + /// + public static IReadOnlyList Compute(string repositoryRoot, string constructsPath) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(constructsPath); + + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(repositoryRoot); + List constructs = CoverageReport.LoadConstructChecklist(constructsPath); + IReadOnlyDictionary> mapping = MapConstructsToDtdTokens(constructs, inventory); + + var rows = new List(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + var statusCache = new Dictionary(StringComparer.Ordinal); + + ConstructClaimStatus StatusFor(string construct) + { + if (statusCache.TryGetValue(construct, out ConstructClaimStatus cached)) + return cached; + + IReadOnlyList tokens = mapping.TryGetValue(construct, out IReadOnlyList? found) + ? found + : Array.Empty(); + ConstructClaimStatus status = + tokens.Count == 0 ? ConstructClaimStatus.Unmapped + : GrammarContainsAnyToken(grammar, tokens) ? ConstructClaimStatus.Confirmed + : ConstructClaimStatus.Contradicted; + statusCache[construct] = status; + return status; + } + + void AddClaim(string word, string signature, string construct) + { + IReadOnlyList tokens = mapping.TryGetValue(construct, out IReadOnlyList? found) + ? found + : Array.Empty(); + rows.Add(new Row(fixture.Id, word, signature, construct, StatusFor(construct), tokens)); + } + + foreach (WordEntry word in fixture.Words.Words) + { + if (word.ExpectFail || word.ExpectSkip) + { + foreach (string construct in word.Exercises) + AddClaim(word.Word, "", construct); + } + else + { + foreach (ParseEntry parse in word.Parses) + { + foreach ( + string construct in parse.Exercises.Concat(word.Exercises).Distinct(StringComparer.Ordinal) + ) + { + AddClaim(word.Word, parse.Signature, construct); + } + } + } + } + } + + return rows.OrderBy(r => r.Fixture, StringComparer.Ordinal) + .ThenBy(r => r.Word, StringComparer.Ordinal) + .ThenBy(r => r.Signature, StringComparer.Ordinal) + .ThenBy(r => r.Construct, StringComparer.Ordinal) + .ToArray(); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine("# GENERATED by hc-conformance --write-coverage-traceability. One row per words.yaml"); + writer.WriteLine("# 'exercises:' claim (self-reported by the fixture author), cross-checked against that"); + writer.WriteLine( + "# fixture's OWN grammar.xml. This is a STRUCTURAL check, not a semantic one: Confirmed means" + ); + writer.WriteLine( + "# the construct text names a DTD element/attribute this grammar actually contains, never that" + ); + writer.WriteLine( + "# the word's parse depends on it. Contradicted means identifiers were found in the construct's" + ); + writer.WriteLine( + "# text but none appear in this grammar -- the claim looks wrong. Unmapped means the construct's" + ); + writer.WriteLine( + "# text contains no identifier ConstructClaimCorroboration recognizes, so it cannot be checked" + ); + writer.WriteLine( + "# either way. matched_tokens is empty for Unmapped. signature is \"-\" for expect_fail/expect_skip words." + ); + writer.WriteLine("fixture\tword\tsignature\tconstruct\tstatus\tmatched_tokens"); + foreach ( + Row row in rows.OrderBy(r => r.Fixture, StringComparer.Ordinal) + .ThenBy(r => r.Word, StringComparer.Ordinal) + .ThenBy(r => r.Signature, StringComparer.Ordinal) + .ThenBy(r => r.Construct, StringComparer.Ordinal) + ) + { + writer.WriteLine( + string.Join( + '\t', + row.Fixture, + row.Word, + row.Signature.Length == 0 ? NullField : row.Signature, + row.Construct, + row.Status, + // Trailing-tab safety: Read() trims each raw line, which would otherwise eat an + // empty last field (Unmapped rows have no matched tokens) along with real + // whitespace -- see InterfaceInventoryLedger's identical fix for why "-" and not "". + row.MatchedTokens.Count == 0 + ? NullField + : string.Join(",", row.MatchedTokens) + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("fixture\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[4], out ConstructClaimStatus status)) + throw new FormatException($"{RelativePath}: unknown status '{fields[4]}'"); + + IReadOnlyList tokens = fields[5] is "" or NullField ? Array.Empty() : fields[5].Split(','); + rows.Add(new Row(fields[0], fields[1], fields[2] == NullField ? "" : fields[2], fields[3], status, tokens)); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CounterfactualGate.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CounterfactualGate.cs new file mode 100644 index 000000000..4b7822928 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CounterfactualGate.cs @@ -0,0 +1,799 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// The states a grammar-observable surface may end in; only the first three are evidence. +public enum CounterfactualVerdict +{ + /// Neutralizing the surface changed the result. The delta is the evidence. + Evidenced, + + /// + /// Neutralizing the surface made XmlLanguageLoader's own code throw -- an IDREF lookup, a + /// feature/coercion failure, or similar -- after the document already passed generic XML/DTD + /// validation. This is a genuine engine-semantic witness: the failure could only happen because + /// HermitCrab's loader actually consulted the surface. Strictly weaker than + /// (no word ever parses to show a delta) but a real parse-time observation, unlike + /// . + /// + RequiredByLoader, + + /// + /// The surface only changed a result when jointly activated with an independent referencing + /// declaration; flipping either alone did not. Strictly weaker than and + /// -- it pins the delta on the PAIR, and the partner's own necessity + /// check (not just the target's) is what the pair's three-run record has to show. Stronger than + /// : it still comes from a real three-run parse, not a document that + /// never reached the engine at all. + /// + EvidencedJointly, + + /// + /// Neutralizing the surface removed something the DTD's own content model requires -- an element + /// whose parent's declared sequence no longer validates, or (in the limit) the document's root, so + /// the document fails XmlReader's generic DTD validation before XmlLanguageLoader runs + /// a single line. This re-derives what Level 1's static DTD enumeration already knows and is + /// not equally conclusive with : no HermitCrab-specific code, and no + /// word, was ever reached. A Rust engine that loads every such grammar and then silently ignores the + /// construct at parse time is indistinguishable from a correct one on this verdict alone. + /// + RequiredByDtd, + + /// The mutant did not finish in time. A timing race is not a semantic delta. + Timeout, + + /// Neutralizing the surface changed nothing. Not evidence; fails unless a proof applies. + Unobservable, +} + +/// +/// // +/// are captured structurally at the moment compares a mutant against +/// the baseline, so a caller building an record never has to regex +/// 's prose. Left at their defaults (null / ) +/// for verdicts that are not evidence. is every fixture +/// found reaching this exact for +/// -- is only the first-discovered of that +/// set, kept for the example fields above, never the only one; null outside Sweep's own merge, +/// where "which fixture(s)" is not yet a question being asked. +/// +public sealed record CounterfactualResult( + string SurfaceId, + string FixtureId, + CounterfactualVerdict Verdict, + string Mutation, + string Delta, + string? ExampleWord = null, + string? ExampleOutcome = null, + CounterexampleKind CounterexampleKind = CounterexampleKind.None, + string? CounterexampleOutcome = null, + IReadOnlyList? WitnessingFixtures = null +); + +/// One word's measured parse time, for diagnosing which fixtures or mutants run slow. +public sealed record WordTiming(string Phase, string FixtureId, string? SurfaceId, string Word, long ElapsedMs); + +/// +/// Decides whether a surface is load-bearing by running a fixture twice: once as written, once with the +/// surface neutralized. A difference in the parse results is the evidence; no difference means the +/// fixture does not show the surface matters, whatever else it might declare. +/// +public static class CounterfactualGate +{ + /// The parse outcome of one word, reduced to what a fixture actually asserts. + private static string Outcome(Morpher morpher, string word, Action? onTimed) + { + try + { + (string status, long elapsedMs, string signature) = SignatureFormat.ParseOneWord(morpher, word); + onTimed?.Invoke(word, elapsedMs); + return $"{status}::{signature}"; + } + catch (Exception ex) + { + // A mutated grammar may drive the engine into a state the original never reaches. That is a + // difference in outcome, so it counts as a delta rather than aborting the run. + return $"threw::{ex.GetType().Name}"; + } + } + + private static IReadOnlyList Outcomes( + string grammarPath, + IReadOnlyList words, + Action? onTimed = null + ) + { + Language language = XmlLanguageLoader.Load(grammarPath); + var morpher = new Morpher(new TraceManager(), language); + return words.Select(word => Outcome(morpher, word, onTimed)).ToArray(); + } + + // A mutated grammar can drop whatever bounded a search, so a mutant may never terminate. Kept wide + // enough that a merely slow mutant is never mistaken for a non-terminating one. internal so + // InterfaceWitnessGate shares this constant instead of keeping a second copy that could drift. + internal static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(180); + + // Every Timeout ever investigated here resolved to a real verdict on a quieter machine or under + // a scoped sweep -- genuine non-termination has never once been observed. A retry therefore + // protects against nothing the budget does not, and cost 2x on every slow mutant, so the budget + // carries the whole job: deep-optional-affix-nesting alone needs ~128s uncontended. + private const int TimeoutConfirmationAttempts = 1; + + /// Parses every line of against a grammar. + public static IReadOnlyList EvaluateOneGrammar( + string grammarPath, + string wordsPath, + Action? onTimed = null + ) => Outcomes(grammarPath, File.ReadAllLines(wordsPath).Where(line => line.Length != 0).ToArray(), onTimed); + + // The child's timing side-channel: kept off stdout so it never contaminates the outcome lines a + // baseline diff compares, and parsed back out of stderr regardless of whether the child succeeded. + private const string TimingPrefix = "TIME\t"; + + private static string ExtractWordTimings(string stderr, Action? onTimed) + { + var remaining = new List(); + foreach (string rawLine in stderr.Split('\n')) + { + string line = rawLine.TrimEnd('\r'); + string[] parts = line.StartsWith(TimingPrefix, StringComparison.Ordinal) + ? line.Split('\t') + : Array.Empty(); + if (parts.Length == 3 && long.TryParse(parts[2], out long elapsedMs)) + { + onTimed?.Invoke(parts[1], elapsedMs); + continue; + } + remaining.Add(line); + } + return string.Join('\n', remaining).Trim(); + } + + /// + /// Runs the parse in a child process so a mutant that never terminates can be killed. Waiting on an + /// in-process task only abandons it: it keeps allocating for the rest of the sweep. Requires + /// independent timeouts in a row before reporting one -- + /// see that constant's own doc comment for why a single sample is not trusted. + /// + private static IReadOnlyList OutcomesWithTimeout( + string grammarPath, + IReadOnlyList words, + TimeSpan timeout, + Action? onTimed + ) + { + TimeoutException lastTimeout; + int attempt = 1; + while (true) + { + try + { + return RunOnceWithTimeout(grammarPath, words, timeout, onTimed); + } + catch (TimeoutException ex) + { + lastTimeout = ex; + if (attempt++ >= TimeoutConfirmationAttempts) + throw lastTimeout; + } + } + } + + /// One wall-clock-bounded attempt; see for why + /// never accepts a single one of these as final. + private static IReadOnlyList RunOnceWithTimeout( + string grammarPath, + IReadOnlyList words, + TimeSpan timeout, + Action? onTimed + ) + { + string wordsPath = grammarPath + ".words"; + File.WriteAllLines(wordsPath, words); + try + { + // Not Environment.ProcessPath / Assembly.GetEntryAssembly(): under `dotnet test` those + // resolve to the test host, not this assembly, and re-launching the test host with + // --evaluate-mutant would run the wrong program. This assembly's own location is + // correct regardless of what process is hosting the caller. + var start = new System.Diagnostics.ProcessStartInfo + { + FileName = "dotnet", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + start.ArgumentList.Add(typeof(CounterfactualGate).Assembly.Location); + start.ArgumentList.Add("--evaluate-mutant"); + start.ArgumentList.Add(grammarPath); + start.ArgumentList.Add(wordsPath); + // Morpher.Synthesize's Parallel.ForEach sizes itself off Environment.ProcessorCount, which + // the CLR reads from this variable at startup: pinning it to 1 makes synthesis run its + // partitions on a single thread, so a mutant that races under real concurrency stops racing. + start.EnvironmentVariables["DOTNET_PROCESSOR_COUNT"] = "1"; + + using System.Diagnostics.Process child = + System.Diagnostics.Process.Start(start) ?? throw new InvalidOperationException("could not start child"); + + // Drain both pipes before waiting. Reading one to the end first deadlocks as soon as the + // child fills the other, and then the timeout below is never reached. + Task outputTask = child.StandardOutput.ReadToEndAsync(); + Task errorTask = child.StandardError.ReadToEndAsync(); + if (!child.WaitForExit((int)timeout.TotalMilliseconds)) + { + child.Kill(entireProcessTree: true); + // Best effort: whatever timings the mutant printed before it was killed are real + // measurements of the words it did finish, even though the run overall did not. + if (errorTask.Wait(TimeSpan.FromSeconds(5))) + ExtractWordTimings(errorTask.Result, onTimed); + throw new TimeoutException($"parse did not complete within {timeout.TotalSeconds:0}s"); + } + + string output = outputTask.GetAwaiter().GetResult(); + string error = ExtractWordTimings(errorTask.GetAwaiter().GetResult(), onTimed); + if (child.ExitCode != 0) + throw new InvalidOperationException(error.Trim()); + return output + .Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.TrimEnd('\r')) + .ToArray(); + } + finally + { + if (File.Exists(wordsPath)) + File.Delete(wordsPath); + } + } + + /// + /// The fixture's outcomes as written, computed once and shared across every surface it contains -- + /// recomputing it per surface is the dominant cost of a counterfactual sweep. + /// + public static IReadOnlyList ComputeBaseline(Fixture fixture, Action? onTimed = null) + { + ArgumentNullException.ThrowIfNull(fixture); + string[] words = fixture.Words.Words.Select(word => word.Word).ToArray(); + return Outcomes(fixture.GrammarPath, words, onTimed); + } + + /// + /// Evaluates in the same killable child process a mutant gets, rather + /// than 's in-process, untimed path. Needed for a fixture whose baseline + /// is not trustworthy to run unprotected -- a pathological or expect_crash fixture -- so an Ordering + /// item belonging to it gets the same non-terminating-search protection a Surface mutant already has. + /// + public static IReadOnlyList EvaluateWithTimeout( + string grammarPath, + IReadOnlyList words, + TimeSpan? timeout = null, + Action? onTimed = null + ) => OutcomesWithTimeout(grammarPath, words, timeout ?? DefaultTimeout, onTimed); + + /// + /// Runs 's adjacent-pair transposition against the already-computed + /// , reusing exactly as a Surface neutralization + /// does -- the swap is just a different shape (reordering rather than + /// deleting or rewriting). + /// + public static CounterfactualResult EvaluateOrderingSwap( + Fixture fixture, + OrderingItem item, + IReadOnlyList baseline, + string scratchDirectory, + TimeSpan? timeout = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(fixture); + ArgumentNullException.ThrowIfNull(item); + ArgumentNullException.ThrowIfNull(baseline); + XDocument grammar = XDocument.Load(fixture.GrammarPath); + OrderingSwap? swap = OrderingGenerator.Swap(grammar, item); + if (swap is null) + { + return new CounterfactualResult( + item.Id, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + "the item no longer matches this fixture's grammar" + ); + } + + var mutation = new GrammarMutation(item.Id, "adjacent-transposition", swap.Detail, swap.Mutated); + return RunMutation( + fixture, + item.Id, + mutation, + baseline, + scratchDirectory, + timeout ?? DefaultTimeout, + onWordTimed + ); + } + + /// + /// Runs the fixture with neutralized against the already-computed + /// , and reports which of the four outcomes applies. A deletion that + /// times out is retried once as a lighter, children-only mutation before being accepted as + /// pathological: an unconstrained search exploding is a cost of the mutation, not of the surface. + /// + public static CounterfactualResult Evaluate( + Fixture fixture, + string surfaceId, + SemanticInventory inventory, + IReadOnlyList baseline, + string scratchDirectory, + TimeSpan? timeout = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(fixture); + ArgumentNullException.ThrowIfNull(inventory); + ArgumentNullException.ThrowIfNull(baseline); + XDocument grammar = XDocument.Load(fixture.GrammarPath); + + // A single arbitrarily-chosen sibling can be a no-op while another one is not, so every + // declared sibling is tried before Unobservable is accepted; see EvaluateEveryEnumSibling. + CounterfactualResult? enumResult = EvaluateEveryEnumSibling( + fixture, + surfaceId, + inventory, + baseline, + scratchDirectory, + timeout ?? DefaultTimeout, + onWordTimed, + grammar + ); + if (enumResult is not null) + return enumResult; + + GrammarMutation? mutation = GrammarMutator.Mutate(grammar, surfaceId, inventory); + if (mutation is null) + { + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + "the fixture does not contain this surface" + ); + } + + TimeSpan effectiveTimeout = timeout ?? DefaultTimeout; + CounterfactualResult primary = RunMutation( + fixture, + surfaceId, + mutation, + baseline, + scratchDirectory, + effectiveTimeout, + onWordTimed + ); + if (primary.Verdict != CounterfactualVerdict.Timeout || mutation.Kind != GrammarMutator.DeletedElements) + return primary; + + GrammarMutation? lighter = GrammarMutator.MutateByEmptyingElementChildren(grammar, surfaceId); + if (lighter is null) + return primary; + + CounterfactualResult fallback = RunMutation( + fixture, + surfaceId, + lighter, + baseline, + scratchDirectory, + effectiveTimeout, + onWordTimed + ); + return fallback.Verdict switch + { + // The lighter mutation proved nothing; the exploding deletion is the only real + // neutralization on offer, so report it rather than a mutation that quietly proves nothing. + CounterfactualVerdict.Unobservable => primary, + CounterfactualVerdict.Timeout => primary with + { + Delta = + primary.Delta + " (a lighter, children-only mutation was also tried and also did not terminate)", + }, + _ => fallback with { Mutation = $"{fallback.Mutation}, in place of a deletion that did not terminate" }, + }; + } + + /// Whether an enum-sibling search should keep trying remaining siblings. + public enum EnumSiblingSearchAction + { + Continue, + Stop, + } + + /// + /// An enum rewrite always targets an attribute value the DTD already permits (a declared sibling), + /// so it can never itself fail generic DTD validation -- a load failure reached this way is always + /// , never . + /// + private static bool IsLoadFailureFromEnumRewrite(CounterfactualVerdict verdict) => + verdict == CounterfactualVerdict.RequiredByLoader; + + /// + /// Folds one enum-sibling mutation result into the best found so far. (a word-level counter-example) always wins and stops + /// the search; a load failure (see ) is kept only until + /// something stronger turns up. Word and LoadFailure are different strengths of evidence (see + /// ), so stopping at whichever verdict a caller happens to reach + /// first in declared sibling order would make the recorded strength depend on the DTD's + /// alphabetical value ordering rather than on what the grammar actually shows. + /// + public static (CounterfactualResult? Best, EnumSiblingSearchAction Action) ConsiderEnumSiblingResult( + CounterfactualResult? bestSoFar, + CounterfactualResult candidate + ) + { + ArgumentNullException.ThrowIfNull(candidate); + if (candidate.Verdict == CounterfactualVerdict.Evidenced) + return (candidate, EnumSiblingSearchAction.Stop); + if (IsLoadFailureFromEnumRewrite(candidate.Verdict) && bestSoFar is null) + return (candidate, EnumSiblingSearchAction.Continue); + return (bestSoFar, EnumSiblingSearchAction.Continue); + } + + /// + /// Tries every declared sibling of an enum surface, preferring a word-level + /// result over a one -- see . + /// Returns null (never a result) when there are + /// no siblings to enumerate -- not an enum surface, absent from the document, or with no declared + /// sibling at all -- so falls back to 's + /// single-mutation path, which is the only neutralization available in that last case (a removal, + /// not a rewrite). + /// + private static CounterfactualResult? EvaluateEveryEnumSibling( + Fixture fixture, + string surfaceId, + SemanticInventory inventory, + IReadOnlyList baseline, + string scratchDirectory, + TimeSpan timeout, + Action? onWordTimed, + XDocument grammar + ) + { + IReadOnlyList candidates = GrammarMutator.MutateEnumAgainstEverySibling( + grammar, + surfaceId, + inventory + ); + if (candidates.Count == 0) + return null; + + var tried = new List(); + CounterfactualResult? bestSoFar = null; + string? bestSibling = null; + foreach (GrammarMutator.EnumSiblingCandidate candidate in candidates) + { + CounterfactualResult result = RunMutation( + fixture, + surfaceId, + candidate.Mutation, + baseline, + scratchDirectory, + timeout, + onWordTimed + ); + tried.Add($"\"{candidate.Sibling}\" ({result.Verdict})"); + + (CounterfactualResult? updated, EnumSiblingSearchAction action) = ConsiderEnumSiblingResult( + bestSoFar, + result + ); + if (!ReferenceEquals(updated, bestSoFar)) + { + bestSoFar = updated; + bestSibling = candidate.Sibling; + } + + if (action == EnumSiblingSearchAction.Stop) + { + return bestSoFar! with + { + Delta = $"sibling \"{bestSibling}\" of {candidates.Count} tried: {bestSoFar!.Delta}", + }; + } + } + + if (bestSoFar is not null) + { + return bestSoFar with + { + Delta = + $"sibling \"{bestSibling}\" of {candidates.Count} tried ({bestSoFar.Verdict}; no sibling produced " + + $"word-level evidence): {bestSoFar.Delta}", + }; + } + + string siblingList = string.Join(", ", candidates.Select(c => $"\"{c.Sibling}\"")); + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + $"tried {candidates.Count} declared sibling(s): {siblingList}", + $"none produced a delta: {string.Join(", ", tried)}" + ); + } + + /// + /// Evidences an isActive="no" surface that cannot: one whose only + /// consumer is a fail-fast IDREF lookup, so activating it alone never dangles (nothing references + /// it) and activating a live reference to it alone never loads (the baseline correctly still has + /// the target inactive). Runs THREE mutants against the same baseline -- target alone, the + /// referencing partner alone, and both together -- and only credits the target when all three of + /// the docstring's necessity conditions hold: alone changes nothing, the partner alone does not + /// already explain the joint delta, and jointly something does change. All three outcomes are + /// folded into the returned result's Delta so the attribution is checkable, not asserted. + /// + public static CounterfactualResult EvaluateJointly( + Fixture fixture, + string surfaceId, + SemanticInventory inventory, + IReadOnlyList baseline, + string scratchDirectory, + TimeSpan? timeout = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(fixture); + ArgumentNullException.ThrowIfNull(inventory); + ArgumentNullException.ThrowIfNull(baseline); + + GrammarMutator.JointPartner? partner = GrammarMutator.FindJointPartner( + XDocument.Load(fixture.GrammarPath), + surfaceId + ); + if (partner is null) + { + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + "no independently-inactive referencing declaration exists to pair a joint mutation against" + ); + } + + TimeSpan effectiveTimeout = timeout ?? DefaultTimeout; + GrammarMutation? targetAlone = GrammarMutator.Mutate(XDocument.Load(fixture.GrammarPath), surfaceId, inventory); + GrammarMutation? partnerAlone = GrammarMutator.MutatePartnerAlone(XDocument.Load(fixture.GrammarPath), partner); + GrammarMutation? joint = GrammarMutator.MutateJointly( + XDocument.Load(fixture.GrammarPath), + surfaceId, + partner, + inventory + ); + if (targetAlone is null || partnerAlone is null || joint is null) + { + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + "a joint partner was located but one of the three required mutations could not be built" + ); + } + + CounterfactualResult resultA = RunMutation( + fixture, + surfaceId, + targetAlone, + baseline, + scratchDirectory, + effectiveTimeout, + onWordTimed + ); + CounterfactualResult resultB = RunMutation( + fixture, + surfaceId, + partnerAlone, + baseline, + scratchDirectory, + effectiveTimeout, + onWordTimed + ); + CounterfactualResult resultJoint = RunMutation( + fixture, + surfaceId, + joint, + baseline, + scratchDirectory, + effectiveTimeout, + onWordTimed + ); + + string threeRun = + $"three-run: target alone ({targetAlone.Detail}) -> {resultA.Verdict} ({resultA.Delta}); " + + $"partner alone ({partnerAlone.Detail}) -> {resultB.Verdict} ({resultB.Delta}); " + + $"both jointly ({joint.Detail}) -> {resultJoint.Verdict} ({resultJoint.Delta})"; + + // Condition 1: the target alone must already be insufficient, or this is ordinary + // single-surface evidence and reporting it as merely "joint" would UNDERSTATE it. + if (resultA.Verdict is CounterfactualVerdict.Evidenced or CounterfactualVerdict.RequiredByLoader) + return resultA; + if (resultA.Verdict is not CounterfactualVerdict.Unobservable) + { + // Timeout, most likely. No clean "alone changes nothing" baseline to reason from, so + // claiming joint attribution here would not be safe. + return new CounterfactualResult( + surfaceId, + fixture.Id, + resultA.Verdict, + targetAlone.Detail, + $"the target-alone run did not settle cleanly ({resultA.Delta}); {threeRun}" + ); + } + + // Condition 3: the joint mutation must actually change something -- otherwise the pair proves + // nothing either, honestly reported as still-unobservable rather than forced to a verdict. + if (resultJoint.Verdict is not (CounterfactualVerdict.Evidenced or CounterfactualVerdict.RequiredByLoader)) + { + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + joint.Detail, + $"joint activation produced no change either; {threeRun}" + ); + } + + // Condition 2: the partner alone must not already reproduce the identical delta -- if it does, + // the joint result is attributable to the partner, not to this surface, and must NOT evidence it. + bool partnerAloneExplainsTheJointDelta = + resultB.Verdict == resultJoint.Verdict && resultB.Delta == resultJoint.Delta; + if (partnerAloneExplainsTheJointDelta) + { + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + joint.Detail, + $"the partner alone reproduces the identical delta, so it is not attributable to this surface; {threeRun}" + ); + } + + // Carries resultJoint's ExampleWord/ExampleOutcome/CounterexampleKind/CounterexampleOutcome + // forward rather than dropping them: resultJoint is already Evidenced or RequiredByLoader at + // this point, so RunMutation already populated a real counter-example, and EvidencedJointly is a + // strength label on that same counter-example, not a different, weaker one that has none. + return resultJoint with + { + Verdict = CounterfactualVerdict.EvidencedJointly, + Mutation = joint.Detail, + Delta = threeRun, + }; + } + + /// Applies one already-built mutation and diffs it against the baseline. + private static CounterfactualResult RunMutation( + Fixture fixture, + string surfaceId, + GrammarMutation mutation, + IReadOnlyList baseline, + string scratchDirectory, + TimeSpan timeout, + Action? onWordTimed + ) + { + string[] words = fixture.Words.Words.Select(word => word.Word).ToArray(); + + Directory.CreateDirectory(scratchDirectory); + string mutatedPath = Path.Combine(scratchDirectory, $"mutated-{Guid.NewGuid():N}.xml"); + // The loader resolves the DTD relative to the document, so the mutant has to sit beside a copy. + string dtdSource = Path.Combine(Path.GetDirectoryName(fixture.GrammarPath)!, "HermitCrabInput.dtd"); + if (File.Exists(dtdSource)) + File.Copy(dtdSource, Path.Combine(scratchDirectory, "HermitCrabInput.dtd"), overwrite: true); + try + { + IReadOnlyList mutated; + try + { + // Neutralizing the root element leaves a document that will not even serialize -- the + // most extreme case of RequiredByDtd there is, since it fails before DTD validation + // itself gets a document to validate. + mutation.Mutated.Save(mutatedPath); + mutated = OutcomesWithTimeout(mutatedPath, words, timeout, onWordTimed); + } + catch (TimeoutException) + { + // Not finishing in a wall-clock bound is timing-dependent, not a semantic delta. + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Timeout, + mutation.Detail, + $"the mutant did not terminate within {timeout.TotalSeconds:0}s" + ); + } + catch (Exception ex) + { + string loadFailure = $"{ex.GetType().Name}: {Summarize(ex.Message)}"; + return new CounterfactualResult( + surfaceId, + fixture.Id, + LoadFailureVerdict(mutation.Kind), + mutation.Detail, + loadFailure, + ExampleWord: words.Length != 0 ? words[0] : null, + ExampleOutcome: words.Length != 0 ? baseline[0] : null, + CounterexampleKind: CounterexampleKind.LoadFailure, + CounterexampleOutcome: loadFailure + ); + } + + for (int i = 0; i < words.Length; i++) + { + if (baseline[i] != mutated[i]) + { + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Evidenced, + mutation.Detail, + $"'{words[i]}': {baseline[i]} -> {mutated[i]}", + ExampleWord: words[i], + ExampleOutcome: baseline[i], + CounterexampleKind: CounterexampleKind.Word, + CounterexampleOutcome: mutated[i] + ); + } + } + + return new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + mutation.Detail, + $"all {words.Length} word(s) unchanged" + ); + } + finally + { + try + { + if (File.Exists(mutatedPath)) + File.Delete(mutatedPath); + } + catch (IOException) + { + // An abandoned timed-out worker task may still hold this file open; leaving it + // behind in scratch is cheaper than blocking on a thread we deliberately gave up on. + } + } + } + + /// + /// Classifies a load failure by the neutralization that produced it, + /// mechanically rather than by inspecting the exception -- and only ever + /// remove or hollow out an element (a dtd:element/* surface), which can fail only by tripping + /// generic DTD content-model validation before XmlLanguageLoader runs; every other kind + /// (, , + /// , ) + /// only ever touches a dtd:enum/* attribute already legal under the DTD, so a failure there + /// can only come from HermitCrab's own loader. + /// + private static CounterfactualVerdict LoadFailureVerdict(string mutationKind) => + mutationKind is GrammarMutator.DeletedElements or GrammarMutator.EmptiedChildren + ? CounterfactualVerdict.RequiredByDtd + : CounterfactualVerdict.RequiredByLoader; + + private static string Summarize(string message) + { + string single = message.Replace('\n', ' ').Replace('\r', ' ').Trim(); + return single.Length <= 120 ? single : single[..120] + "..."; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CounterfactualLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CounterfactualLedger.cs new file mode 100644 index 000000000..eaeb78aac --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CounterfactualLedger.cs @@ -0,0 +1,360 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Runs across every fixture and reads/writes the checked-in +/// ledger, so the CLI and the test suite recompute the identical thing rather than each carrying +/// its own copy of the sweep. +/// +public static class CounterfactualLedger +{ + public const string RelativePath = "conformance/semantic-coverage-counterfactuals.tsv"; + + /// + /// Evaluates every surface every non-pathological, non-crash fixture contains, and keeps the + /// strongest verdict any fixture reaches for each surface. + /// + public static IReadOnlyList Sweep( + string repositoryRoot, + SemanticInventory inventory, + Action? onFixtureStarted = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(inventory); + string scratch = Path.Combine(Path.GetTempPath(), "hc-counterfactual"); + var results = new List(); + + // Every fixture's baseline has to be computed regardless -- evaluating any of its surfaces + // needs it -- so timing it here to run fixtures cheapest-first afterward costs nothing extra. + var candidates = + new List<(Fixture Fixture, string[] SurfaceIds, IReadOnlyList Baseline, long BaselineMs)>(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + // Neither a pathological timing fixture nor a crash-is-the-answer fixture has a real + // outcome CI ever checks, so there is no trustworthy baseline to diff a mutant against. + if (fixture.Words.BudgetMs is not null || fixture.Words.ExpectCrash) + continue; + + XDocument grammar = XDocument.Load(fixture.GrammarPath); + string[] surfaceIds = GrammarFeatureUsage + .Read(grammar, inventory) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + if (surfaceIds.Length == 0) + continue; + + IReadOnlyList baseline; + var stopwatch = Stopwatch.StartNew(); + try + { + baseline = CounterfactualGate.ComputeBaseline( + fixture, + onTimed: (word, ms) => onWordTimed?.Invoke(new WordTiming("baseline", fixture.Id, null, word, ms)) + ); + } + catch (Exception ex) + { + foreach (string surfaceId in surfaceIds) + { + results.Add( + new CounterfactualResult( + surfaceId, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + $"the fixture itself does not load: {ex.GetType().Name}" + ) + ); + } + continue; + } + stopwatch.Stop(); + candidates.Add((fixture, surfaceIds, baseline, stopwatch.ElapsedMilliseconds)); + } + + // Deliberately exhaustive: every fixture is evaluated against every surface it contains, in + // discovery order, with no short-circuit once some fixture already reaches the best possible + // verdict for a surface. A skip there would mean a surface's later fixtures are never even + // run, so a languages/* fixture that ALSO reaches Evidenced could never be discovered once an + // edge-case fixture (sorted first by Fixture.DiscoverAll) got there first -- exactly the + // fold-in-candidates.tsv defect this ledger exists to avoid. See the tie-preserving merge below. + foreach (var candidate in candidates) + { + onFixtureStarted?.Invoke(candidate.Fixture.Id, candidate.SurfaceIds.Length); + foreach (string surfaceId in candidate.SurfaceIds) + { + CounterfactualResult result = CounterfactualGate.Evaluate( + candidate.Fixture, + surfaceId, + inventory, + candidate.Baseline, + scratch, + onWordTimed: (word, ms) => + onWordTimed?.Invoke(new WordTiming("mutant", candidate.Fixture.Id, surfaceId, word, ms)) + ); + results.Add(result); + + // A single flip proved nothing; before giving up, see whether an independent + // referencing declaration exists that a JOINT flip can pin the delta on instead. Only + // worth the extra runs when the single-surface attempt was genuinely inconclusive. + if (result.Verdict == CounterfactualVerdict.Unobservable) + { + CounterfactualResult jointResult = CounterfactualGate.EvaluateJointly( + candidate.Fixture, + surfaceId, + inventory, + candidate.Baseline, + scratch, + onWordTimed: (word, ms) => + onWordTimed?.Invoke(new WordTiming("mutant", candidate.Fixture.Id, surfaceId, word, ms)) + ); + results.Add(jointResult); + } + } + } + + // The strongest verdict any fixture reaches for a surface is the one that counts, and every + // fixture tied at that verdict is a real witness -- recording only the first-discovered one + // (candidates arrive in Fixture.DiscoverAll's id order, so edge-cases always precede + // languages/*) would silently drop a language-grammar witness that ties rather than beats it. + // The kept row is still the first-discovered (its example/mutation fields describe that one + // run), but WitnessingFixtures names every fixture that reached the same verdict. + var bestVerdictBySurface = new Dictionary(StringComparer.Ordinal); + foreach (CounterfactualResult result in results) + { + if ( + !bestVerdictBySurface.TryGetValue(result.SurfaceId, out CounterfactualVerdict existing) + || result.Verdict < existing + ) + { + bestVerdictBySurface[result.SurfaceId] = result.Verdict; + } + } + + var tiedFixturesBySurface = new Dictionary>(StringComparer.Ordinal); + foreach (CounterfactualResult result in results) + { + if (result.Verdict != bestVerdictBySurface[result.SurfaceId]) + continue; + if (!tiedFixturesBySurface.TryGetValue(result.SurfaceId, out SortedSet? fixtureIds)) + { + fixtureIds = new SortedSet(StringComparer.Ordinal); + tiedFixturesBySurface[result.SurfaceId] = fixtureIds; + } + fixtureIds.Add(result.FixtureId); + } + + var best = new SortedDictionary(StringComparer.Ordinal); + foreach (CounterfactualResult result in results) + { + if (result.Verdict != bestVerdictBySurface[result.SurfaceId] || best.ContainsKey(result.SurfaceId)) + continue; + best[result.SurfaceId] = result with + { + WitnessingFixtures = tiedFixturesBySurface[result.SurfaceId].ToArray(), + }; + } + + return best.Values.ToArray(); + } + + /// + /// Evaluates every Ordering adjacent-pair item the corpus declares () by swapping it and diffing against its own + /// fixture's baseline. Unlike , no cross-fixture "best verdict" merge is needed: + /// an Ordering item's id already names the one fixture it came from, so each item is evaluated + /// exactly once. The baseline is computed through the same killable child process a mutant uses + /// (), never in-process, because some fixtures in + /// this corpus are deliberately pathological or expect_crash and have no trustworthy unprotected run. + /// + public static IReadOnlyList SweepOrdering( + string repositoryRoot, + Action? onFixtureStarted = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string scratch = Path.Combine(Path.GetTempPath(), "hc-ordering-counterfactual"); + var results = new List(); + + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + IReadOnlyList items = OrderingGenerator.EnumerateAdjacentPairs(grammar, fixture.Id); + if (items.Count == 0) + continue; + + onFixtureStarted?.Invoke(fixture.Id, items.Count); + string[] words = fixture.Words.Words.Select(word => word.Word).ToArray(); + + IReadOnlyList baseline; + try + { + baseline = CounterfactualGate.EvaluateWithTimeout( + fixture.GrammarPath, + words, + onTimed: (word, ms) => onWordTimed?.Invoke(new WordTiming("baseline", fixture.Id, null, word, ms)) + ); + } + catch (TimeoutException) + { + foreach (OrderingItem item in items) + { + results.Add( + new CounterfactualResult( + item.Id, + fixture.Id, + CounterfactualVerdict.Timeout, + "none", + "the fixture's own unmutated baseline did not terminate within the timeout" + ) + ); + } + continue; + } + catch (Exception ex) + { + foreach (OrderingItem item in items) + { + results.Add( + new CounterfactualResult( + item.Id, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + $"the fixture's own unmutated baseline failed to evaluate: {ex.GetType().Name}" + ) + ); + } + continue; + } + + foreach (OrderingItem item in items) + { + results.Add( + CounterfactualGate.EvaluateOrderingSwap( + fixture, + item, + baseline, + scratch, + onWordTimed: (word, ms) => + onWordTimed?.Invoke(new WordTiming("mutant", fixture.Id, item.Id, word, ms)) + ) + ); + } + } + + return results.OrderBy(r => r.SurfaceId, StringComparer.Ordinal).ToArray(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var entries = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("surface\t", StringComparison.Ordinal) + ) + { + continue; + } + string[] fields = line.Split('\t'); + if (fields.Length != 10) + throw new FormatException($"{RelativePath}: '{line}' must be 10 tab-separated fields"); + if (!Enum.TryParse(fields[1], out CounterfactualVerdict verdict)) + throw new FormatException($"{RelativePath}: unknown verdict '{fields[1]}' for '{fields[0]}'"); + if (!Enum.TryParse(fields[7], out CounterexampleKind counterexampleKind)) + { + throw new FormatException( + $"{RelativePath}: unknown counterexample kind '{fields[7]}' for '{fields[0]}'" + ); + } + entries.Add( + new CounterfactualResult( + fields[0], + fields[2], + verdict, + fields[3], + fields[4], + fields[5] == NullField ? null : fields[5], + fields[6] == NullField ? null : fields[6], + counterexampleKind, + fields[8] == NullField ? null : fields[8], + fields[9].Split(',') + ) + ); + } + + return entries.OrderBy(entry => entry.SurfaceId, StringComparer.Ordinal).ToArray(); + } + + private const string NullField = "-"; + + public static void Write(string repositoryRoot, IReadOnlyList entries) + { + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + using var writer = new StreamWriter(path, false); + writer.WriteLine("# GENERATED by hc-conformance --write-counterfactual. One line per grammar-observable"); + writer.WriteLine("# surface a fixture contains: the verdict, the fixture, what was neutralized, the"); + writer.WriteLine("# observed delta, and the structural counter-example fields CoverageEvidencePipeline"); + writer.WriteLine("# joins into an Evidence record (never re-derived from delta's free text). Absent"); + writer.WriteLine("# fields are \"-\"."); + writer.WriteLine("# Evidenced neutralizing it changed a result"); + writer.WriteLine("# RequiredByLoader the mutant would not load: HermitCrab's own loader threw (an"); + writer.WriteLine("# IDREF/lookup/coercion failure) after passing DTD validation --"); + writer.WriteLine("# a real engine-semantic witness, though not a word-level delta"); + writer.WriteLine("# EvidencedJointly only a joint mutation with an independent partner changed a result;"); + writer.WriteLine( + "# weaker than Evidenced/RequiredByLoader, see CounterfactualGate.EvaluateJointly" + ); + writer.WriteLine("# RequiredByDtd the mutant would not load: it failed generic DTD content-model"); + writer.WriteLine("# validation before HermitCrab's loader ran at all -- this only"); + writer.WriteLine("# re-derives Level 1's static DTD enumeration and is NOT equally"); + writer.WriteLine("# conclusive with Evidenced; there is no parse-time witness"); + writer.WriteLine("# Timeout the mutant did not finish in time, which is not evidence"); + writer.WriteLine("# Unobservable neutralizing it changed nothing, which is not evidence"); + writer.WriteLine("# fixture is the first-discovered fixture reaching verdict (its run is what mutation/"); + writer.WriteLine("# delta/example describe); witnessed_by is EVERY fixture that reached the identical"); + writer.WriteLine("# verdict, comma-separated, ALWAYS including fixture -- a tie is not a loss, see"); + writer.WriteLine("# CounterfactualLedger.Sweep. FoldInCandidateLedger reads this to tell 'only an edge"); + writer.WriteLine("# case witnesses this' from 'an edge case was merely recorded first'."); + writer.WriteLine( + "surface\tverdict\tfixture\tmutation\tdelta\texample_word\texample_outcome\tcounterexample_kind\tcounterexample_outcome\twitnessed_by" + ); + foreach (CounterfactualResult r in entries.OrderBy(entry => entry.SurfaceId, StringComparer.Ordinal)) + { + writer.WriteLine( + string.Join( + '\t', + r.SurfaceId, + r.Verdict, + r.FixtureId, + r.Mutation, + r.Delta, + r.ExampleWord ?? NullField, + r.ExampleOutcome ?? NullField, + r.CounterexampleKind, + r.CounterexampleOutcome ?? NullField, + string.Join(",", r.WitnessingFixtures ?? new[] { r.FixtureId }) + ) + ); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageCompletenessGate.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageCompletenessGate.cs new file mode 100644 index 000000000..f5917408d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageCompletenessGate.cs @@ -0,0 +1,309 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// How one ended up resolved, or not, by the gate. +public enum CoverageResolution +{ + /// Resolved by evidence carrying a real counter-example. + Evidenced, + + /// Resolved by a proof, with no evidence claimed for the same item. + Proven, + + /// Neither evidence with a counter-example nor a proof claims this item. A real gap. + Unresolved, + + /// Both evidence and a proof claim this item. The proof outlived its evidence; stale. + Conflicting, + + /// + /// A proof was supplied but failed recomputation: the check the gate re-runs for its kind did not + /// come back with the result the proof claims. Never resolved as -- a rejected + /// proof is treated as absent, so the item still fails completeness. + /// + Rejected, +} + +public sealed record CoverageResolutionResult( + string ItemId, + CoverageResolution Resolution, + CounterexampleKind CounterexampleKind, + string Detail +); + +public sealed record CompletenessReport( + IReadOnlyList Items, + IReadOnlyDictionary EvidencedCountsByCounterexampleKind, + IReadOnlyList OrphanedEvidenceItemIds, + IReadOnlyList OrphanedProofItemIds, + bool IsComplete +); + +/// +/// Recomputes, per , whether it resolves to evidence with a counter-example, +/// a proof that re-verifies, both (stale), or neither (a gap). Never blends and +/// into one count -- they are different strengths of +/// evidence and the whole point of the kind is that they stop being summed. +/// +public static class CoverageCompletenessGate +{ + public static CompletenessReport Evaluate( + IReadOnlyList items, + IReadOnlyList evidence, + IReadOnlyList proofs, + Func? loadGrammar = null + ) + { + ArgumentNullException.ThrowIfNull(items); + ArgumentNullException.ThrowIfNull(evidence); + ArgumentNullException.ThrowIfNull(proofs); + + var duplicateEvidenceItemIds = evidence + .GroupBy(e => e.ItemId, StringComparer.Ordinal) + .Where(group => group.Skip(1).Any()) + .Select(group => group.Key) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + if (duplicateEvidenceItemIds.Length > 0) + { + throw new ArgumentException( + $"Evidence contains duplicate rows for item(s): {string.Join(", ", duplicateEvidenceItemIds)}", + nameof(evidence) + ); + } + + var itemById = items.ToDictionary(item => item.Id, StringComparer.Ordinal); + var evidenceByItem = evidence + .Where(evidenceRow => + IsCompletenessEvidence(evidenceRow) + && itemById.TryGetValue(evidenceRow.ItemId, out CoverageItem? item) + && string.Equals(evidenceRow.Fixture, item.Fixture, StringComparison.Ordinal) + ) + .ToDictionary(e => e.ItemId, StringComparer.Ordinal); + var invalidEvidenceDetails = evidence + .Where(evidenceRow => itemById.ContainsKey(evidenceRow.ItemId)) + .GroupBy(evidenceRow => evidenceRow.ItemId, StringComparer.Ordinal) + .ToDictionary( + group => group.Key, + group => + group + .Where(evidenceRow => + !IsCompletenessEvidence(evidenceRow) + || !string.Equals( + evidenceRow.Fixture, + itemById[group.Key].Fixture, + StringComparison.Ordinal + ) + ) + .Select(evidenceRow => EvidenceDiagnostic(evidenceRow, itemById[group.Key])) + .FirstOrDefault(), + StringComparer.Ordinal + ); + var proofByItem = proofs.ToDictionary(p => p.ItemId, StringComparer.Ordinal); + var itemIds = itemById.Keys.ToHashSet(StringComparer.Ordinal); + + var counts = new Dictionary + { + [CounterexampleKind.Word] = 0, + [CounterexampleKind.LoadFailure] = 0, + }; + + var results = new List(); + foreach (CoverageItem item in items.OrderBy(item => item.Id, StringComparer.Ordinal)) + { + bool hasEvidence = evidenceByItem.TryGetValue(item.Id, out Evidence? matchedEvidence); + bool hasInvalidEvidence = + invalidEvidenceDetails.TryGetValue(item.Id, out string? invalidEvidenceDetail) + && invalidEvidenceDetail is not null; + bool hasProof = proofByItem.TryGetValue(item.Id, out Proof? matchedProof); + + if (hasEvidence && hasProof) + { + results.Add( + new CoverageResolutionResult( + item.Id, + CoverageResolution.Conflicting, + matchedEvidence!.CounterexampleKind, + $"has both evidence ({matchedEvidence.CounterexampleKind}) and proof " + + $"({matchedProof!.Kind}); a proof that outlives its evidence is stale" + ) + ); + continue; + } + + if (hasEvidence) + { + counts[matchedEvidence!.CounterexampleKind]++; + results.Add( + new CoverageResolutionResult( + item.Id, + CoverageResolution.Evidenced, + matchedEvidence.CounterexampleKind, + $"{matchedEvidence.CounterexampleKind} counter-example: {matchedEvidence.Mutation}" + ) + ); + continue; + } + + if (hasInvalidEvidence) + { + results.Add( + new CoverageResolutionResult( + item.Id, + CoverageResolution.Unresolved, + CounterexampleKind.None, + invalidEvidenceDetail! + ) + ); + continue; + } + + if (hasProof) + { + string? rejection = RejectRecomputedOrderingProof(item, matchedProof!, loadGrammar); + if (rejection is not null) + { + results.Add( + new CoverageResolutionResult( + item.Id, + CoverageResolution.Rejected, + CounterexampleKind.None, + rejection + ) + ); + continue; + } + + results.Add( + new CoverageResolutionResult( + item.Id, + CoverageResolution.Proven, + CounterexampleKind.None, + $"{matchedProof!.Kind}: {matchedProof.Check}" + ) + ); + continue; + } + + results.Add( + new CoverageResolutionResult( + item.Id, + CoverageResolution.Unresolved, + CounterexampleKind.None, + "neither evidence with a counter-example nor a proof claims this item" + ) + ); + } + + string[] orphanedEvidence = evidence + .Select(evidenceRow => evidenceRow.ItemId) + .Where(id => !itemIds.Contains(id)) + .Distinct(StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] orphanedProofs = proofs + .Select(proof => proof.ItemId) + .Where(id => !itemIds.Contains(id)) + .Distinct(StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + bool complete = + orphanedEvidence.Length == 0 + && orphanedProofs.Length == 0 + && results.All(result => result.Resolution is CoverageResolution.Evidenced or CoverageResolution.Proven); + + return new CompletenessReport(results, counts, orphanedEvidence, orphanedProofs, complete); + } + + private static string EvidenceDiagnostic(Evidence evidence, CoverageItem item) + { + if (!string.Equals(evidence.Fixture, item.Fixture, StringComparison.Ordinal)) + { + return $"evidence fixture '{evidence.Fixture}' does not match generated item fixture '{item.Fixture}'"; + } + + return "evidence claim is invalid or lacks a structural counter-example"; + } + + /// + /// Returns whether an evidence record has the exact verdict/kind pairing and structural payload + /// that can resolve an item: a word counter-example from an evidenced verdict, or a load failure + /// from either required-to-load verdict ( or + /// -- both are still a genuine, structural + /// load-failure counter-example for completeness purposes, even though they differ in strength) or + /// the jointly-evidenced verdict. Other pairings, including , + /// are not completeness evidence. + /// + private static bool IsCompletenessEvidence(Evidence evidence) => + (evidence.Verdict, evidence.CounterexampleKind) + is + (CounterfactualVerdict.Evidenced, CounterexampleKind.Word) + or + (CounterfactualVerdict.EvidencedJointly, CounterexampleKind.Word) + or + (CounterfactualVerdict.EvidencedJointly, CounterexampleKind.LoadFailure) + or + (CounterfactualVerdict.RequiredByDtd, CounterexampleKind.LoadFailure) + or + (CounterfactualVerdict.RequiredByLoader, CounterexampleKind.LoadFailure) + && !string.IsNullOrWhiteSpace(evidence.ExampleWord) + && evidence.ExampleOutcome is not null + && evidence.CounterexampleOutcome is not null + && !string.Equals(evidence.ExampleOutcome, evidence.CounterexampleOutcome, StringComparison.Ordinal); + + /// + /// Null only when 's kind is one of the seven recomputed Ordering-proof kinds + /// and it re-verifies against the current grammar. Unknown and surface-side kinds + /// ( and siblings) fail closed until a mechanical verifier + /// exists; checked-in prose never resolves completeness. + /// + private static string? RejectRecomputedOrderingProof( + CoverageItem item, + Proof proof, + Func? loadGrammar + ) + { + bool isRecomputed = + proof.Kind == OrderingProofs.Kind + || proof.Kind == UnorderedInvariantProofs.Kind + || proof.Kind == InactiveMemberProofs.Kind + || proof.Kind == PosDisjointProofs.Kind + || proof.Kind == TemplateMaskedProofs.Kind + || proof.Kind == NeverFiresProofs.Kind + || proof.Kind == FeatureValueDisjointProofs.Kind; + if (!isRecomputed) + { + bool isKnownSurfaceKind = + proof.Kind == ImpossibilityProofs.DtdDefault + || proof.Kind == ImpossibilityProofs.NoConsumer + || proof.Kind == ImpossibilityProofs.NotInSignature + || proof.Kind == ImpossibilityProofs.BlockedByDefect; + return isKnownSurfaceKind + ? $"{proof.Kind} proof cannot be verified: surface proof kinds require a mechanical verifier" + : $"Unknown proof kind '{proof.Kind}' cannot be verified: a mechanical verifier exists only for recomputed ordering proof kinds"; + } + + if (loadGrammar is null) + { + return $"{proof.Kind} proof cannot be verified: Evaluate was not given a grammar loader"; + } + + XDocument grammar = loadGrammar(item.Fixture); + bool verified = + proof.Kind == OrderingProofs.Kind ? OrderingProofs.Verify(grammar, item.Fixture, proof) + : proof.Kind == UnorderedInvariantProofs.Kind + ? UnorderedInvariantProofs.Verify(grammar, item.Fixture, proof) + : proof.Kind == InactiveMemberProofs.Kind ? InactiveMemberProofs.Verify(grammar, item.Fixture, proof) + : proof.Kind == PosDisjointProofs.Kind ? PosDisjointProofs.Verify(grammar, item.Fixture, proof) + : proof.Kind == TemplateMaskedProofs.Kind ? TemplateMaskedProofs.Verify(grammar, item.Fixture, proof) + : proof.Kind == NeverFiresProofs.Kind ? NeverFiresProofs.Verify(grammar, item.Fixture, proof) + : FeatureValueDisjointProofs.Verify(grammar, item.Fixture, proof); + return verified ? null : $"{proof.Kind} proof failed recomputation for '{proof.ItemId}' in '{item.Fixture}'"; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageEvidencePipeline.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageEvidencePipeline.cs new file mode 100644 index 000000000..1265a3dd4 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageEvidencePipeline.cs @@ -0,0 +1,161 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Assembles the combined Surface+Ordering coverage inventory -- 194 +/// items plus every Ordering adjacent pair the corpus declares -- from the two independent sweeps +/// ( and ) into the +/// // shape +/// consumes. +/// +public static class CoverageEvidencePipeline +{ + /// One item per surface result plus one per ordering result -- never merged or deduplicated, + /// since a surface and an ordering pair are always distinct generators over disjoint id spaces. + public static IReadOnlyList BuildItems( + IReadOnlyList surfaceResults, + IReadOnlyList orderingResults + ) + { + ArgumentNullException.ThrowIfNull(surfaceResults); + ArgumentNullException.ThrowIfNull(orderingResults); + var items = new List(surfaceResults.Count + orderingResults.Count); + foreach (CounterfactualResult result in surfaceResults) + { + items.Add( + new CoverageItem( + result.SurfaceId, + CoverageItemKind.Surface, + SurfaceOrigin(result.SurfaceId), + result.FixtureId + ) + ); + } + foreach (CounterfactualResult result in orderingResults) + { + items.Add( + new CoverageItem( + result.SurfaceId, + CoverageItemKind.Ordering, + "adjacent-transposition", + result.FixtureId + ) + ); + } + return items.OrderBy(item => item.Id, StringComparer.Ordinal).ToArray(); + } + + private static string SurfaceOrigin(string surfaceId) => + surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal) ? "dtd-enum" : "dtd-element"; + + /// + /// Every Ordering item the corpus currently declares, enumerated structurally from the checked-in + /// grammars -- no engine sweep, no child process, just + /// per fixture. Cheap enough to call on every test run, which is what lets a gap-count ratchet stay + /// off the expensive sweep. + /// + public static IReadOnlyList BuildOrderingItems(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + var items = new List(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + foreach (OrderingItem item in OrderingGenerator.EnumerateAdjacentPairs(grammar, fixture.Id)) + items.Add(new CoverageItem(item.Id, CoverageItemKind.Ordering, "adjacent-transposition", fixture.Id)); + } + return items.OrderBy(item => item.Id, StringComparer.Ordinal).ToArray(); + } + + /// Evidence for every result whose verdict carries a real counter-example (Word or LoadFailure). + public static IReadOnlyList BuildEvidence(IReadOnlyList results) => + results + .Where(result => result.CounterexampleKind != CounterexampleKind.None) + .Select(result => Evidence.FromCounterfactualResult(result.SurfaceId, result)) + .ToArray(); + + /// + /// Every proof the combined inventory can claim: the checked-in Surface impossibility claims + /// (dtd-default, no-consumer, not-in-signature, blocked-by-defect), plus a freshly recomputed + /// Ordering proof -- disjoint-domains, unordered-invariant, inactive-member, pos-disjoint, + /// template-masked, never-fires, or feature-value-disjoint, tried in that order -- for every + /// non-evidenced Ordering item one of them resolves. Ordering proofs are never read from a file -- + /// each kind's check only needs the checked-in grammar, so recomputing it here costs nothing worth + /// caching and there is nothing that can go stale. + /// + public static IReadOnlyList BuildProofs( + string repositoryRoot, + IReadOnlyList nonEvidencedOrderingItems + ) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(nonEvidencedOrderingItems); + + var proofs = ImpossibilityProofs + .Read(repositoryRoot) + .Select(proof => new Proof(proof.SurfaceId, proof.Kind, proof.Evidence)) + .ToList(); + + Dictionary fixturesById = Fixture + .DiscoverAll(Path.Combine(repositoryRoot, "conformance")) + .ToDictionary(fixture => fixture.Id, StringComparer.Ordinal); + var grammarByFixture = new Dictionary(StringComparer.Ordinal); + + foreach (CoverageItem item in nonEvidencedOrderingItems) + { + if (!fixturesById.TryGetValue(item.Fixture, out Fixture? fixture)) + continue; + if (!grammarByFixture.TryGetValue(item.Fixture, out XDocument? grammar)) + { + grammar = XDocument.Load(fixture.GrammarPath); + grammarByFixture[item.Fixture] = grammar; + } + + OrderingItem? orderingItem = OrderingGenerator + .EnumerateAdjacentPairs(grammar, item.Fixture) + .FirstOrDefault(candidate => candidate.Id == item.Id); + if (orderingItem is null) + continue; + + Proof? proof = + OrderingProofs.TryBuild(grammar, orderingItem) + ?? UnorderedInvariantProofs.TryBuild(grammar, orderingItem) + ?? InactiveMemberProofs.TryBuild(grammar, orderingItem) + ?? PosDisjointProofs.TryBuild(grammar, orderingItem) + ?? TemplateMaskedProofs.TryBuild(grammar, orderingItem) + ?? NeverFiresProofs.TryBuild(grammar, orderingItem) + ?? FeatureValueDisjointProofs.TryBuild(grammar, orderingItem); + if (proof is not null) + proofs.Add(proof); + } + + return proofs; + } + + /// A grammar loader keyed by fixture id, for + /// to re-verify disjoint-domains proofs against. + public static Func GrammarLoader(string repositoryRoot) + { + Dictionary fixturesById = Fixture + .DiscoverAll(Path.Combine(repositoryRoot, "conformance")) + .ToDictionary(fixture => fixture.Id, StringComparer.Ordinal); + return fixtureId => XDocument.Load(fixturesById[fixtureId].GrammarPath); + } + + /// Every row the combined inventory should write to : one per + /// item with real evidence. + public static IReadOnlyList BuildLedgerRows( + IReadOnlyList items, + IReadOnlyList evidence + ) + { + Dictionary itemsById = items.ToDictionary(item => item.Id, StringComparer.Ordinal); + return evidence.Select(e => EvidenceLedger.ToRow(itemsById[e.ItemId], e)).ToArray(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageModel.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageModel.cs new file mode 100644 index 000000000..0b4536aec --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/CoverageModel.cs @@ -0,0 +1,76 @@ +#nullable enable + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Which generator produced a . +public enum CoverageItemKind +{ + Surface, + Ordering, + Interaction, +} + +/// +/// How a counter-example was obtained. Never summed across kinds when reporting coverage: a load +/// failure and a word-level contrast are different strengths of evidence, and blending them into one +/// count hides which strength a given item actually reached. +/// +public enum CounterexampleKind +{ + /// The mutant grammar still loads, and a specific word's parse outcome changed. + Word, + + /// The mutant grammar would not load at all. + LoadFailure, + + /// No counter-example exists; the item can only be resolved by a . + None, +} + +/// +/// One line of the inventory: something the pipeline has committed to cover. Generated, never +/// hand-maintained. names where the item is expected to be evidenced, +/// not necessarily where it ends up evidenced. +/// +public sealed record CoverageItem(string Id, CoverageItemKind Kind, string Origin, string Fixture); + +/// +/// The example and counter-example for one , captured at the moment a +/// mutant's outcome was compared against the baseline -- never reconstructed afterward from a +/// string. +/// +public sealed record Evidence( + string ItemId, + string Fixture, + string? ExampleWord, + string? ExampleOutcome, + CounterexampleKind CounterexampleKind, + string? CounterexampleOutcome, + string Mutation, + CounterfactualVerdict Verdict +) +{ + /// + /// Lifts the structural fields a already carries into + /// for , rather than re-deriving them from + /// 's free text. + /// + public static Evidence FromCounterfactualResult(string itemId, CounterfactualResult result) => + new( + itemId, + result.FixtureId, + result.ExampleWord, + result.ExampleOutcome, + result.CounterexampleKind, + result.CounterexampleOutcome, + result.Mutation, + result.Verdict + ); +} + +/// +/// A claim that evidence for a is impossible, re-verified at gate time +/// rather than trusted as prose. names a check the gate recomputes -- see +/// for the concrete checks behind each kind. +/// +public sealed record Proof(string ItemId, string Kind, string Check); diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DataflowClaimGate.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DataflowClaimGate.cs new file mode 100644 index 000000000..68200c89f --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DataflowClaimGate.cs @@ -0,0 +1,451 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Whether a claimed cell id checks out against the checked-in ledger. This is the ONLY axis that fails +/// a build -- see . +/// +public enum DataflowClaimValidity +{ + /// The cell id exists in conformance/dataflow-obligations.tsv and its status is Satisfied. + Valid, + + /// No row in the ledger has this cell id -- a typo, or an id orphaned when a chain's schema + /// shape changed. + UnknownCellId, + + /// The cell id exists but the ledger's status for it is not Satisfied -- the author + /// intended a witness and did not get one. + NotSatisfied, +} + +/// +/// Whether a claim's optional inline review bundle (/ +/// ) still matches a fresh recomputation of the severance it +/// describes. A SEPARATE axis from : witnessed (the ledger's +/// pair-witness join says the cell is Satisfied) and reviewed (a human recorded the specific ROLE +/// attribution -- that this word really demonstrates e.g. PresentGatedForm, with the exact before/after +/// parse to show it) are different facts. Collapsing them would let a stale review read as an active +/// one, the same presence-vs-witness confusion a severance sweep elsewhere in this suite already +/// guards against -- this is that rule one level up, for witnessed-vs-reviewed. +/// +public enum DataflowClaimReviewStatus +{ + /// No severing/before/after/proof recorded on this claim yet. Not a defect -- most claims + /// start here. + Unreviewed, + + /// Recomputing BOTH the writer's and the reader's severance against the CURRENT grammar, + /// for THIS word, reproduces the claimed before/after exactly. + Reviewed, + + /// + /// A review bundle was recorded but recomputation no longer agrees with it -- the grammar moved, + /// the engine changed, or the named attribute no longer occurs in this fixture at all. Reported + /// loudly, never a build failure by itself: a stale review means the review needs to happen again, + /// not that the cell stopped being covered. + /// + Stale, +} + +/// One severance recomputation for one word: the writer or reader attribute named by the +/// caller's arguments is stripped from a copy of the fixture's grammar +/// (a null element/attribute means "recompute the unsevered baseline instead") and the word is +/// reparsed. is null exactly when recomputation could not be attempted or +/// did not finish -- then explains why, and DataflowClaimGate treats that as +/// Stale, never as a silent pass. +public sealed record SeveranceRecomputation(string? Outcome, string? Error); + +public delegate SeveranceRecomputation RecomputeSeverance( + Fixture fixture, + string? severedElement, + string? severedAttribute, + string word +); + +public sealed record DataflowClaimResult( + string FixtureId, + string Word, + string CellId, + DataflowClaimValidity Validity, + string Detail, + DataflowClaimReviewStatus Review, + string ReviewDetail, + bool? DistinctFromVerified, + string DistinctFromDetail +); + +/// A Satisfied ledger cell no claimed_cells: entry names, with the witnessing (fixture, word) +/// the ledger's own evidence text names -- read back for a human to act on, never used to fail anything +/// (see 's doc comment). +public sealed record UnclaimedSatisfiedCell(string CellId, string FixtureId, string WitnessWord); + +public sealed record DataflowClaimReport( + IReadOnlyList Claims, + IReadOnlyList UnclaimedSatisfiedCells +) +{ + /// + /// The one thing that fails a build: every claimed cell id exists in the ledger and its status is + /// Satisfied. Review staleness deliberately never appears here, and neither does + /// -- both are reports, not gates, per this class's own doc + /// comment. + /// + public bool AllClaimsValid => Claims.All(c => c.Validity == DataflowClaimValidity.Valid); +} + +/// +/// Checks every word's claimed_cells: entries () against the +/// checked-in . The whole point of the field is that a claim is +/// authored INTENT and intent is only worth anything checked against outcome -- so this gate never +/// marks a cell covered because a word claims it. +/// 's own pair-witness join is the sole authority on +/// ; this class only cross-checks a claim against that +/// already-computed fact, in the direction the field exists to catch: +/// +/// a claimed cell id absent from the ledger fails (); +/// a claimed cell whose ledger status is not Satisfied fails +/// () -- the field's entire reason to exist; +/// a Satisfied cell no word claims is reported via +/// , never failed -- a documentation gap, not a +/// correctness one, and failing it now would force mass authoring before anything can go green. +/// +/// +/// +/// A claim's optional inline review bundle (/ +/// // +/// ) is checked as a third, independent axis +/// (): the literal before/after parse outcomes are RECOMPUTED -- +/// severing the writer and, separately, the reader (the element/attribute pair comes from the ledger +/// row, never from the claim's own text) and reparsing this one word -- and compared against what the +/// claim recorded. A hash would only detect that the evidence moved; the literal values do the same +/// staleness detection AND let a reviewer read them directly, which is the entire reason this is inline +/// text rather than a hash. A mismatch (or an attribute that no longer occurs in this fixture to sever) +/// is , reported loudly, and NEVER silently treated as +/// reviewed. Recomputation is never used to grant -- only the +/// ledger's own pair-witness join does that. +/// +/// +/// +/// distinct_from (MC/DC independence -- every claim needs a control) is checked structurally, +/// independent of the review bundle: the named word must exist in the same +/// fixture and its outcome (currently: ) must differ from this word's. +/// This is deliberately the existence-plus-outcome-difference floor, not the fuller check of whether the +/// grammar difference between the two words is exactly the one named condition -- see this method's own +/// remarks in the class that calls it for what is left undone. +/// +/// +public static class DataflowClaimGate +{ + private static readonly TimeSpan RecomputeTimeout = TimeSpan.FromSeconds(20); + + /// + /// The real severance recomputation: strips . from a copy of the fixture's grammar (or, when either is null, leaves + /// the grammar unsevered -- the baseline run) and reparses exactly , in the + /// same killable child process every other counterfactual run in this directory uses. + /// + public static SeveranceRecomputation DefaultRecompute( + Fixture fixture, + string? severedElement, + string? severedAttribute, + string word + ) + { + ArgumentNullException.ThrowIfNull(fixture); + ArgumentNullException.ThrowIfNull(word); + + string grammarPath = fixture.GrammarPath; + string? scratchPath = null; + try + { + if (severedElement is not null && severedAttribute is not null) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + XDocument? severed = InterfaceWitnessGate.Sever( + grammar, + severedElement, + severedAttribute, + out int removedCount + ); + if (severed is null) + { + return new SeveranceRecomputation( + null, + $"'{severedElement}.{severedAttribute}' does not occur in this fixture's grammar to sever" + ); + } + + string scratchDirectory = Path.Combine(Path.GetTempPath(), "hc-dataflow-claim-gate"); + Directory.CreateDirectory(scratchDirectory); + scratchPath = Path.Combine(scratchDirectory, $"claim-{Guid.NewGuid():N}.xml"); + string dtdSource = Path.Combine(Path.GetDirectoryName(fixture.GrammarPath)!, "HermitCrabInput.dtd"); + if (File.Exists(dtdSource)) + File.Copy(dtdSource, Path.Combine(scratchDirectory, "HermitCrabInput.dtd"), overwrite: true); + severed.Save(scratchPath); + grammarPath = scratchPath; + } + + IReadOnlyList outcomes = CounterfactualGate.EvaluateWithTimeout( + grammarPath, + new[] { word }, + RecomputeTimeout + ); + return new SeveranceRecomputation(outcomes[0], null); + } + catch (TimeoutException ex) + { + return new SeveranceRecomputation(null, ex.Message); + } + catch (Exception ex) + { + return new SeveranceRecomputation(null, $"{ex.GetType().Name}: {ex.Message}"); + } + finally + { + if (scratchPath is not null && File.Exists(scratchPath)) + { + try + { + File.Delete(scratchPath); + } + catch (IOException) + { + // Mirrors InterfaceWitnessGate.Evaluate: a killed timed-out worker may still hold + // the file open, and blocking on that thread is worse than leaving one scratch file. + } + } + } + } + + public static DataflowClaimReport Evaluate( + IReadOnlyList fixtures, + IReadOnlyList ledger, + RecomputeSeverance? recompute = null + ) + { + ArgumentNullException.ThrowIfNull(fixtures); + ArgumentNullException.ThrowIfNull(ledger); + RecomputeSeverance evaluate = recompute ?? DefaultRecompute; + + Dictionary byCellId = ledger.ToDictionary( + r => r.CellId, + StringComparer.Ordinal + ); + + var claims = new List(); + var claimedCellIds = new HashSet(StringComparer.Ordinal); + + foreach (Fixture fixture in fixtures) + { + Dictionary wordsByName = fixture.Words.Words.ToDictionary( + w => w.Word, + StringComparer.Ordinal + ); + + foreach (WordEntry word in fixture.Words.Words) + { + foreach (ClaimedCellEntry claim in word.ClaimedCells) + { + claimedCellIds.Add(claim.Cell); + + if (!byCellId.TryGetValue(claim.Cell, out DataflowObligationLedger.Row? row)) + { + claims.Add( + new DataflowClaimResult( + fixture.Id, + word.Word, + claim.Cell, + DataflowClaimValidity.UnknownCellId, + $"'{claim.Cell}' does not exist in {DataflowObligationLedger.RelativePath}", + DataflowClaimReviewStatus.Unreviewed, + "cell id is unknown; review cannot be evaluated", + null, + "" + ) + ); + continue; + } + + if (row.Status != ObligationStatus.Satisfied) + { + claims.Add( + new DataflowClaimResult( + fixture.Id, + word.Word, + claim.Cell, + DataflowClaimValidity.NotSatisfied, + $"ledger status is {row.Status}, not Satisfied: {row.Evidence}", + DataflowClaimReviewStatus.Unreviewed, + "cell is not Satisfied; review cannot be evaluated", + null, + "" + ) + ); + continue; + } + + (DataflowClaimReviewStatus review, string reviewDetail) = EvaluateReview( + claim, + row, + fixture, + word.Word, + evaluate + ); + (bool? distinctFromVerified, string distinctFromDetail) = EvaluateDistinctFrom( + claim, + word, + wordsByName + ); + + claims.Add( + new DataflowClaimResult( + fixture.Id, + word.Word, + claim.Cell, + DataflowClaimValidity.Valid, + "matches a Satisfied cell in the ledger", + review, + reviewDetail, + distinctFromVerified, + distinctFromDetail + ) + ); + } + } + } + + var unclaimed = new List(); + foreach (DataflowObligationLedger.Row row in ledger.Where(r => r.Status == ObligationStatus.Satisfied)) + { + if (claimedCellIds.Contains(row.CellId)) + continue; + unclaimed.Add( + new UnclaimedSatisfiedCell( + row.CellId, + ExtractWitnessFixture(row.Evidence), + ExtractWitnessWord(row.Evidence) + ) + ); + } + + return new DataflowClaimReport(claims, unclaimed); + } + + private static (DataflowClaimReviewStatus, string) EvaluateReview( + ClaimedCellEntry claim, + DataflowObligationLedger.Row row, + Fixture fixture, + string word, + RecomputeSeverance evaluate + ) + { + if (!claim.HasReviewBundle) + return (DataflowClaimReviewStatus.Unreviewed, "no severing/before/after/proof recorded on this claim yet"); + + SeveranceRecomputation baseline = evaluate(fixture, null, null, word); + if (baseline.Outcome is null) + { + return ( + DataflowClaimReviewStatus.Stale, + $"could not recompute the unsevered baseline for '{word}': {baseline.Error}" + ); + } + if (baseline.Outcome != claim.Before) + { + return ( + DataflowClaimReviewStatus.Stale, + $"current baseline outcome for '{word}' is '{baseline.Outcome}', not the claimed before '{claim.Before}'" + ); + } + + foreach ( + (string element, string attribute, string role) in new[] + { + (row.WriterElement, row.WriterAttribute, "writer"), + (row.ReaderElement, row.ReaderAttribute, "reader"), + } + ) + { + SeveranceRecomputation severed = evaluate(fixture, element, attribute, word); + if (severed.Outcome is null) + { + return ( + DataflowClaimReviewStatus.Stale, + $"could not recompute severing the {role} ({element}.{attribute}) for '{word}': {severed.Error}" + ); + } + if (severed.Outcome != claim.After) + { + return ( + DataflowClaimReviewStatus.Stale, + $"severing the {role} ({element}.{attribute}) now gives '{severed.Outcome}' for '{word}', " + + $"not the claimed after '{claim.After}'" + ); + } + } + + return ( + DataflowClaimReviewStatus.Reviewed, + $"recomputed: '{word}' is '{claim.Before}' unsevered and '{claim.After}' with either the writer " + + "or the reader severed, matching the claim" + ); + } + + /// + /// Existence-plus-outcome-difference only (see this class's own doc comment for what is left): + /// confirms names a real word in the same fixture whose + /// differs from this word's. Does not (yet) confirm both words + /// claim a cell of the same chain, nor that the grammar difference between them is exactly the one + /// named condition. + /// + private static (bool?, string) EvaluateDistinctFrom( + ClaimedCellEntry claim, + WordEntry word, + IReadOnlyDictionary wordsByName + ) + { + if (claim.DistinctFrom.Length == 0) + return (null, ""); + + if (!wordsByName.TryGetValue(claim.DistinctFrom, out WordEntry? counterpart)) + return (false, $"distinct_from '{claim.DistinctFrom}' does not exist in this fixture"); + + if (word.ExpectFail == counterpart.ExpectFail) + { + return ( + false, + $"'{word.Word}' and distinct_from '{claim.DistinctFrom}' both have expect_fail={word.ExpectFail} -- " + + "independence not demonstrated" + ); + } + + return ( + true, + $"'{word.Word}' (expect_fail={word.ExpectFail}) and distinct_from '{claim.DistinctFrom}' " + + $"(expect_fail={counterpart.ExpectFail}) differ" + ); + } + + // Structured extraction from DataflowObligationLedger's fixed Evidence string shape (see its + // FindPairedWitness/EvaluateMcDcCell doc comments) -- used ONLY for the non-fatal + // UnclaimedSatisfiedCells report, never for anything that can fail a build, so a format drift here + // degrades to "(unparsed)" rather than an exception. + private static readonly Regex PairedWitnessPattern = new( + @"flip '(?[^']+)' from failed to successful parse in (?\S+) \(", + RegexOptions.Compiled + ); + + private static string ExtractWitnessWord(string evidence) => + PairedWitnessPattern.Match(evidence) is { Success: true } m ? m.Groups["word"].Value : "(unparsed)"; + + private static string ExtractWitnessFixture(string evidence) => + PairedWitnessPattern.Match(evidence) is { Success: true } m ? m.Groups["fixture"].Value : "(unparsed)"; +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DataflowObligationLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DataflowObligationLedger.cs new file mode 100644 index 000000000..dd42c9601 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DataflowObligationLedger.cs @@ -0,0 +1,717 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Whether the corpus currently WITNESSES an obligation cell, as opposed to merely permitting it +/// structurally -- the presence/witness distinction already draws +/// for a single edge, applied here to a composed chain cell. is deliberate: this +/// generator marks a cell only where a PAIR witness was found (see +/// 's own doc comment) and refuses every weaker predicate -- +/// "writer witnessed somewhere, reader witnessed somewhere, possibly different words" is edge coverage +/// counted twice, which is exactly the fallacy this layer exists to catch. +/// +public enum ObligationStatus +{ + Satisfied, + NotSatisfied, + Unknown, +} + +/// +/// A construct that can sit between a chain's write and its read and destroy the payload before the +/// reader sees it -- schema/engine-derived, never corpus-derived (a fixture happening to contain one +/// is a WITNESS fact, not a denominator fact). Each member names the exact engine mechanism, verified +/// against source: +/// +/// -- MprFeatureSet.AddOutput (MprFeatureSet.cs): an +/// outputType="overwrite" MorphologicalPhonologicalRuleFeatureGroup drops every other +/// member of its group before unioning in a new write. Detected by , +/// reused unmodified from . Applicable to every MPR-payload +/// chain (24). +/// -- Word.CheckBlocking (Word.cs:472) into +/// Word.SetRootAllomorph (Word.cs:137): a blocked derivation is rebuilt as a brand-new +/// from a sibling lexical entry, which clears and reseeds _mprFeatures, +/// resets SyntacticFeatureStruct, and swaps RootAllomorph (hence StemName, +/// which reads live off it) -- killing all three payload types at once. Applicable to every chain +/// regardless of payload type (40): triggering it needs only ONE prior blockable rule application +/// (default blockable="true" on every MorphologicalRule/RealizationalRule/ +/// CompoundingRule) between the write and the read, which a grammar can always arrange, and a +/// rule-output writer (MorphologicalOutput.MPRFeatures, CompoundingRule.output*, +/// MorphologicalRule.outputPartOfSpeech) gets that for free from its OWN post-application +/// blocking check. Realizing it in a GIVEN fixture additionally needs LexEntry.Family populated +/// (Word.cs:475-477) -- a real, checkable grammar-authoring fact, not a schema guarantee -- which is +/// exactly the corpus-level question answers. +/// -- SynthesisAffixProcessRule.cs:181-182 and +/// SynthesisCompoundingRule.cs:181-182: outWord.SyntacticFeatureStruct.PriorityUnion( +/// _rule.OutSyntacticFeatureStruct) lets an intervening rule's own outputPartOfSpeech +/// overwrite a POS def placed earlier in the derivation, before a later required*PartsOfSpeech +/// read. Applicable only to PartOfSpeech-payload chains (15). +/// -- SynthesisCompoundingRule.cs:236: +/// ApplySubrule builds output from headMatch.Input.Clone() alone, so a non-head's +/// entire MprFeatureSet is never copied into outWord.MprFeatures at all -- no overwrite +/// group is even needed for the non-head's def to fail to reach a later reader. Applicable to any of +/// the three MPR writers, but only where the reader gates on the derivation's ACCUMULATED state at a +/// point a compounding step could sit before it (MorphologicalInput/PhonologicalSubrule's +/// required/excludedMPRFeatures, 12 chains) -- see +/// for the engine reasoning +/// excluding the other five MPR readers. +/// +/// +public enum ObligationMutatorClass +{ + Overwrite, + Blocking, + PosPriorityUnion, + CompoundingNonHeadDrop, +} + +/// +/// The checked-in denominator for the data-flow/MC/DC obligation-matrix layer, built on top of +/// 's chains. +/// +/// +/// Every chain gates (no plain def-use class). 's own +/// doc comment defines READ as "gates on derivation state something else placed there" -- that is +/// already true of every reader in every chain, not just attributes literally named +/// required*/excluded*. CompoundingRule.headPartsOfSpeech gates via +/// HeadRequiredSyntacticFeatureStruct.Unify (SynthesisCompoundingRule.cs:101) and +/// headProdRestrictionsMprFeatures gates via MprFeatureSet.CompoundMprFeaturesMatch +/// (SynthesisCompoundingRule.cs:116) exactly as the *-prefixed attributes do. So every chain gets the +/// base MC/DC four cells: PresentControl/PresentGatedForm/AbsentControl/ +/// AbsentGatedForm -- 40 chains x 4 = 160 is the schema floor. +/// +/// +/// +/// MC/DC is per condition, not per gate. MprFeatureSet.IsMatchRequired/ +/// IsMatchExcluded (MprFeatureSet.cs:46,72) are a conjunction across ungrouped features and +/// matchType="all" groups, a disjunction across matchType="any" groups -- an n-condition +/// boolean whenever a required*/excludedMPRFeatures value lists n>1 feature ids (real +/// case: mpr-overwrite-order-dependence/grammar.xml:145, requiredMPRFeatures="mprP mprQ"). +/// MC/DC over n conditions needs n+1 cases, not a fixed 2. This generator scans every MPR-payload +/// chain's exercising fixtures for the largest observed token count and, where n>1, emits +/// ConditionExtension rows on top of the floor's four, attributed to the specific fixture that +/// realizes it (see ). CompoundMprFeaturesMatch +/// (MprFeatureSet.cs:98, Count == 0 || Intersect.Any()) is a DIFFERENT decision shape -- +/// vacuously true on an empty restriction set, otherwise a disjunction -- so it is scanned with the +/// same token-count mechanism but never assimilated to the conjunction/disjunction-per-group reading. +/// POS and StemName reader gates (FeatureStruct unification, not a flat id-set) are not decomposed +/// this way yet -- floor only, named as a scoping boundary rather than silently assumed complete. +/// +/// +/// +/// Cell satisfaction requires a PAIR witness on the SAME word. "Writer witnessed somewhere, +/// reader witnessed somewhere" is edge coverage counted twice; a chain cell is satisfied only when +/// severing the writer flips a named word's outcome AND severing the reader flips THAT SAME word's +/// outcome. This generator gets both severance runs for free by reading the already-computed, already +/// checked-in (conformance/interface-witness.tsv) rather than +/// re-running any engine sweep: for each exercising fixture, it joins the writer's and reader's rows on +/// (fixture, ExampleWord) and requires both (a +/// row is never treated as witness, per the same rule +/// itself follows -- "I could not look" must never read as "fine"). +/// When the flip is a clean fail-to-pass on both sides (baseline blocked, severing either side +/// unblocks it -- the textbook gated-form shape) and the reader +/// attribute names its own polarity (required* => blocks on absence, excludedMPRFeatures- +/// family => blocks on presence), the specific MC/DC arm that word demonstrates is marked +/// ; every other pattern (no paired witness, a +/// non-fail/pass flip, or a reader name this generator cannot read a polarity from, e.g. +/// head/nonHeadPartsOfSpeech) is left rather than +/// guessed. +/// +/// +/// +/// The kill-path denominator is chains x mutator classes, schema-derived. A chain's applicable +/// set is fixed by its payload type, writer and (for +/// ) reader, never by which fixture happens +/// to exist (see ): today that is 24 MPR chains x +/// , 40 chains (every chain) x +/// , 15 PartOfSpeech chains x +/// , and 12 chains (all three MPR writers, but only +/// the MorphologicalInput/PhonologicalSubrule readers -- see +/// for why the other five MPR readers are engine-proven +/// unreachable by this mutator) x -- 91 +/// (chain, class) candidates, each contributing a MutatorAbsent/MutatorPresent pair. Every +/// class now has a real structural detector ( for the three added +/// here; , reused unmodified from , +/// for ) that checks the exercising fixture(s) for the +/// engine's own necessary precondition -- never a proof of temporal ordering or of a specific word's +/// outcome, so status stays either way; only +/// 's same-word severance pair ever produces +/// . +/// +/// +public static class DataflowObligationLedger +{ + public const string RelativePath = "conformance/dataflow-obligations.tsv"; + + private const int ColumnCount = 11; + + public sealed record Row( + string CellId, + string WriterElement, + string WriterAttribute, + string PayloadType, + string ReaderElement, + string ReaderAttribute, + string CellKind, // "McDc" | "ConditionExtension" | "Mutator" + string Role, + string MutatorClass, // "-" unless CellKind == "Mutator" + ObligationStatus Status, + string Evidence + ); + + private const string NoMutatorClass = "-"; + + // ---------------------------------------------------------------------------------------- + // Mutator-class applicability (schema/engine-derived, not corpus-derived). + // ---------------------------------------------------------------------------------------- + + public static IReadOnlyList ApplicableMutatorClasses(InteractionChainLedger.Row chain) + { + ArgumentNullException.ThrowIfNull(chain); + var classes = new List { ObligationMutatorClass.Blocking }; + + if (chain.PayloadType == "MorphologicalPhonologicalRuleFeature") + { + classes.Add(ObligationMutatorClass.Overwrite); + if (IsCompoundingNonHeadDropReader(chain.ReaderElement, chain.ReaderAttribute)) + classes.Add(ObligationMutatorClass.CompoundingNonHeadDrop); + } + + if (chain.PayloadType == "PartOfSpeech") + classes.Add(ObligationMutatorClass.PosPriorityUnion); + + return classes; + } + + /// + /// is NOT applicable to every + /// MPR-payload chain a naive "writer is LexicalEntry.ruleFeatures" rule would suggest -- engine + /// verification narrows AND widens that guess, and both corrections are load-bearing (a mutator + /// that structurally cannot change a parse for a given chain must not generate an obligation for + /// it): + /// + /// NARROWED: CompoundingRule.headProdRestrictionsMprFeatures and + /// HeadMorphologicalInput.{required,excluded}MPRFeatures all gate on + /// input.MprFeatures -- the HEAD side, read BEFORE this same rule's own drop step + /// (SynthesisCompoundingRule.cs:116,136-137,153-154). For a writer's id to reach one of these + /// readers at all, it must have arrived via the undropped head path, so no drop event ever sits + /// between that write and that read. CompoundingRule.nonHeadProdRestrictionsMprFeatures is + /// read only by AnalysisCompoundingRule (line 76-77), straight off the candidate + /// LexEntry's own MprFeatures during unapplication -- a lexicon read, not the + /// derivation-accumulated state this generator's chains model, and outside this generator's + /// analysis-direction scope besides. + /// WIDENED: the drop empties the ENTIRE Word.MprFeatures bag regardless of which + /// construct wrote into it, so it reaches MorphologicalInput/PhonologicalSubrule + /// readers from ALL THREE MPR writers (LexicalEntry.ruleFeatures, + /// MorphologicalOutput.MPRFeatures, CompoundingRule.outputProdRestrictionsMprFeatures), + /// not only the lexical-entry one. + /// + /// Net effect: 12 chains (3 writers x these 4 readers), not the 8 a writer-only rule would produce. + /// + private static bool IsCompoundingNonHeadDropReader(string readerElement, string readerAttribute) => + (readerElement == "MorphologicalInput" || readerElement == "PhonologicalSubrule") + && (readerAttribute == "requiredMPRFeatures" || readerAttribute == "excludedMPRFeatures"); + + // ---------------------------------------------------------------------------------------- + // Condition-count scan for the MC/DC extension (point 2): n = the largest token count this + // generator finds, across the chain's own exercising fixtures, on a reader-attribute occurrence + // that actually carries one of the writer/reader shared ids. Mirrors the tokenizing + // InteractionChainLedger/MutatingConstructs already do, without modifying either file. + // ---------------------------------------------------------------------------------------- + + private sealed record ConditionScanResult(int MaxTokenCount, string FixtureId, string ObservedValue); + + private static IReadOnlyList Tokenize(string? value) => + string.IsNullOrEmpty(value) + ? Array.Empty() + : value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + + /// + /// Only meaningful for an MPR-feature payload: IsMatchRequired/IsMatchExcluded/ + /// CompoundMprFeaturesMatch are all n-ary over a flat, whitespace-separated IDREFS value. + /// POS/StemName reader gates are FeatureStruct unification, not decomposed here (see this class's + /// own doc comment) -- deliberately out of scope, not silently assumed single-condition. + /// + private static ConditionScanResult? ScanLargestConditionCount( + string repositoryRoot, + InteractionChainLedger.Row chain + ) + { + if (chain.PayloadType != "MorphologicalPhonologicalRuleFeature") + return null; + + int bestCount = 1; + string? bestFixture = null; + string? bestValue = null; + + foreach (string fixtureId in chain.ExercisingFixtures) + { + string grammarPath = Path.Combine( + repositoryRoot, + "conformance", + fixtureId.Replace('/', Path.DirectorySeparatorChar), + "grammar.xml" + ); + if (!File.Exists(grammarPath)) + continue; + + XDocument grammar = XDocument.Load(grammarPath); + + var writerIds = new HashSet(StringComparer.Ordinal); + foreach (XElement owner in grammar.Descendants(chain.WriterElement)) + { + foreach (string token in Tokenize((string?)owner.Attribute(chain.WriterAttribute))) + writerIds.Add(token); + } + + foreach (XElement owner in grammar.Descendants(chain.ReaderElement)) + { + string? rawValue = (string?)owner.Attribute(chain.ReaderAttribute); + IReadOnlyList readerTokens = Tokenize(rawValue); + if (readerTokens.Count == 0 || !readerTokens.Any(writerIds.Contains)) + continue; + + if (readerTokens.Count > bestCount) + { + bestCount = readerTokens.Count; + bestFixture = fixtureId; + bestValue = rawValue; + } + } + } + + return bestFixture is null ? null : new ConditionScanResult(bestCount, bestFixture, bestValue!); + } + + // ---------------------------------------------------------------------------------------- + // Pair-witness satisfaction (point 3): join the writer's and reader's already-computed + // InterfaceWitnessLedger rows for the SAME fixture on the SAME example word. + // ---------------------------------------------------------------------------------------- + + /// Shared with , which needs the same fail/pass + /// classification for its own severance-based Blocked arm. + internal static bool IsFailOutcome(string? outcome) => + outcome != null && outcome.EndsWith("::-", StringComparison.Ordinal); + + private readonly record struct PairedWitness(string FixtureId, string Word, string Role); + + /// + /// Finds, at most, one paired witness for a chain: the first exercising fixture (in the chain's own + /// sorted order) where the writer's and reader's severance rows both flip the SAME word from a + /// failed parse to a successful one -- the shape that means the gate was actively blocking that + /// word, and severing either side of the chain unblocks it. Direction is read off the reader + /// attribute's own name (required* => blocks on absence => AbsentGatedForm; + /// excluded* => blocks on presence => PresentGatedForm); every other reader name + /// (e.g. headPartsOfSpeech) or flip shape returns null -- a real paired witness may still + /// exist there, this generator just does not attempt to classify it. + /// + private static PairedWitness? FindPairedWitness( + InteractionChainLedger.Row chain, + IReadOnlyDictionary<(string Element, string Attribute, string Fixture), InterfaceWitnessResult> witnessByKey + ) + { + string role; + if (chain.ReaderAttribute.StartsWith("required", StringComparison.Ordinal)) + role = "AbsentGatedForm"; + else if (chain.ReaderAttribute.StartsWith("excluded", StringComparison.Ordinal)) + role = "PresentGatedForm"; + else + return null; + + foreach (string fixtureId in chain.ExercisingFixtures) + { + if ( + !witnessByKey.TryGetValue( + (chain.WriterElement, chain.WriterAttribute, fixtureId), + out InterfaceWitnessResult? w + ) + || !witnessByKey.TryGetValue( + (chain.ReaderElement, chain.ReaderAttribute, fixtureId), + out InterfaceWitnessResult? r + ) + ) + { + continue; + } + + if (w.Verdict != CounterfactualVerdict.Evidenced || r.Verdict != CounterfactualVerdict.Evidenced) + continue; + if (w.ExampleWord == null || w.ExampleWord != r.ExampleWord) + continue; + + bool writerFlipsFailToPass = IsFailOutcome(w.ExampleOutcome) && !IsFailOutcome(w.CounterexampleOutcome); + bool readerFlipsFailToPass = IsFailOutcome(r.ExampleOutcome) && !IsFailOutcome(r.CounterexampleOutcome); + if (writerFlipsFailToPass && readerFlipsFailToPass) + return new PairedWitness(fixtureId, w.ExampleWord, role); + } + + return null; + } + + // ---------------------------------------------------------------------------------------- + // Compute + // ---------------------------------------------------------------------------------------- + + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + IReadOnlyList chains = InteractionChainLedger.Compute(repositoryRoot); + IReadOnlyList witnessRows = InterfaceWitnessLedger.Read(repositoryRoot); + var witnessByKey = witnessRows.ToDictionary(r => (r.Element, r.Attribute, r.FixtureId)); + + var rows = new List(); + foreach (InteractionChainLedger.Row chain in chains) + { + PairedWitness? paired = chain.Exercised ? FindPairedWitness(chain, witnessByKey) : null; + + foreach (string role in new[] { "PresentControl", "PresentGatedForm", "AbsentControl", "AbsentGatedForm" }) + { + (ObligationStatus status, string evidence) = EvaluateMcDcCell(chain, role, paired); + rows.Add(BuildRow(chain, "McDc", role, NoMutatorClass, status, evidence, extensionKey: null)); + } + + ConditionScanResult? conditionScan = ScanLargestConditionCount(repositoryRoot, chain); + if (conditionScan is { MaxTokenCount: > 1 } scan) + { + // MC/DC over n conditions needs n+1 cases; the floor already carries 2 (present/absent), + // so n-1 extra McDc-style vectors are required, each still crossed with the + // control/gated-form axis that attributes the outcome. + for (int vector = 3; vector <= scan.MaxTokenCount + 1; vector++) + { + foreach (string half in new[] { "Control", "GatedForm" }) + { + string role = $"McDcVector{vector}{half}"; + string evidence = + $"mechanically required by {scan.MaxTokenCount}-condition gate observed in " + + $"{scan.FixtureId} ('{scan.ObservedValue}'); no per-vector witness check implemented yet"; + rows.Add( + BuildRow( + chain, + "ConditionExtension", + role, + NoMutatorClass, + ObligationStatus.Unknown, + evidence, + extensionKey: scan.FixtureId + ) + ); + } + } + } + + foreach (ObligationMutatorClass mutatorClass in ApplicableMutatorClasses(chain)) + { + (ObligationStatus status, string evidence) = EvaluateMutatorClass(repositoryRoot, chain, mutatorClass); + foreach (string role in new[] { "MutatorAbsent", "MutatorPresent" }) + { + rows.Add( + BuildRow(chain, "Mutator", role, mutatorClass.ToString(), status, evidence, extensionKey: null) + ); + } + } + } + + return Sort(rows); + } + + private static (ObligationStatus, string) EvaluateMcDcCell( + InteractionChainLedger.Row chain, + string role, + PairedWitness? paired + ) + { + if (!chain.Exercised) + { + return ( + ObligationStatus.NotSatisfied, + "chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv)" + ); + } + + if (paired is { } p && p.Role == role) + { + return ( + ObligationStatus.Satisfied, + $"paired witness: severing writer and reader both flip '{p.Word}' from failed to successful parse in {p.FixtureId} (conformance/interface-witness.tsv)" + ); + } + + return ( + ObligationStatus.Unknown, + "chain exercised (conformance/interaction-chains.tsv) but no same-word paired severance witness (writer+reader both Evidenced on the same example word in conformance/interface-witness.tsv) was found for this arm" + ); + } + + private static (ObligationStatus, string) EvaluateMutatorClass( + string repositoryRoot, + InteractionChainLedger.Row chain, + ObligationMutatorClass mutatorClass + ) + { + if (!chain.Exercised) + { + return ( + ObligationStatus.NotSatisfied, + "chain unexercised: no fixture sets writer and reader to a shared id (conformance/interaction-chains.tsv)" + ); + } + + switch (mutatorClass) + { + case ObligationMutatorClass.Overwrite: + return chain.Hazardous + ? ( + ObligationStatus.Unknown, + "structurally hazardous (conformance/interaction-chains.tsv: an exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id) but word-level witness of the kill itself is not independently checked here" + ) + : ( + ObligationStatus.Unknown, + "no exercising fixture has an overwrite-type MorphologicalPhonologicalRuleFeatureGroup covering the shared id yet" + ); + + case ObligationMutatorClass.Blocking: + return EvaluateBlocking(repositoryRoot, chain); + + case ObligationMutatorClass.PosPriorityUnion: + return EvaluatePosPriorityUnion(repositoryRoot, chain); + + case ObligationMutatorClass.CompoundingNonHeadDrop: + return EvaluateCompoundingNonHeadDrop(repositoryRoot, chain); + + default: + throw new ArgumentOutOfRangeException(nameof(mutatorClass), mutatorClass, "unhandled mutator class"); + } + } + + private static (ObligationStatus, string) EvaluateBlocking(string repositoryRoot, InteractionChainLedger.Row chain) + { + (bool eligible, string? fixtureId) = MutatorClassDetectors.ScanForAny( + repositoryRoot, + chain.ExercisingFixtures, + MutatorClassDetectors.HasEligibleFamily + ); + + return eligible + ? ( + ObligationStatus.Unknown, + $"structurally hazardous: {fixtureId} declares >=2 LexicalEntry sharing a family under the same Stratum (Word.CheckBlocking's family+stratum precondition, Word.cs:475-485); FeatureStruct subsumption and word-level witness of an actual block are not checked here" + ) + : ( + ObligationStatus.Unknown, + "no exercising fixture declares >=2 LexicalEntry sharing a family under the same Stratum -- Word.CheckBlocking (Word.cs:475-477) requires LexEntry.Family != null, so blocking cannot fire in any exercising fixture as authored" + ); + } + + private static (ObligationStatus, string) EvaluatePosPriorityUnion( + string repositoryRoot, + InteractionChainLedger.Row chain + ) + { + (int maxCount, string? fixtureId) = MutatorClassDetectors.ScanForMax( + repositoryRoot, + chain.ExercisingFixtures, + MutatorClassDetectors.CountPosWritingRuleElements + ); + + // A rule-element writer (MorphologicalRule/CompoundingRule.outputPartOfSpeech) counts as its own + // occurrence, so a genuinely different intervening mutator needs a second one; a LexicalEntry. + // partOfSpeech writer is not a rule at all, so any occurrence at all is a candidate mutator. + bool writerIsRuleElement = chain.WriterElement is "MorphologicalRule" or "CompoundingRule"; + int threshold = writerIsRuleElement ? 2 : 1; + + return maxCount >= threshold + ? ( + ObligationStatus.Unknown, + $"structurally hazardous: {fixtureId} declares {maxCount} outputPartOfSpeech-bearing MorphologicalRule/CompoundingRule element(s) -- SynthesisAffixProcessRule.cs:181-182/SynthesisCompoundingRule.cs:181-182's unconditional PriorityUnion gives each one a chance to clobber POS before this reader's gate; which element actually intervenes, and word-level witness of an actual clobber, are not checked here" + ) + : ( + ObligationStatus.Unknown, + "no exercising fixture declares a second outputPartOfSpeech-bearing rule besides (or, for a LexicalEntry writer, at all beyond) the chain's own writer -- PriorityUnion has nothing else to clobber with in this fixture as authored" + ); + } + + private static (ObligationStatus, string) EvaluateCompoundingNonHeadDrop( + string repositoryRoot, + InteractionChainLedger.Row chain + ) + { + (bool hasRule, string? fixtureId) = MutatorClassDetectors.ScanForAny( + repositoryRoot, + chain.ExercisingFixtures, + MutatorClassDetectors.HasCompoundingRule + ); + + return hasRule + ? ( + ObligationStatus.Unknown, + $"structurally hazardous: {fixtureId} declares a CompoundingRule -- SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds output from the head alone, so the non-head's entire MprFeatureSet is dropped unconditionally whenever this rule applies with the writer's word as non-head; which word actually plays non-head, and word-level witness of the drop, are not checked here" + ) + : ( + ObligationStatus.Unknown, + "no exercising fixture declares a CompoundingRule -- the drop mechanism (SynthesisCompoundingRule.cs:236) cannot fire in any exercising fixture as authored" + ); + } + + private static Row BuildRow( + InteractionChainLedger.Row chain, + string cellKind, + string role, + string mutatorClass, + ObligationStatus status, + string evidence, + string? extensionKey + ) + { + string cellId = + $"{chain.PayloadType}::{chain.WriterElement}.{chain.WriterAttribute}->{chain.ReaderElement}.{chain.ReaderAttribute}::{cellKind}:{role}" + + (mutatorClass == NoMutatorClass ? "" : $":{mutatorClass}") + + (extensionKey == null ? "" : $":{extensionKey}"); + + return new Row( + cellId, + chain.WriterElement, + chain.WriterAttribute, + chain.PayloadType, + chain.ReaderElement, + chain.ReaderAttribute, + cellKind, + role, + mutatorClass, + status, + evidence + ); + } + + private static IReadOnlyList Sort(IEnumerable rows) => + rows.OrderBy(r => r.PayloadType, StringComparer.Ordinal) + .ThenBy(r => r.WriterElement, StringComparer.Ordinal) + .ThenBy(r => r.WriterAttribute, StringComparer.Ordinal) + .ThenBy(r => r.ReaderElement, StringComparer.Ordinal) + .ThenBy(r => r.ReaderAttribute, StringComparer.Ordinal) + .ThenBy(r => r.CellKind, StringComparer.Ordinal) + .ThenBy(r => r.MutatorClass, StringComparer.Ordinal) + .ThenBy(r => r.Role, StringComparer.Ordinal) + .ThenBy(r => r.CellId, StringComparer.Ordinal) + .ToArray(); + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine("# GENERATED by hc-conformance --write-dataflow-obligations. One row per required CELL of"); + writer.WriteLine( + "# this file's own obligation matrix -- all-uses, plus MC/DC on every gate, plus every kill-path" + ); + writer.WriteLine( + "# witnessed -- built on conformance/interaction-chains.tsv (InteractionChainLedger). Every chain" + ); + writer.WriteLine( + "# gates (see DataflowObligationLedger's own doc comment for why the old required*/excluded*-name" + ); + writer.WriteLine("# heuristic was wrong), so cell_kind=McDc contributes the"); + writer.WriteLine("# floor 4 cells per chain (PresentControl/PresentGatedForm/AbsentControl/AbsentGatedForm)."); + writer.WriteLine( + "# cell_kind=ConditionExtension adds the extra MC/DC vectors an MPR-feature gate needs when a real" + ); + writer.WriteLine( + "# fixture's attribute value lists more than one feature id (n conditions need n+1 cases, not a" + ); + writer.WriteLine("# fixed 2) -- attributed to the specific fixture that realizes it. cell_kind=Mutator adds a"); + writer.WriteLine( + "# MutatorAbsent/MutatorPresent pair per (chain, ObligationMutatorClass) the payload type/writer" + ); + writer.WriteLine( + "# make schema-applicable -- mutator_class names which one; only Overwrite has a corpus detector" + ); + writer.WriteLine( + "# today, the other three are declared-but-unmodelled. status is Satisfied only for a same-word" + ); + writer.WriteLine("# PAIR witness (writer AND reader severance both flip one named word -- see"); + writer.WriteLine("# conformance/interface-witness.tsv); NotSatisfied when the chain is not even structurally"); + writer.WriteLine("# exercised; Unknown otherwise -- deliberate, not a gap (see this class's own doc comment)."); + writer.WriteLine( + "cell_id\twriter_element\twriter_attribute\tpayload_type\treader_element\treader_attribute\tcell_kind\trole\tmutator_class\tstatus\tevidence" + ); + foreach (Row row in Sort(rows)) + { + writer.WriteLine( + string.Join( + '\t', + row.CellId, + row.WriterElement, + row.WriterAttribute, + row.PayloadType, + row.ReaderElement, + row.ReaderAttribute, + row.CellKind, + row.Role, + row.MutatorClass, + row.Status, + row.Evidence + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("cell_id\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[9], out ObligationStatus status)) + throw new FormatException($"{RelativePath}: unknown status '{fields[9]}'"); + + rows.Add( + new Row( + fields[0], + fields[1], + fields[2], + fields[3], + fields[4], + fields[5], + fields[6], + fields[7], + fields[8], + status, + fields[10] + ) + ); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DeadSchemaDetector.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DeadSchemaDetector.cs new file mode 100644 index 000000000..4fb5be9d3 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DeadSchemaDetector.cs @@ -0,0 +1,77 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Finds DTD element names the engine never mentions. The loader reads the grammar document by +/// element name, so an element with no string-literal occurrence anywhere in the engine source +/// cannot influence a parse: it is schema the implementation does not consume, and no conformance +/// grammar can give it semantic coverage. +/// +public static class DeadSchemaDetector +{ + public const string EngineSourceRelativePath = "src/SIL.Machine.Morphology.HermitCrab"; + + public static IReadOnlyCollection ReadEngineSources(string repositoryRoot) + { + string root = Path.Combine(repositoryRoot, EngineSourceRelativePath.Replace('/', Path.DirectorySeparatorChar)); + return Directory + .GetFiles(root, "*.cs", SearchOption.AllDirectories) + .Where(path => !IsGenerated(path)) + .OrderBy(path => path, StringComparer.Ordinal) + .Select(File.ReadAllText) + .ToArray(); + } + + /// + /// Which of appear as a quoted string in no engine source file. + /// + public static IReadOnlySet FindUnreferenced(string repositoryRoot, IEnumerable elementNames) + { + ArgumentNullException.ThrowIfNull(elementNames); + IReadOnlyCollection sources = ReadEngineSources(repositoryRoot); + var unreferenced = new SortedSet(StringComparer.Ordinal); + foreach (string name in elementNames.Distinct(StringComparer.Ordinal)) + { + // A quoted literal is the loader's way of naming an element. nameof(X) names a TYPE, so + // counting it would let `case nameof(ComplexFeature)` launder a live element into + // dead-schema, which permanently excuses it from ever needing a fixture. + string quoted = $"\"{name}\""; + string nameOf = $"nameof({name})"; + if ( + !sources.Any(text => + text.Contains(quoted, StringComparison.Ordinal) || text.Contains(nameOf, StringComparison.Ordinal) + ) + ) + { + unreferenced.Add(name); + } + } + + return unreferenced; + } + + /// The DTD element a grammar-observable surface ID belongs to. + public static string? OwningElement(string surfaceId) + { + ArgumentNullException.ThrowIfNull(surfaceId); + if (surfaceId.StartsWith(GrammarFeatureUsage.ElementPrefix, StringComparison.Ordinal)) + return surfaceId[GrammarFeatureUsage.ElementPrefix.Length..]; + if (surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + { + string rest = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..]; + int slash = rest.IndexOf('/'); + return slash < 0 ? rest : rest[..slash]; + } + + return null; + } + + private static bool IsGenerated(string path) => + path.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", StringComparison.Ordinal) + || path.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", StringComparison.Ordinal); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DtdInventoryReader.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DtdInventoryReader.cs new file mode 100644 index 000000000..be0a7dabe --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/DtdInventoryReader.cs @@ -0,0 +1,847 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal static class DtdInventoryReader +{ + private const string Profile = "sil.machine.hc-semantic-catalog/v1"; + + private static readonly HashSet AttributeTypes = new(StringComparer.Ordinal) + { + "CDATA", + "ID", + "IDREF", + "IDREFS", + "NMTOKEN", + "NMTOKENS", + "ENTITY", + "ENTITIES", + }; + + public static SemanticInventory Read(string dtdPath, string dtdText) + { + ArgumentException.ThrowIfNullOrEmpty(dtdPath); + ArgumentNullException.ThrowIfNull(dtdText); + + var parser = new Parser(dtdPath, dtdText); + IReadOnlyList surfaces = parser.Parse(); + return new SemanticInventory( + Profile, + Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(dtdText))).ToLowerInvariant(), + InventorySurfaceFactory.Sort(surfaces) + ); + } + + private sealed class Parser(string path, string text) + { + private readonly string _path = path; + private readonly string _text = text; + private readonly List _surfaces = new(); + private readonly HashSet _elementNames = new(StringComparer.Ordinal); + private readonly HashSet _attributeNames = new(StringComparer.Ordinal); + private readonly HashSet _surfaceIds = new(StringComparer.Ordinal); + private int _index; + + public IReadOnlyList Parse() + { + while (true) + { + SkipWhitespaceAndComments(); + if (End) + { + return _surfaces; + } + + int declarationStart = _index; + if (!StartsWith(" _index >= _text.Length; + + private void ParseElementDeclaration(int start) + { + _index += "(StringComparer.Ordinal); + for (int index = 1; index < model.Children.Count; index++) + { + ContentNode child = model.Children[index]; + if ( + child.Kind != "element" + || child.Name is null + || child.MinOccurs != 1 + || child.MaxOccurs != 1 + || !names.Add(child.Name) + ) + { + Fail( + declarationStart, + "invalid mixed content model; expected unique unquantified element names after #PCDATA" + ); + } + } + } + + private static bool ContainsPcdata(ContentNode node) => + node.Kind == "pcdata" || node.Children.Any(ContainsPcdata); + + private ContentNode ParseGroup(int declarationStart) + { + Require('(', declarationStart, "content model group"); + SkipWhitespace(); + + var children = new List(); + char? separator = null; + while (true) + { + if (End) + { + Fail(declarationStart, "unterminated content model group"); + } + + ContentNode child = ParseContentTerm(declarationStart); + children.Add(child); + SkipWhitespace(); + + if (TryConsume(')')) + { + break; + } + + if (End) + { + Fail(declarationStart, "unterminated content model group"); + } + + char next = Current; + if (next is not (',' or '|')) + { + Fail(_index, "expected ',' or '|' in content model group"); + } + + if (separator is null) + { + separator = next; + } + else if (separator != next) + { + Fail(_index, "content model group cannot mix ',' and '|' separators"); + } + + _index++; + SkipWhitespace(); + } + + const int Min = 1; + const int Max = 1; + if (separator is null && children.Count == 1 && children[0].Kind == "pcdata" && Min == 1 && Max == 1) + { + return children[0]; + } + + string kind = separator == '|' ? "choice" : "sequence"; + return ContentNode.Group(kind, children, Min, Max); + } + + private ContentNode ParseContentTerm(int declarationStart) + { + ContentNode term; + if (Peek('(')) + { + term = ParseGroup(declarationStart); + } + else if (StartsWith("#PCDATA")) + { + _index += "#PCDATA".Length; + term = ContentNode.Special("pcdata", 1, 1); + } + else + { + string name = ReadName(declarationStart, "content model element"); + term = ContentNode.Element(name, 1, 1); + } + + (int min, int max) = ReadOccurrenceSuffix(); + if (term.IsGroup) + { + return term with { MinOccurs = min, MaxOccurs = max, GroupMinOccurs = min, GroupMaxOccurs = max }; + } + + return term with + { + MinOccurs = min, + MaxOccurs = max, + }; + } + + private void EmitContentNode( + string parent, + ContentNode node, + string? groupId, + string path, + int declarationStart, + int containingGroupMin = 1, + int containingGroupMax = 1 + ) + { + string cardinality = Cardinality(node.MinOccurs, node.MaxOccurs); + if (node.IsGroup) + { + string id = $"dtd:content/{CanonicalIdCodec.Encode(parent)}/{path}.{node.Kind}@{cardinality}"; + AddSurface( + new InventorySurface( + id, + "content-group", + parent, + parent, + Location(declarationStart), + $"kind={node.Kind};path={path};min={FormatMax(node.MinOccurs)};" + + $"max={FormatMax(node.MaxOccurs)};parent={parent}" + ) + ); + + for (int index = 0; index < node.Children.Count; index++) + { + EmitContentNode( + parent, + node.Children[index], + id, + $"{path}.{index}", + declarationStart, + node.MinOccurs, + node.MaxOccurs + ); + } + + return; + } + + if (node.Kind is "pcdata" or "empty" or "any") + { + string id = $"dtd:content/{CanonicalIdCodec.Encode(parent)}/{path}.{node.Kind}@{cardinality}"; + AddSurface( + new InventorySurface( + id, + "special-content", + node.Kind, + parent, + Location(declarationStart), + $"kind={node.Kind};path={path};min={FormatMax(node.MinOccurs)};" + + $"max={FormatMax(node.MaxOccurs)};parent={parent}" + ) + ); + return; + } + + string placementId = + $"dtd:placement/{CanonicalIdCodec.Encode(parent)}/{path}/" + + $"{CanonicalIdCodec.Encode(node.Name!)}/{cardinality}"; + AddSurface( + new InventorySurface( + placementId, + "placement", + node.Name!, + parent, + Location(declarationStart), + $"group={groupId ?? "none"};path={path};min={FormatMax(node.MinOccurs)};" + + $"max={FormatMax(node.MaxOccurs)};groupMin={FormatMax(containingGroupMin)};" + + $"groupMax={FormatMax(containingGroupMax)}" + ) + ); + } + + private void AddSurface(InventorySurface surface) + { + if (!_surfaceIds.Add(surface.Id)) + { + Fail(_index, $"duplicate generated surface ID {surface.Id}"); + } + + _surfaces.Add(surface); + } + + private void ParseAttributeListDeclaration(int start) + { + _index += "')) + { + _index++; + return; + } + + RequireDtdWhitespace("first attribute declaration"); + SkipWhitespace(); + + while (true) + { + if (TryConsume('>')) + { + return; + } + + if (End) + { + Fail(start, "unterminated ATTLIST declaration"); + } + + string attributeName = ReadName(start, "attribute name"); + string attributeKey = $"{elementName}/{attributeName}"; + if (!_attributeNames.Add(attributeKey)) + { + Fail(start, $"duplicate attribute declaration '{attributeKey}'"); + } + + RequireDtdWhitespace("attribute type"); + AttributeType type = ParseAttributeType(start); + RequireDtdWhitespace("attribute default declaration"); + + AttributeDefaultMode defaultModeKind; + string defaultValue; + if (TryReadKeyword("#REQUIRED")) + { + defaultModeKind = AttributeDefaultMode.Required; + defaultValue = "#REQUIRED"; + } + else if (TryReadKeyword("#IMPLIED")) + { + defaultModeKind = AttributeDefaultMode.Implied; + defaultValue = "#IMPLIED"; + } + else if (TryReadKeyword("#FIXED")) + { + defaultModeKind = AttributeDefaultMode.FixedValue; + RequireDtdWhitespace("fixed attribute default"); + defaultValue = ReadQuoted(start, "fixed attribute default"); + } + else + { + defaultModeKind = AttributeDefaultMode.DefaultValue; + defaultValue = ReadQuoted(start, "attribute default"); + } + + if ( + type.EnumValues.Count > 0 + && defaultModeKind is AttributeDefaultMode.DefaultValue or AttributeDefaultMode.FixedValue + && !type.EnumValues.Contains(defaultValue, StringComparer.Ordinal) + ) + { + Fail(start, $"attribute default '{defaultValue}' is not an enumeration member"); + } + + string encodedElementName = CanonicalIdCodec.Encode(elementName); + string encodedAttributeName = CanonicalIdCodec.Encode(attributeName); + string encodedType = CanonicalIdCodec.Encode(type.Display); + bool fixedValue = defaultModeKind is AttributeDefaultMode.FixedValue; + string defaultMode = defaultModeKind switch + { + AttributeDefaultMode.Required => "required", + AttributeDefaultMode.Implied => "implied", + AttributeDefaultMode.FixedValue => "fixed", + AttributeDefaultMode.DefaultValue => "default", + _ => throw new InvalidOperationException(), + }; + + AddSurface( + new InventorySurface( + $"dtd:attribute/{encodedElementName}/{encodedAttributeName}", + "attribute", + attributeName, + elementName, + Location(start), + $"type={type.Display};default={defaultValue};fixed={fixedValue.ToString().ToLowerInvariant()}" + ) + ); + AddSurface( + new InventorySurface( + $"dtd:attribute-type/{encodedElementName}/{encodedAttributeName}/{encodedType}", + "attribute-type", + type.Display, + elementName, + Location(start), + $"attribute={attributeName};type={type.Display}" + ) + ); + + string encodedDefaultValue = defaultModeKind + is AttributeDefaultMode.Required + or AttributeDefaultMode.Implied + ? string.Empty + : $"/{CanonicalIdCodec.Encode(defaultValue)}"; + AddSurface( + new InventorySurface( + $"dtd:attribute-default/{encodedElementName}/{encodedAttributeName}/{defaultMode}{encodedDefaultValue}", + "attribute-default", + defaultMode, + elementName, + Location(start), + $"attribute={attributeName};default={defaultValue};fixed={fixedValue.ToString().ToLowerInvariant()}" + ) + ); + + foreach (string value in type.EnumValues) + { + AddSurface( + new InventorySurface( + $"dtd:enum/{encodedElementName}/{encodedAttributeName}/{CanonicalIdCodec.Encode(value)}", + "enum", + value, + elementName, + Location(start), + $"attribute={attributeName};type=enumeration" + ) + ); + } + + if (defaultModeKind is not (AttributeDefaultMode.Required or AttributeDefaultMode.Implied)) + { + AddSurface( + new InventorySurface( + $"dtd:default/{encodedElementName}/{encodedAttributeName}/{CanonicalIdCodec.Encode(defaultValue)}", + "default", + defaultValue, + elementName, + Location(start), + $"attribute={attributeName};fixed={fixedValue.ToString().ToLowerInvariant()}" + ) + ); + } + + if (End) + { + Fail(start, "unterminated ATTLIST declaration"); + } + + if (TryConsume('>')) + { + return; + } + + RequireDtdWhitespace("next attribute declaration or '>'"); + } + } + + private AttributeType ParseAttributeType(int declarationStart) + { + if (TryConsume('(')) + { + var values = new List(); + while (true) + { + SkipWhitespace(); + string value = ReadEnumerationValue(declarationStart, "enumeration value"); + if (values.Contains(value, StringComparer.Ordinal)) + { + Fail(declarationStart, $"duplicate enumeration value '{value}'"); + } + + values.Add(value); + SkipWhitespace(); + if (TryConsume(')')) + { + break; + } + + Require('|', declarationStart, "attribute enumeration"); + } + + return new AttributeType("enumeration", values); + } + + string type = ReadName(declarationStart, "attribute type"); + if (!AttributeTypes.Contains(type)) + { + Fail(declarationStart, $"unsupported attribute type '{type}'"); + } + + return new AttributeType(type, Array.Empty()); + } + + private void ParseDoctypeDeclaration(int start) + { + Fail( + start, + "DOCTYPE declarations are unsupported at this seam because referenced declarations are not loaded" + ); + } + + private void RequireEndOfDeclaration(int declarationStart, string declarationKind) + { + SkipWhitespace(); + if (!TryConsume('>')) + { + if (End) + { + Fail(declarationStart, $"unterminated {declarationKind} declaration"); + } + + Fail(_index, $"unexpected content in {declarationKind} declaration"); + } + } + + private string ReadName(int _, string description) + { + SkipWhitespace(); + int start = _index; + if (End || !(char.IsLetter(Current) || Current is '_' or ':')) + { + Fail(start, $"expected {description}"); + } + + _index++; + while (!End && (char.IsLetterOrDigit(Current) || Current is '_' or '-' or '.' or ':')) + { + _index++; + } + + return _text[start.._index]; + } + + private string ReadEnumerationValue(int _, string description) + { + SkipWhitespace(); + int start = _index; + if (End || !(char.IsLetterOrDigit(Current) || Current is '_' or ':' or '-' or '.')) + { + Fail(start, $"expected {description}"); + } + + _index++; + while (!End && (char.IsLetterOrDigit(Current) || Current is '_' or '-' or '.' or ':')) + { + _index++; + } + + return _text[start.._index]; + } + + private string ReadQuoted(int _, string description) + { + SkipWhitespace(); + if (End || Current is not ('"' or '\'')) + { + Fail(_index, $"expected quoted {description}"); + } + + char quote = Current; + _index++; + int start = _index; + while (!End && Current != quote) + { + _index++; + } + + if (End) + { + Fail(start, $"unterminated quoted {description}"); + } + + string value = _text[start.._index]; + _index++; + return value; + } + + private void RequireDtdWhitespace(string description) + { + if (End || !IsDtdWhitespace(Current)) + { + Fail(_index, $"expected XML DTD whitespace before {description}"); + } + + SkipWhitespace(); + } + + private bool TryReadKeyword(string keyword) + { + SkipWhitespace(); + if (!StartsWith(keyword)) + { + return false; + } + + int end = _index + keyword.Length; + if (end < _text.Length && (char.IsLetterOrDigit(_text[end]) || _text[end] is '_' or '-' or ':')) + { + return false; + } + + _index = end; + return true; + } + + private (int Min, int Max) ReadOccurrenceSuffix() + { + if (End) + { + return (1, 1); + } + + return Current switch + { + '?' => ConsumeOccurrence(0, 1), + '*' => ConsumeOccurrence(0, int.MaxValue), + '+' => ConsumeOccurrence(1, int.MaxValue), + _ => (1, 1), + }; + } + + private (int Min, int Max) ConsumeOccurrence(int min, int max) + { + _index++; + return (min, max); + } + + private static string Cardinality(int min, int max) => + (min, max) switch + { + (0, 1) => "optional", + (0, int.MaxValue) => "zero-or-more", + (1, int.MaxValue) => "one-or-more", + _ => "one", + }; + + private static string FormatMax(int value) => value == int.MaxValue ? "unbounded" : value.ToString(); + + private void Require(char expected, int _, string description) + { + SkipWhitespace(); + if (!TryConsume(expected)) + { + Fail(_index, $"expected '{expected}' in {description}"); + } + } + + private bool TryConsume(char value) + { + if (!End && Current == value) + { + _index++; + return true; + } + + return false; + } + + private bool Peek(char value) => !End && Current == value; + + private bool StartsWith(string value) => _text.AsSpan(_index).StartsWith(value, StringComparison.Ordinal); + + private bool StartsWithDeclaration(string keyword) + { + int end = _index + keyword.Length; + return StartsWith(keyword) && end < _text.Length && IsDtdWhitespace(_text[end]); + } + + private char Current => _text[_index]; + + private static bool IsDtdWhitespace(char value) => value is ' ' or '\t' or '\r' or '\n'; + + private void SkipWhitespace() + { + while (!End && IsDtdWhitespace(Current)) + { + _index++; + } + } + + private void SkipWhitespaceAndComments() + { + while (true) + { + SkipWhitespace(); + if (!StartsWith("", _index + 4, StringComparison.Ordinal); + if (end < 0) + { + Fail(commentStart, "unterminated DTD comment"); + } + + string body = _text[(_index + 4)..end]; + if (body.Contains("--", StringComparison.Ordinal) || body.EndsWith("-", StringComparison.Ordinal)) + { + Fail(commentStart, "invalid DTD comment: comments cannot contain '--' or end with '-'"); + } + + _index = end + 3; + } + } + + private string Location(int offset) + { + (int line, int column) = GetLineAndColumn(offset); + return $"{_path}:{line}:{column}"; + } + + private void Fail(int offset, string message) + { + (int line, int column) = GetLineAndColumn(offset); + throw new SemanticCoverageParseException(_path, line, column, message); + } + + private (int Line, int Column) GetLineAndColumn(int offset) + { + int line = 1; + int column = 1; + int boundedOffset = Math.Clamp(offset, 0, _text.Length); + for (int index = 0; index < boundedOffset; index++) + { + if (_text[index] == '\n') + { + line++; + column = 1; + } + else + { + column++; + } + } + + return (line, column); + } + + private enum AttributeDefaultMode + { + Required, + Implied, + DefaultValue, + FixedValue, + } + + private sealed record AttributeType(string Display, IReadOnlyList EnumValues); + + private sealed record ContentNode( + string Kind, + string? Name, + IReadOnlyList Children, + int MinOccurs, + int MaxOccurs, + int GroupMinOccurs = 1, + int GroupMaxOccurs = 1 + ) + { + public bool IsGroup => Children.Count > 0; + + public static ContentNode Group(string kind, IReadOnlyList children, int min, int max) => + new(kind, null, children, min, max, min, max); + + public static ContentNode Element(string name, int min, int max) => + new("element", name, Array.Empty(), min, max); + + public static ContentNode Special(string kind, int min, int max) => + new(kind, null, Array.Empty(), min, max); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EngineGateInventoryLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EngineGateInventoryLedger.cs new file mode 100644 index 000000000..bf271bc7d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EngineGateInventoryLedger.cs @@ -0,0 +1,295 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Whether at least one fixture word demonstrably makes a gate fire. +public enum EngineGateStatus +{ + Witnessed, + Unreached, +} + +/// +/// The checked-in denominator for a coverage layer keyed to -- HermitCrab's +/// OWN enumeration of the 23 (excluding ) decisions it makes when +/// declining to apply or unapply something -- rather than to a DTD attribute pair, which is what every +/// other ledger in this directory (, , +/// ) is keyed to. +/// +/// +/// Why this denominator, alongside the DTD-attribute one, not instead of it. The DTD-attribute +/// layer is authored from the SCHEMA outward: it enumerates writer/reader attribute pairs a grammar +/// author can set. That is the right question for "does severing this payload flip a parse", but it +/// cannot even NAME a decision the schema fuses into no single attribute, or that several attributes +/// share. is authored from the ENGINE outward, so it draws different lines: +/// is one gate reached from four call sites across three files +/// (an unfinished obligatory template slot, an unrealizable realizational feature struct, or a +/// still-final-template-shaped derivation with rules left in its stratum) that no DTD-attribute pair +/// names at all; , , +/// , and +/// likewise have no row in conformance/dataflow-obligations.tsv at all -- not because they are +/// unimportant, but because that ledger's cells are payload write/read PAIRS and these are not that +/// shape. See this class's own table for exactly which of the 23 turn out +/// to have an identifiable attribute anyway (more than half do) and which genuinely do not. +/// +/// +/// +/// A row here is a WEAKER claim than a +/// dataflow-obligation cell -- do not read the two as +/// comparable strength. A satisfied obligation cell means a same-word PAIR witness: severing the +/// writer AND severing the reader both flip ONE named word from failed to successful (see +/// 's own doc comment). A Witnessed row here means only +/// that observed this value SOMEWHERE +/// in SOME word's trace tree -- with no attempt to distinguish a genuine per-word conflict from a rule +/// merely tried against a candidate it has nothing to do with, which +/// 's own doc comment documents as routine for several of these +/// reasons. "Some word made this gate fire" and "severing a payload provably flipped a parse" are +/// different claims; this ledger only ever makes the first one. +/// +/// +public static class EngineGateInventoryLedger +{ + public const string RelativePath = "conformance/engine-gate-inventory.tsv"; + + private const int ColumnCount = 6; + private const string NoAttributes = "-"; + + public sealed record Row( + string Gate, + string RaiseSites, + string DtdAttributes, + string TriggeredByFixtures, + string TriggeringWords, + EngineGateStatus Status + ); + + /// + /// The DTD attribute(s) that, per src/SIL.Machine.Morphology.HermitCrab/XmlLanguageLoader.cs, + /// feed the runtime state a gate's raise sites check -- hand-verified against source, exactly like + /// 's own schema/engine-derived + /// mapping, because "which attribute reaches which engine decision" requires reading what the + /// loader DOES with an attribute, which no regex over the DTD or the engine alone can derive. + /// is a genuine finding, not a placeholder, for six of the 23: three + /// (// + /// ) are driven by PhoneticSequence ELEMENT CONTENT (the + /// shape itself), never an attribute; and + /// are driven by the presence/order/overlap of + /// RequiredEnvironments/ExcludedEnvironments child ELEMENTS among an allomorph's siblings, again no + /// attribute; is a pure engine-internal + /// reconstruction check with no grammar input at all. Every other gate DOES resolve to a real + /// IDREFS/boolean attribute -- including three that are easy to assume have none + /// ( -> Allomorph.isBound, + /// -> MorphologicalRule.multipleApplication, + /// and -> Slot.optional/AffixTemplate.final). + /// + public static readonly IReadOnlyDictionary DtdAttributes = new Dictionary( + StringComparer.Ordinal + ) + { + // XmlLanguageLoader.cs:897 (MorphologicalRule), :1227 (CompoundingRule). + ["ObligatorySyntacticFeatures"] = + "MorphologicalRule.outputObligatoryFeatures;CompoundingRule.outputObligatoryFeatures", + // AllomorphCoOccurrenceRule is a global rule element that names its target via an IDREF + // attribute on ITSELF (conformance/HermitCrabInput.dtd:601-606), not an attribute on Allomorph. + ["AllomorphCoOccurrenceRules"] = "AllomorphCoOccurrenceRule.primaryAllomorph", + // RequiredEnvironments/ExcludedEnvironments are child ELEMENTS of Allomorph + // (conformance/HermitCrabInput.dtd:305,320-322), never an attribute. + ["Environments"] = NoAttributes, + // Same shape as AllomorphCoOccurrenceRules: MorphemeCoOccurrenceRule names its target via its + // own IDREF attribute (conformance/HermitCrabInput.dtd:585-590). + ["MorphemeCoOccurrenceRules"] = "MorphemeCoOccurrenceRule.primaryMorpheme", + // Structural: which of a morpheme's OTHER allomorphs are tried, driven by allomorph order, + // free-fluctuation, and Environment overlap (Allomorph.cs's IsWordValid) -- no attribute names it. + ["DisjunctiveAllomorph"] = NoAttributes, + // Pure engine-internal reconstruction check (Morpher.cs's IsMatch): the confirming synthesis's + // shape does not match the original surface. No grammar attribute feeds this at all. + ["SurfaceFormMismatch"] = NoAttributes, + // Driven by whether a MorphologicalInput/HeadMorphologicalInput/NonHeadMorphologicalInput's + // PhoneticSequence CONTENT matches the input shape -- element content, not an attribute. + ["Pattern"] = NoAttributes, + ["HeadPattern"] = NoAttributes, + ["NonHeadPattern"] = NoAttributes, + // XmlLanguageLoader.cs:872-874 (MorphologicalRule), :788-796 (PhonologicalSubrule). The + // RealizationalRule and per-subrule/per-allomorph raise sites reach this same reason from + // RequiredHeadFeatures/RequiredFootFeatures ELEMENTS alone, with no attribute at all -- these + // two attributes are real but do not cover every raise site for this gate. + ["RequiredSyntacticFeatureStruct"] = + "MorphologicalRule.requiredPartsOfSpeech;PhonologicalSubrule.requiredPartsOfSpeech", + // XmlLanguageLoader.cs:1159-1161. + ["HeadRequiredSyntacticFeatureStruct"] = "CompoundingRule.headPartsOfSpeech", + // XmlLanguageLoader.cs:1182-1184. + ["NonHeadRequiredSyntacticFeatureStruct"] = "CompoundingRule.nonHeadPartsOfSpeech", + // XmlLanguageLoader.cs:1217-1219. + ["HeadProdRestrictMprFeatures"] = "CompoundingRule.headProdRestrictionsMprFeatures", + // XmlLanguageLoader.cs:1220-1222. + ["NonHeadProdRestrictMprFeatures"] = "CompoundingRule.nonHeadProdRestrictionsMprFeatures", + // XmlLanguageLoader.cs:1057-1059 (MorphologicalInput, affix-process subrule), :1278 (Head- + // MorphologicalInput, compounding subrule), :798-800 (PhonologicalSubrule, rewrite subrule). + ["RequiredMprFeatures"] = + "MorphologicalInput.requiredMPRFeatures;HeadMorphologicalInput.requiredMPRFeatures;PhonologicalSubrule.requiredMPRFeatures", + // Same three elements, XmlLanguageLoader.cs:1060-1062/:1279/:801-803. + ["ExcludedMprFeatures"] = + "MorphologicalInput.excludedMPRFeatures;HeadMorphologicalInput.excludedMPRFeatures;PhonologicalSubrule.excludedMPRFeatures", + // RootAllomorph.cs reads its OWN Allomorph.stemName (XmlLanguageLoader's Allomorph loader); + // SynthesisAffixProcessRule.cs reads MorphologicalRule.requiredStemName (XmlLanguageLoader.cs:908-910). + ["RequiredStemName"] = "Allomorph.stemName;MorphologicalRule.requiredStemName", + // RootAllomorph.cs compares this allomorph's OWN Allomorph.stemName against a SIBLING + // allomorph's Allomorph.stemName (same attribute, opposite direction of the check). + ["ExcludedStemName"] = "Allomorph.stemName", + // XmlLanguageLoader.cs:1333 (Slot.optional feeds Word.IsAllMorphologicalRulesApplied), :1304 + // (AffixTemplate.final feeds Word.IsLastAppliedRuleFinal, read by SynthesisStratumRule.cs's own + // raise site). One raise site (Morpher.cs's RealizationalFeatureStruct check) additionally + // depends on RealizationalRule's RealizationalFeatures ELEMENT, which carries no attribute. + ["PartialParse"] = "Slot.optional;AffixTemplate.final", + // XmlLanguageLoader.cs's Allomorph loader reads Allomorph.isBound directly onto RootAllomorph.IsBound. + ["BoundRoot"] = "Allomorph.isBound", + // AffixTemplate.final (XmlLanguageLoader.cs:1304) plus MorphologicalRule.partial + // (XmlLanguageLoader.cs:865); CompoundingRule has no `partial` attribute of its own and reads + // the word-level IsPartial state a MorphologicalRule raise earlier in the derivation set. + ["NonPartialRuleProhibitedAfterFinalTemplate"] = "AffixTemplate.final;MorphologicalRule.partial", + ["NonPartialRuleRequiredAfterNonFinalTemplate"] = "AffixTemplate.final;MorphologicalRule.partial", + // XmlLanguageLoader.cs:867-869 (MorphologicalRule), :1154-1156 (CompoundingRule). + ["MaxApplicationCount"] = "MorphologicalRule.multipleApplication;CompoundingRule.multipleApplication", + }; + + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + IReadOnlyDictionary> raiseSites = RaiseSiteScanner.Scan(repositoryRoot); + IReadOnlyList witnesses = EngineGateWitnessSweep.Sweep(repositoryRoot); + var witnessesByGate = witnesses.ToLookup(w => w.Gate, StringComparer.Ordinal); + + var rows = new List(); + foreach (FailureReason reason in Enum.GetValues()) + { + if (reason == FailureReason.None) + continue; + + string gate = reason.ToString(); + string raiseSiteText = raiseSites.TryGetValue(gate, out IReadOnlyList? sites) + ? string.Join(';', sites) + : NoAttributes; + string dtdAttributeText = DtdAttributes.TryGetValue(gate, out string? attrs) ? attrs : NoAttributes; + + EngineGateWitnessSweep.Witness[] hits = witnessesByGate[gate].ToArray(); + string fixturesText = + hits.Length == 0 + ? NoAttributes + : string.Join( + ';', + hits.Select(h => h.FixtureId) + .Distinct(StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + ); + string wordsText = + hits.Length == 0 + ? NoAttributes + : string.Join( + ';', + hits.Select(h => h.Word) + .Distinct(StringComparer.Ordinal) + .OrderBy(w => w, StringComparer.Ordinal) + ); + EngineGateStatus status = hits.Length == 0 ? EngineGateStatus.Unreached : EngineGateStatus.Witnessed; + + rows.Add(new Row(gate, raiseSiteText, dtdAttributeText, fixturesText, wordsText, status)); + } + + return rows.OrderBy(r => r.Gate, StringComparer.Ordinal).ToArray(); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine( + "# GENERATED by hc-conformance --write-engine-gate-inventory. One row per SIL.Machine.Morphology." + ); + writer.WriteLine("# HermitCrab.FailureReason member (excluding None) -- HermitCrab's OWN enumeration of the"); + writer.WriteLine("# decisions it makes when declining to apply or unapply something, kept alongside (never"); + writer.WriteLine( + "# instead of) conformance/dataflow-obligations.tsv's DTD-attribute-pair denominator, because" + ); + writer.WriteLine( + "# the engine's own enum draws different lines than the schema does: it separates gates the DTD" + ); + writer.WriteLine("# fuses into one attribute and names several gates no DTD attribute pair expresses at all."); + writer.WriteLine("# raise_sites is mechanically scanned (RaiseSiteScanner); dtd_attributes is hand-verified"); + writer.WriteLine( + "# against XmlLanguageLoader.cs (see EngineGateInventoryLedger.DtdAttributes' own doc comment) and" + ); + writer.WriteLine("# '-' is a genuine finding for six gates, not a placeholder. triggered_by_fixtures/"); + writer.WriteLine( + "# triggering_words/status come from EngineGateWitnessSweep, an ACTUAL traced engine run over" + ); + writer.WriteLine( + "# every non-pathological, non-crash fixture -- status is Witnessed iff some word's trace tree" + ); + writer.WriteLine( + "# contains this FailureReason anywhere, a materially WEAKER claim than a dataflow-obligation" + ); + writer.WriteLine("# cell's same-word pair witness (see this file's own doc comment, and conformance/docs/"); + writer.WriteLine("# how-it-is-computed.md, for why the two are not comparable strength)."); + writer.WriteLine("gate\traise_sites\tdtd_attributes\ttriggered_by_fixtures\ttriggering_words\tstatus"); + foreach (Row row in rows.OrderBy(r => r.Gate, StringComparer.Ordinal)) + { + writer.WriteLine( + string.Join( + '\t', + row.Gate, + row.RaiseSites, + row.DtdAttributes, + row.TriggeredByFixtures, + row.TriggeringWords, + row.Status + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("gate\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[5], out EngineGateStatus status)) + throw new FormatException($"{RelativePath}: unknown status '{fields[5]}'"); + + rows.Add(new Row(fields[0], fields[1], fields[2], fields[3], fields[4], status)); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EngineGateWitnessSweep.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EngineGateWitnessSweep.cs new file mode 100644 index 000000000..fc7945a97 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EngineGateWitnessSweep.cs @@ -0,0 +1,99 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Runs every non-pathological, non-crash fixture's words through the reference engine with tracing +/// on and records every non- value observed ANYWHERE in the resulting +/// trace tree, tagged to the fixture and word that produced it -- the evidence behind +/// 's triggered_by_fixtures/triggering_words/ +/// status columns. +/// +/// This is a materially weaker claim than /'s +/// per-rule attribution, deliberately. Those two are careful to attribute a reason only to a rule +/// that provably OWNS the failing/blocked candidate -- 's own doc +/// comment records that a reason like fires routinely +/// for a rule merely TRIED against a candidate it has nothing to do with, in a linear/unordered +/// stratum search, and there is no value that reliably tells the two +/// apart. This sweep does not attempt to: it answers only "did this value appear anywhere while +/// parsing this word", which is the right (and only mechanically available) question for a gate +/// inventory keyed to the enum itself rather than to a specific rule instance. See +/// 's own doc comment for why a Witnessed gate here is a +/// weaker claim than a witnessed dataflow-obligation cell. +/// +public static class EngineGateWitnessSweep +{ + public sealed record Witness(string Gate, string FixtureId, string Word); + + public static IReadOnlyList Sweep(string repositoryRoot, Action? onFixtureStarted = null) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + var witnesses = new List(); + + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + // Mirrors CounterfactualLedger.Sweep's own exclusion: a pathological (budgeted) fixture + // exists precisely because some word may never terminate, and an expect_crash fixture's + // ground truth is that the engine throws before ever returning a traceable result -- neither + // has a trustworthy per-word trace tree to walk. + if (fixture.Words.BudgetMs is not null || fixture.Words.ExpectCrash) + continue; + + onFixtureStarted?.Invoke(fixture.Id, fixture.Words.Words.Count); + + Language language; + try + { + language = XmlLanguageLoader.Load(fixture.GrammarPath); + } + catch + { + continue; + } + + var traceManager = new TraceManager { IsTracing = true }; + var morpher = new Morpher(traceManager, language); + + foreach (WordEntry word in fixture.Words.Words) + { + bool guessRoot = word.Parses.Any(p => p.Guess); + object? trace; + try + { + morpher.ParseWord(word.Word, out trace, guessRoot).ToList(); + } + catch + { + // InvalidShapeException (skip words) and any other engine exception leave no trace + // worth walking; a gate cannot be witnessed by a word the engine never traced. + continue; + } + + foreach (string gate in ObservedGates(trace)) + witnesses.Add(new Witness(gate, fixture.Id, word.Word)); + } + } + + return witnesses; + } + + private static IReadOnlyList ObservedGates(object? trace) + { + var gates = new HashSet(StringComparer.Ordinal); + if (trace is Trace root) + Walk(root); + return gates.ToArray(); + + void Walk(Trace node) + { + if (node.FailureReason != FailureReason.None) + gates.Add(node.FailureReason.ToString()); + foreach (Trace child in node.Children) + Walk(child); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EvidenceCardGenerator.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EvidenceCardGenerator.cs new file mode 100644 index 000000000..776f2f48c --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EvidenceCardGenerator.cs @@ -0,0 +1,655 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// One rendered card: is the entire file content, ready to write as-is +/// under /. +public sealed record EvidenceCard(string CellId, string FileName, string Markdown); + +/// The result of comparing freshly d cards against +/// what is checked in under . +public sealed record EvidenceCardDiff(int StaleOrMissingCount, int ExtraFileCount, IReadOnlyList Details) +{ + public bool IsCurrent => StaleOrMissingCount == 0 && ExtraFileCount == 0; +} + +/// +/// Renders one reviewable Markdown card per row of , so a +/// reviewer reads one screen instead of hand-joining dataflow-obligations.tsv, interface-witness.tsv, +/// words.yaml's claimed_cells/note, and grammar.xml. +/// +/// +/// This is not a gate. It reads four already-checked-in, already-authoritative sources and +/// renders their contents; it computes no new verdict and writes to none of them. The single fact it +/// decides for itself is which (fixture, word) a cell's evidence refers to, and that decision is a text +/// extraction from (a fixed shape written by +/// itself) or a direct read of a claimed_cells entry -- +/// never a fresh severance run. +/// +/// +/// +/// Absence is rendered, never invented. A cell with no claimed_cells entry, no +/// extractable witnessing word, no proof:, or no named distinct_from says so in the +/// card's own words rather than leaving the section blank -- see this class's own falsification test +/// for why (an empty section read as "nothing to see" is exactly how an unexamined claim gets waved +/// through). +/// +/// +public static class EvidenceCardGenerator +{ + public const string RelativeDirectory = "conformance/evidence-cards"; + private const string IndexFileName = "index.tsv"; + + private static readonly Regex PairedWitnessPattern = new( + @"flip '(?[^']+)' from failed to successful parse in (?\S+) \(", + RegexOptions.Compiled + ); + + // Matches the two other evidence shapes DataflowObligationLedger writes that name a fixture but no + // word: "structurally hazardous: declares..." (Mutator cells) and "...observed in + // ('...')" (ConditionExtension cells). Never invents a fixture the evidence text does not + // itself name. + private static readonly Regex FixtureOnlyPattern = new( + @"(?:hazardous:\s+|observed in\s+)(?(?:languages|edge-cases)/[A-Za-z0-9\-]+)", + RegexOptions.Compiled + ); + + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + + IReadOnlyList cells = DataflowObligationLedger.Read(repositoryRoot); + IReadOnlyList witnesses = InterfaceWitnessLedger.Read(repositoryRoot); + IReadOnlyList fixtures = Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance")); + + var witnessByKey = + new Dictionary<(string Element, string Attribute, string FixtureId), InterfaceWitnessResult>(); + foreach (InterfaceWitnessResult w in witnesses) + witnessByKey[(w.Element, w.Attribute, w.FixtureId)] = w; + + var claimsByCellId = new Dictionary>( + StringComparer.Ordinal + ); + foreach (Fixture fixture in fixtures) + { + foreach (WordEntry word in fixture.Words.Words) + { + foreach (ClaimedCellEntry claim in word.ClaimedCells) + { + if (!claimsByCellId.TryGetValue(claim.Cell, out List<(string, WordEntry, ClaimedCellEntry)>? list)) + { + list = new List<(string, WordEntry, ClaimedCellEntry)>(); + claimsByCellId[claim.Cell] = list; + } + list.Add((fixture.Id, word, claim)); + } + } + } + + var cards = new List(); + var seenFileNames = new HashSet(StringComparer.Ordinal); + foreach (DataflowObligationLedger.Row row in cells) + { + IReadOnlyList<(string FixtureId, WordEntry Word, ClaimedCellEntry Claim)> claims = + claimsByCellId.TryGetValue(row.CellId, out List<(string, WordEntry, ClaimedCellEntry)>? found) + ? found + : Array.Empty<(string, WordEntry, ClaimedCellEntry)>(); + + (string? FixtureId, string? Word, string Source) primary = ResolvePrimaryWitness(row, claims); + string markdown = BuildMarkdown(row, claims, primary, witnessByKey, fixtures, repositoryRoot); + string fileName = SlugFileName(row.CellId); + if (!seenFileNames.Add(fileName)) + { + throw new InvalidOperationException( + $"evidence card filename collision for cell '{row.CellId}' -> '{fileName}'" + ); + } + + cards.Add(new EvidenceCard(row.CellId, fileName, markdown)); + } + + return cards; + } + + /// Writes every card plus index.tsv, and removes any file in the directory that is + /// not part of the fresh set -- so a deleted or renamed cell's stale card can never linger unnoticed + /// next to a Check() that only compares what it expects to find. + public static void Write(string repositoryRoot, IReadOnlyList cards) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(cards); + + string dir = Path.Combine(repositoryRoot, RelativeDirectory.Replace('/', Path.DirectorySeparatorChar)); + Directory.CreateDirectory(dir); + + var expected = new HashSet(cards.Select(c => c.FileName), StringComparer.Ordinal) { IndexFileName }; + foreach (string existing in Directory.EnumerateFiles(dir)) + { + if (!expected.Contains(Path.GetFileName(existing))) + File.Delete(existing); + } + + foreach (EvidenceCard card in cards) + File.WriteAllText(Path.Combine(dir, card.FileName), card.Markdown); + + File.WriteAllText(Path.Combine(dir, IndexFileName), ToIndexText(cards)); + } + + /// Compares freshly computed cards against the checked-in directory without writing + /// anything -- the drift check a build runs. + public static EvidenceCardDiff Check(string repositoryRoot, IReadOnlyList cards) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(cards); + + string dir = Path.Combine(repositoryRoot, RelativeDirectory.Replace('/', Path.DirectorySeparatorChar)); + var details = new List(); + int staleOrMissing = 0; + + foreach (EvidenceCard card in cards) + { + string path = Path.Combine(dir, card.FileName); + if (!File.Exists(path)) + { + staleOrMissing++; + details.Add($"MISSING {card.CellId} ({card.FileName})"); + continue; + } + + string onDisk = File.ReadAllText(path).ReplaceLineEndings("\n"); + string fresh = card.Markdown.ReplaceLineEndings("\n"); + if (!string.Equals(onDisk, fresh, StringComparison.Ordinal)) + { + staleOrMissing++; + details.Add($"STALE {card.CellId} ({card.FileName})"); + } + } + + string indexPath = Path.Combine(dir, IndexFileName); + string freshIndex = ToIndexText(cards).ReplaceLineEndings("\n"); + if ( + !File.Exists(indexPath) + || !string.Equals( + File.ReadAllText(indexPath).ReplaceLineEndings("\n"), + freshIndex, + StringComparison.Ordinal + ) + ) + { + staleOrMissing++; + details.Add($"STALE {IndexFileName}"); + } + + var expected = new HashSet(cards.Select(c => c.FileName), StringComparer.Ordinal) { IndexFileName }; + int extra = 0; + if (Directory.Exists(dir)) + { + foreach (string existing in Directory.EnumerateFiles(dir)) + { + string name = Path.GetFileName(existing); + if (expected.Contains(name)) + continue; + extra++; + details.Add( + $"EXTRA FILE {name} (not produced by any current cell -- regenerate with --write-evidence-cards)" + ); + } + } + + return new EvidenceCardDiff(staleOrMissing, extra, details); + } + + public static string ToIndexText(IReadOnlyList cards) + { + ArgumentNullException.ThrowIfNull(cards); + var writer = new StringWriter(); + writer.WriteLine( + "# GENERATED by hc-conformance --write-evidence-cards. Maps each conformance/dataflow-obligations.tsv" + ); + writer.WriteLine( + "# cell_id to the Markdown card that renders it under conformance/evidence-cards/ -- file names are" + ); + writer.WriteLine( + "# a truncated, sanitized slug of the cell id plus a stable content hash (cell ids contain ':'/'.'" + ); + writer.WriteLine("# /'->' and can exceed Windows path-length limits verbatim), so this index is the lookup a"); + writer.WriteLine("# human or gate uses instead of reconstructing the file name by hand."); + writer.WriteLine("cell_id\tfile_name"); + foreach (EvidenceCard card in cards.OrderBy(c => c.CellId, StringComparer.Ordinal)) + writer.WriteLine($"{card.CellId}\t{card.FileName}"); + return writer.ToString(); + } + + // ---------------------------------------------------------------------------------------- + // Resolving which (fixture, word), if any, this cell's evidence refers to. + // ---------------------------------------------------------------------------------------- + + private static (string? FixtureId, string? Word, string Source) ResolvePrimaryWitness( + DataflowObligationLedger.Row row, + IReadOnlyList<(string FixtureId, WordEntry Word, ClaimedCellEntry Claim)> claims + ) + { + if (claims.Count > 0) + return (claims[0].FixtureId, claims[0].Word.Word, "claimed_cells entry in words.yaml"); + + Match paired = PairedWitnessPattern.Match(row.Evidence); + if (paired.Success) + { + return ( + paired.Groups["fixture"].Value, + paired.Groups["word"].Value, + "extracted from this cell's dataflow-obligations.tsv evidence text" + ); + } + + Match fixtureOnly = FixtureOnlyPattern.Match(row.Evidence); + if (fixtureOnly.Success) + { + return ( + fixtureOnly.Groups["fixture"].Value, + null, + "extracted from this cell's dataflow-obligations.tsv evidence text (names a fixture, no specific word)" + ); + } + + return (null, null, "none -- no claim and no fixture/word named in this cell's evidence text"); + } + + // ---------------------------------------------------------------------------------------- + // Plain-English role text. + // ---------------------------------------------------------------------------------------- + + private static readonly Regex ConditionExtensionRolePattern = new( + @"^McDcVector(?\d+)(?Control|GatedForm)$", + RegexOptions.Compiled + ); + + private static string MutatorClassPlainEnglish(string mutatorClass) => + mutatorClass switch + { + "Overwrite" => "an MPR-feature overwrite group (a MorphologicalPhonologicalRuleFeatureGroup with " + + "outputType=\"overwrite\" drops the accumulated feature set before the read)", + "Blocking" => "blocking (Word.CheckBlocking rebuilds the derivation from a sibling LexicalEntry, clearing " + + "and reseeding MPR features, part of speech, and stem name)", + "PosPriorityUnion" => + "a part-of-speech priority-union clobber (an intervening rule's own outputPartOfSpeech " + + "overwrites an earlier part-of-speech write via PriorityUnion)", + "CompoundingNonHeadDrop" => + "a compounding non-head drop (the output word is built from the head alone, so the " + + "non-head's payload is never copied into it)", + _ => mutatorClass, + }; + + private static string RolePlainEnglish(DataflowObligationLedger.Row row) + { + switch (row.CellKind) + { + case "McDc": + return row.Role switch + { + "PresentControl" => "the payload IS present, and the reader does NOT block (control case: normal " + + "operation with the payload present).", + "PresentGatedForm" => "the payload IS present and the gated form IS blocked.", + "AbsentControl" => "the payload is ABSENT, and the reader does NOT block (control case: normal " + + "operation without the payload).", + "AbsentGatedForm" => "the payload is ABSENT and the gated form IS blocked.", + _ => $"(unrecognized McDc role '{row.Role}' -- this generator does not know how to describe it)", + }; + + case "ConditionExtension": + { + Match m = ConditionExtensionRolePattern.Match(row.Role); + if (!m.Success) + return $"(unrecognized ConditionExtension role '{row.Role}' -- this generator does not know how to describe it)"; + + string half = + m.Groups["half"].Value == "GatedForm" + ? "the gated form IS blocked" + : "the reader does NOT block (control)"; + return $"Extra MC/DC vector #{m.Groups["n"].Value}, required because the reader's gate has more than " + + $"one condition -- see the chain kind below. This arm is where {half}."; + } + + case "Mutator": + return row.Role switch + { + "MutatorAbsent" => + $"no mutator sits between the write and the read: {MutatorClassPlainEnglish(row.MutatorClass)} " + + "is ABSENT from the path.", + "MutatorPresent" => + $"a mutator sits between the write and the read: {MutatorClassPlainEnglish(row.MutatorClass)} " + + "is PRESENT and structurally capable of killing the payload before the reader sees it.", + _ => $"(unrecognized Mutator role '{row.Role}' -- this generator does not know how to describe it)", + }; + + default: + return $"(unrecognized cell_kind '{row.CellKind}' -- this generator does not know how to describe it)"; + } + } + + // ---------------------------------------------------------------------------------------- + // Markdown rendering. + // ---------------------------------------------------------------------------------------- + + private static string BuildMarkdown( + DataflowObligationLedger.Row row, + IReadOnlyList<(string FixtureId, WordEntry Word, ClaimedCellEntry Claim)> claims, + (string? FixtureId, string? Word, string Source) primary, + IReadOnlyDictionary<(string Element, string Attribute, string FixtureId), InterfaceWitnessResult> witnessByKey, + IReadOnlyList fixtures, + string repositoryRoot + ) + { + var sb = new StringBuilder(); + + sb.AppendLine($"# {row.CellId}"); + sb.AppendLine(); + sb.AppendLine("GENERATED by `hc-conformance --write-evidence-cards`. Do not hand-edit; regenerate instead."); + sb.AppendLine(); + + sb.AppendLine("## Role, in plain English"); + sb.AppendLine(); + sb.AppendLine(RolePlainEnglish(row)); + sb.AppendLine(); + + sb.AppendLine("## Chain"); + sb.AppendLine(); + sb.AppendLine($"- Writer: `{row.WriterElement}.{row.WriterAttribute}`"); + sb.AppendLine($"- Payload type: `{row.PayloadType}`"); + sb.AppendLine($"- Reader: `{row.ReaderElement}.{row.ReaderAttribute}`"); + sb.AppendLine( + row.MutatorClass == "-" + ? $"- Cell kind: `{row.CellKind}`" + : $"- Cell kind: `{row.CellKind}`, mutator class: `{row.MutatorClass}`" + ); + sb.AppendLine(); + + sb.AppendLine("## Machine status"); + sb.AppendLine(); + sb.AppendLine( + $"**{row.Status}** -- machine-established (`conformance/dataflow-obligations.tsv`), never a review " + + "verdict. A human sign-off is a separate fact and is never recorded here." + ); + sb.AppendLine(); + sb.AppendLine($"Ledger evidence: {row.Evidence}"); + sb.AppendLine(); + + sb.AppendLine("## Fixture and word"); + sb.AppendLine(); + if (claims.Count > 0) + { + foreach ((string fixtureId, WordEntry word, ClaimedCellEntry _) in claims) + { + sb.AppendLine( + $"- Claimed by word **'{word.Word}'** in `{fixtureId}` (a `claimed_cells` entry in `words.yaml`)." + ); + } + } + else if (primary.FixtureId is not null) + { + sb.AppendLine( + primary.Word is not null + ? $"- No `claimed_cells` entry names this cell. The ledger's own evidence names word " + + $"**'{primary.Word}'** in `{primary.FixtureId}` ({primary.Source})." + : $"- No `claimed_cells` entry names this cell, and the ledger's evidence names no specific " + + $"word -- only fixture `{primary.FixtureId}` ({primary.Source})." + ); + } + else + { + sb.AppendLine( + "- No fixture or word is identified for this cell: no claim, and the ledger's evidence names none." + ); + } + sb.AppendLine(); + + string[] fixtureIdsInScope = + claims.Count > 0 ? claims.Select(c => c.FixtureId).Distinct(StringComparer.Ordinal).ToArray() + : primary.FixtureId is not null ? new[] { primary.FixtureId } + : Array.Empty(); + + sb.AppendLine("## Exact mutation and before/after parse"); + sb.AppendLine(); + if (claims.Count == 0) + { + sb.AppendLine("No `claimed_cells` entry recorded an author-reviewed severing/before/after for this cell."); + sb.AppendLine(); + } + else + { + foreach ((string fixtureId, WordEntry word, ClaimedCellEntry claim) in claims) + { + sb.AppendLine($"### Author's claim ({fixtureId} / '{word.Word}')"); + sb.AppendLine(); + if (claim.HasReviewBundle) + { + sb.AppendLine($"- Severing: {claim.Severing}"); + sb.AppendLine($"- Before: `{claim.Before}`"); + sb.AppendLine($"- After: `{claim.After}`"); + } + else + { + sb.AppendLine("- No severing/before/after recorded on this claim yet (unreviewed)."); + } + sb.AppendLine(); + } + } + + sb.AppendLine("### Machine witness (`conformance/interface-witness.tsv`)"); + sb.AppendLine(); + if (fixtureIdsInScope.Length == 0) + { + sb.AppendLine("No fixture is identified for this cell, so no witness row can be looked up."); + } + else + { + foreach (string fixtureId in fixtureIdsInScope) + { + AppendWitnessLine(sb, witnessByKey, row.WriterElement, row.WriterAttribute, fixtureId, "Writer"); + AppendWitnessLine(sb, witnessByKey, row.ReaderElement, row.ReaderAttribute, fixtureId, "Reader"); + } + } + sb.AppendLine(); + + sb.AppendLine("## Grammar citations"); + sb.AppendLine(); + if (fixtureIdsInScope.Length == 0) + { + sb.AppendLine("No fixture is identified for this cell, so no `grammar.xml` lines can be cited."); + } + else + { + foreach (string fixtureId in fixtureIdsInScope) + { + string grammarPath = Path.Combine( + repositoryRoot, + "conformance", + fixtureId.Replace('/', Path.DirectorySeparatorChar), + "grammar.xml" + ); + sb.AppendLine($"### `{fixtureId}/grammar.xml`"); + sb.AppendLine(); + AppendCitations( + sb, + grammarPath, + row.WriterElement, + row.WriterAttribute, + "Writer (payload declared here)" + ); + AppendCitations(sb, grammarPath, row.ReaderElement, row.ReaderAttribute, "Reader (gate declared here)"); + sb.AppendLine(); + } + } + + sb.AppendLine("## Author's prose"); + sb.AppendLine(); + if (claims.Count > 0) + { + foreach ((string fixtureId, WordEntry word, ClaimedCellEntry claim) in claims) + { + if (claim.Proof.Length != 0) + { + sb.AppendLine($"- `proof:` (claimed_cells, '{word.Word}' in {fixtureId}): {claim.Proof}"); + } + else if (word.Note.Length != 0) + { + sb.AppendLine( + $"- No `proof:` on this claim. Falling back to the word's `note:` ('{word.Word}' in " + + $"{fixtureId}): {word.Note}" + ); + } + else + { + sb.AppendLine( + $"- No prose recorded: '{word.Word}' in {fixtureId} has neither a claim `proof:` nor a word `note:`." + ); + } + } + } + else if (primary is { FixtureId: not null, Word: not null }) + { + WordEntry? witnessWord = fixtures + .FirstOrDefault(f => f.Id == primary.FixtureId) + ?.Words.Words.FirstOrDefault(w => w.Word == primary.Word); + if (witnessWord is { Note.Length: > 0 }) + { + sb.AppendLine( + $"- No claim exists for this cell. This is the witnessing word's `note:` ('{primary.Word}' in " + + $"{primary.FixtureId}): {witnessWord.Note}" + ); + } + else + { + sb.AppendLine("- No prose recorded: no claim exists, and the witnessing word has no `note:`."); + } + } + else + { + sb.AppendLine("- No prose recorded: no claim, and no word is identified for this cell."); + } + sb.AppendLine(); + + sb.AppendLine("## `distinct_from` counterpart"); + sb.AppendLine(); + if (claims.Count == 0) + { + sb.AppendLine("No claim exists for this cell, so no `distinct_from` counterpart is recorded."); + } + else + { + foreach ((string fixtureId, WordEntry word, ClaimedCellEntry claim) in claims) + { + if (claim.DistinctFrom.Length == 0) + { + sb.AppendLine($"- '{word.Word}' in {fixtureId}: no `distinct_from` named."); + continue; + } + + Fixture? fixture = fixtures.FirstOrDefault(f => f.Id == fixtureId); + WordEntry? counterpart = fixture?.Words.Words.FirstOrDefault(w => w.Word == claim.DistinctFrom); + sb.AppendLine( + counterpart is null + ? $"- '{word.Word}' in {fixtureId}: `distinct_from` names **'{claim.DistinctFrom}'**, which " + + "does not exist in this fixture." + : $"- '{word.Word}' in {fixtureId}: `distinct_from` **'{counterpart.Word}'** " + + $"(expect_fail={counterpart.ExpectFail}) vs. this word (expect_fail={word.ExpectFail})." + ); + } + } + + return sb.ToString(); + } + + private static void AppendWitnessLine( + StringBuilder sb, + IReadOnlyDictionary<(string Element, string Attribute, string FixtureId), InterfaceWitnessResult> witnessByKey, + string element, + string attribute, + string fixtureId, + string role + ) + { + if (witnessByKey.TryGetValue((element, attribute, fixtureId), out InterfaceWitnessResult? w)) + { + string example = w.ExampleWord is null + ? "" + : $", example: '{w.ExampleWord}': {w.ExampleOutcome} -> {w.CounterexampleOutcome}"; + sb.AppendLine( + $"- {role} (`{element}.{attribute}` in `{fixtureId}`): verdict={w.Verdict}, mutation=\"{w.Mutation}\"{example}" + ); + } + else + { + sb.AppendLine( + $"- {role} (`{element}.{attribute}` in `{fixtureId}`): no row in `interface-witness.tsv` for this " + + "(element, attribute, fixture) triple." + ); + } + } + + private static void AppendCitations( + StringBuilder sb, + string grammarPath, + string element, + string attribute, + string role + ) + { + if (!File.Exists(grammarPath)) + { + sb.AppendLine($"- {role} `{element}.{attribute}`: `grammar.xml` not found at `{grammarPath}`."); + return; + } + + XDocument doc = XDocument.Load(grammarPath, LoadOptions.SetLineInfo); + (int Line, string Value)[] occurrences = doc.Descendants(element) + .Select(el => (Element: el, Attr: el.Attribute(attribute))) + .Where(x => x.Attr is not null) + .Select(x => (Line: ((IXmlLineInfo)x.Element).LineNumber, Value: x.Attr!.Value)) + .OrderBy(x => x.Line) + .ToArray(); + + if (occurrences.Length == 0) + { + sb.AppendLine($"- {role} `{element}.{attribute}`: no occurrence found in this fixture's `grammar.xml`."); + return; + } + + foreach ((int line, string value) in occurrences) + sb.AppendLine($"- {role} `{element}.{attribute}`: `grammar.xml:{line}` = \"{value}\""); + } + + // ---------------------------------------------------------------------------------------- + // Filenames: cell ids contain "::", "->", ":", and "." -- ":" and the ">" half of "->" are + // illegal or reserved in a Windows path, and a cell id can run past 170 characters, which risks + // MAX_PATH once joined to a repository path. Sanitizing to [A-Za-z0-9._-] and truncating keeps the + // name short and legal; the appended hash (stable across processes -- never string.GetHashCode, + // which .NET randomizes per process) is what actually guarantees uniqueness, so truncation can + // never silently collapse two distinct cells onto one file. + // ---------------------------------------------------------------------------------------- + + private const int MaxSlugLength = 100; + + private static string SlugFileName(string cellId) + { + string safe = new(cellId.Select(c => char.IsLetterOrDigit(c) || c is '.' or '-' or '_' ? c : '_').ToArray()); + safe = Regex.Replace(safe, "_+", "_").Trim('_'); + if (safe.Length > MaxSlugLength) + safe = safe.Substring(0, MaxSlugLength); + + string hash = Convert + .ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(cellId))) + .Substring(0, 10) + .ToLowerInvariant(); + return $"{safe}__{hash}.md"; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EvidenceLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EvidenceLedger.cs new file mode 100644 index 000000000..6f44c485a --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/EvidenceLedger.cs @@ -0,0 +1,183 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// The machine-checkable coverage ledger: one row per resolved by +/// , with the example, the counter-example, and its kind as explicit columns. +/// Unlike 's free-text Delta column, every field here is read back +/// and compared by -- it is the source of truth, not +/// documentation of one. Items resolved by instead live in +/// 's file, never here. +/// +public static class EvidenceLedger +{ + public const string RelativePath = "conformance/semantic-coverage-evidence.tsv"; + + private const string NullField = "-"; + private const int ColumnCount = 9; + + /// One ledger line: a joined to the that + /// resolves it. + public sealed record Row( + string ItemId, + CoverageItemKind Kind, + string Fixture, + string? ExampleWord, + string? ExampleOutcome, + CounterexampleKind CounterexampleKind, + string? CounterexampleOutcome, + string Mutation, + CounterfactualVerdict Verdict + ); + + /// Joins an item to its evidence into the flattened row the ledger stores. + public static Row ToRow(CoverageItem item, Evidence evidence) + { + ArgumentNullException.ThrowIfNull(item); + ArgumentNullException.ThrowIfNull(evidence); + if (item.Id != evidence.ItemId) + throw new ArgumentException($"item '{item.Id}' does not match evidence for '{evidence.ItemId}'"); + + return new Row( + item.Id, + item.Kind, + evidence.Fixture, + evidence.ExampleWord, + evidence.ExampleOutcome, + evidence.CounterexampleKind, + evidence.CounterexampleOutcome, + evidence.Mutation, + evidence.Verdict + ); + } + + /// Restores evidence only after checking the row against its generated item. + public static Evidence ToEvidence(Row row, CoverageItem item) + { + ArgumentNullException.ThrowIfNull(row); + ArgumentNullException.ThrowIfNull(item); + if (!string.Equals(row.ItemId, item.Id, StringComparison.Ordinal)) + { + throw new ArgumentException( + $"evidence row item '{row.ItemId}' does not match generated item '{item.Id}'", + nameof(row) + ); + } + if (row.Kind != item.Kind) + { + throw new ArgumentException( + $"evidence row '{row.ItemId}' kind '{row.Kind}' does not match generated kind '{item.Kind}'", + nameof(row) + ); + } + if (!string.Equals(row.Fixture, item.Fixture, StringComparison.Ordinal)) + { + throw new ArgumentException( + $"evidence row '{row.ItemId}' fixture '{row.Fixture}' does not match generated fixture '{item.Fixture}'", + nameof(row) + ); + } + + return new Evidence( + row.ItemId, + row.Fixture, + row.ExampleWord, + row.ExampleOutcome, + row.CounterexampleKind, + row.CounterexampleOutcome, + row.Mutation, + row.Verdict + ); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + using var writer = new StreamWriter(path, false); + writer.WriteLine("# GENERATED. One line per coverage item resolved by evidence -- an item resolved by"); + writer.WriteLine("# proof instead lives in semantic-coverage-proofs.tsv, never here. Columns are"); + writer.WriteLine("# explicit so CoverageCompletenessGate reads structure, never Delta's free-text prose."); + writer.WriteLine("# counterexample_kind is Word or LoadFailure and the two are never summed into one"); + writer.WriteLine("# count -- see CoverageCompletenessGate. Absent fields are \"-\"."); + writer.WriteLine( + "item_id\tkind\tfixture\texample_word\texample_outcome\tcounterexample_kind\tcounterexample_outcome\tmutation\tverdict" + ); + foreach (Row row in rows.OrderBy(r => r.ItemId, StringComparer.Ordinal)) + { + writer.WriteLine( + string.Join( + '\t', + row.ItemId, + row.Kind, + row.Fixture, + row.ExampleWord ?? NullField, + row.ExampleOutcome ?? NullField, + row.CounterexampleKind, + row.CounterexampleOutcome ?? NullField, + row.Mutation, + row.Verdict + ) + ); + } + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("item_id\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[1], out CoverageItemKind kind)) + throw new FormatException($"{RelativePath}: unknown kind '{fields[1]}' for '{fields[0]}'"); + if (!Enum.TryParse(fields[5], out CounterexampleKind counterexampleKind)) + { + throw new FormatException( + $"{RelativePath}: unknown counterexample kind '{fields[5]}' for '{fields[0]}'" + ); + } + if (!Enum.TryParse(fields[8], out CounterfactualVerdict verdict)) + throw new FormatException($"{RelativePath}: unknown verdict '{fields[8]}' for '{fields[0]}'"); + + rows.Add( + new Row( + fields[0], + kind, + fields[2], + fields[3] == NullField ? null : fields[3], + fields[4] == NullField ? null : fields[4], + counterexampleKind, + fields[6] == NullField ? null : fields[6], + fields[7], + verdict + ) + ); + } + + return rows.OrderBy(row => row.ItemId, StringComparer.Ordinal).ToArray(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/FeatureValueDisjointProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/FeatureValueDisjointProofs.cs new file mode 100644 index 000000000..3ed32fa92 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/FeatureValueDisjointProofs.cs @@ -0,0 +1,407 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind : two PhonologicalRules in +/// a Stratum phonologicalRules adjacent pair whose active subrules are gated by disjoint +/// Environment natural classes, so at most one of them can ever match a given site regardless of +/// which one runs first, AND neither rule's output segment could ever create a NEW site for the other (it +/// is not a member of the other's resolved environment or its shared input class). Both conditions are +/// recomputed fresh, never read from a file: +/// +/// (a) the union of each rule's active-subrule LeftEnvironment/RightEnvironment classes +/// does not intersect the other's; +/// (b) neither rule's PhoneticOutput segment is a member of the other's environment class OR +/// its PhoneticInput class -- the input half closes a feeding channel that environment-disjointness +/// alone misses (one rule's output creating a brand-new instance of the other's input class), resolved by +/// the same natural-class machinery for free, so it only ever rejects a proof that would otherwise be +/// wrongly certified. +/// +/// A rule with an active subrule that has NO Environment at all fires unconditionally wherever its input +/// matches; that removes the mutual-exclusion argument entirely (there is no "at most one can match a given +/// site" race to reason about), so such a pair is never modeled by this check. +/// +public static class FeatureValueDisjointProofs +{ + public const string Kind = "feature-value-disjoint"; + + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + Check check = Evaluate(grammar, item); + return check.Relation == Relation.Disjoint ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies : true only when 's freshly + /// generated adjacent pairs still contain an item with 's id AND the check + /// recomputes for it. A stale id, a recomputed environment overlap, + /// and a recomputed output-feeds-the-other overlap all fail closed to false. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return Evaluate(grammar, item).Relation == Relation.Disjoint; + } + + private enum Relation + { + Disjoint, + Overlaps, + Undetermined, + } + + private sealed record Check(string ItemId, Relation Relation, string Reason); + + private static Check Evaluate(XDocument grammar, OrderingItem item) + { + if (item.Kind != OrderingListKind.StratumPhonologicalRules) + { + return new Check( + item.Id, + Relation.Undetermined, + $"{item.Kind} pairs are not modeled -- this check only resolves a PhonologicalRule's PhoneticInput/Environment classes" + ); + } + + XElement? ruleA = FindElementById(grammar, item.MemberA); + XElement? ruleB = FindElementById(grammar, item.MemberB); + if (ruleA is null || ruleB is null) + { + string missing = ruleA is null ? item.MemberA : item.MemberB; + return new Check( + item.Id, + Relation.Undetermined, + $"'{missing}' was not found as an element with a matching id attribute" + ); + } + if (ruleA.Name.LocalName != "PhonologicalRule" || ruleB.Name.LocalName != "PhonologicalRule") + { + return new Check( + item.Id, + Relation.Undetermined, + $"<{ruleA.Name.LocalName}>/<{ruleB.Name.LocalName}> is not modeled -- only a PhonologicalRule/PhonologicalRule pair " + + "has PhoneticInput/Environment natural classes to compare" + ); + } + + RuleProfile? profileA = BuildProfile(ruleA, grammar); + if (profileA is null) + { + return new Check( + item.Id, + Relation.Undetermined, + $"'{item.MemberA}' has no active subrule with an Environment, or its natural classes could not be resolved" + ); + } + RuleProfile? profileB = BuildProfile(ruleB, grammar); + if (profileB is null) + { + return new Check( + item.Id, + Relation.Undetermined, + $"'{item.MemberB}' has no active subrule with an Environment, or its natural classes could not be resolved" + ); + } + + string[] sharedEnvironment = profileA + .Environment.Intersect(profileB.Environment, StringComparer.Ordinal) + .OrderBy(s => s, StringComparer.Ordinal) + .ToArray(); + if (sharedEnvironment.Length > 0) + { + return new Check( + item.Id, + Relation.Overlaps, + $"environment classes share segment(s) {{{string.Join(",", sharedEnvironment)}}}" + ); + } + + HashSet triggerB = profileB + .Environment.Union(profileB.Input, StringComparer.Ordinal) + .ToHashSet(StringComparer.Ordinal); + string[] aFeedsB = profileA + .Output.Intersect(triggerB, StringComparer.Ordinal) + .OrderBy(s => s, StringComparer.Ordinal) + .ToArray(); + if (aFeedsB.Length > 0) + { + return new Check( + item.Id, + Relation.Overlaps, + $"'{item.MemberA}''s output {{{string.Join(",", aFeedsB)}}} would create a new site for '{item.MemberB}'" + ); + } + + HashSet triggerA = profileA + .Environment.Union(profileA.Input, StringComparer.Ordinal) + .ToHashSet(StringComparer.Ordinal); + string[] bFeedsA = profileB + .Output.Intersect(triggerA, StringComparer.Ordinal) + .OrderBy(s => s, StringComparer.Ordinal) + .ToArray(); + if (bFeedsA.Length > 0) + { + return new Check( + item.Id, + Relation.Overlaps, + $"'{item.MemberB}''s output {{{string.Join(",", bFeedsA)}}} would create a new site for '{item.MemberA}'" + ); + } + + return new Check( + item.Id, + Relation.Disjoint, + $"'{item.MemberA}' environment {{{string.Join(",", profileA.Environment.OrderBy(s => s, StringComparer.Ordinal))}}} and " + + $"'{item.MemberB}' environment {{{string.Join(",", profileB.Environment.OrderBy(s => s, StringComparer.Ordinal))}}} are " + + "disjoint, and neither rule's output could ever create a new site for the other" + ); + } + + private sealed record RuleProfile(HashSet Input, HashSet Output, HashSet Environment); + + // Null means: no active subrule declares any Environment (so the rule fires unconditionally and the + // mutual-exclusion argument this kind depends on does not apply), or some referenced natural class + // could not be fully resolved. Both fail closed to "not modeled" rather than guessing. + private static RuleProfile? BuildProfile(XElement rule, XDocument grammar) + { + SegmentResolution input = ResolveSequenceSegments( + rule.Element("PhoneticInput")?.Element("PhoneticSequence"), + grammar + ); + if (!input.IsResolved) + return null; + + List subrules = + rule.Element("PhonologicalSubrules")?.Elements("PhonologicalSubrule").Where(IsActiveElement).ToList() + ?? new List(); + if (subrules.Count == 0) + return null; + + SegmentResolution output = SegmentResolution.Ok(Array.Empty()); + SegmentResolution environment = SegmentResolution.Ok(Array.Empty()); + bool anyEnvironment = false; + foreach (XElement subrule in subrules) + { + output = Union( + output, + ResolveSequenceSegments(subrule.Element("PhoneticOutput")?.Element("PhoneticSequence"), grammar) + ); + if (!output.IsResolved) + return null; + + XElement? env = subrule.Element("Environment"); + if (env is null) + continue; + + XElement? left = env.Element("LeftEnvironment")?.Element("PhoneticTemplate")?.Element("PhoneticSequence"); + XElement? right = env.Element("RightEnvironment")?.Element("PhoneticTemplate")?.Element("PhoneticSequence"); + if (left is not null || right is not null) + anyEnvironment = true; + + environment = Union(environment, ResolveSequenceSegments(left, grammar)); + if (!environment.IsResolved) + return null; + environment = Union(environment, ResolveSequenceSegments(right, grammar)); + if (!environment.IsResolved) + return null; + } + + if (!anyEnvironment) + return null; + + return new RuleProfile( + input.Segments.ToHashSet(StringComparer.Ordinal), + output.Segments.ToHashSet(StringComparer.Ordinal), + environment.Segments.ToHashSet(StringComparer.Ordinal) + ); + } + + private readonly record struct SegmentResolution(bool IsResolved, IReadOnlySet Segments) + { + public static SegmentResolution Ok(IEnumerable segments) => + new(true, segments.ToHashSet(StringComparer.Ordinal)); + + public static SegmentResolution No() => new(false, new HashSet()); + } + + private static SegmentResolution Union(SegmentResolution a, SegmentResolution b) + { + if (!a.IsResolved) + return a; + if (!b.IsResolved) + return b; + return SegmentResolution.Ok(a.Segments.Concat(b.Segments)); + } + + // Over-approximates on purpose (recursing into OptionalSegmentSequence too): the result is later used + // ONLY to test for intersection, and a superset can only ADD a spurious intersection, never hide a + // real one -- so it can turn a real Disjoint into a false Overlaps but never the reverse, which is the + // safe direction given this check's one forbidden mistake is a false Disjoint. + private static SegmentResolution ResolveSequenceSegments(XElement? sequence, XDocument grammar) + { + if (sequence is null) + return SegmentResolution.Ok(Array.Empty()); + + SegmentResolution acc = SegmentResolution.Ok(Array.Empty()); + foreach (XElement child in sequence.Elements()) + { + acc = Union(acc, ResolveElementSegments(child, grammar)); + if (!acc.IsResolved) + return acc; + } + return acc; + } + + private static SegmentResolution ResolveElementSegments(XElement element, XDocument grammar) + { + switch (element.Name.LocalName) + { + case "Segment": + { + string? segmentId = (string?)element.Attribute("segment"); + if (segmentId is null) + return SegmentResolution.No(); + XElement? segmentDef = FindSegmentDefinition(grammar, segmentId); + if (segmentDef is null) + return SegmentResolution.No(); + return IsActiveElement(segmentDef) + ? SegmentResolution.Ok(new[] { segmentId }) + : SegmentResolution.Ok(Array.Empty()); + } + case "SimpleContext": + { + string? naturalClassId = (string?)element.Attribute("naturalClass"); + return naturalClassId is null ? SegmentResolution.No() : ResolveNaturalClass(naturalClassId, grammar); + } + case "OptionalSegmentSequence": + { + SegmentResolution acc = SegmentResolution.Ok(Array.Empty()); + foreach (XElement child in element.Elements()) + { + acc = Union(acc, ResolveElementSegments(child, grammar)); + if (!acc.IsResolved) + return acc; + } + return acc; + } + case "BoundaryMarker": + return SegmentResolution.Ok(Array.Empty()); + default: + return SegmentResolution.No(); + } + } + + private static SegmentResolution ResolveNaturalClass(string naturalClassId, XDocument grammar) + { + XElement? segmentClass = grammar + .Descendants("SegmentNaturalClass") + .FirstOrDefault(e => (string?)e.Attribute("id") == naturalClassId); + if (segmentClass is not null) + return ResolveSegmentNaturalClass(segmentClass, grammar); + + XElement? featureClass = grammar + .Descendants("FeatureNaturalClass") + .FirstOrDefault(e => (string?)e.Attribute("id") == naturalClassId); + return featureClass is not null ? ResolveFeatureNaturalClass(featureClass, grammar) : SegmentResolution.No(); + } + + private static SegmentResolution ResolveSegmentNaturalClass(XElement segmentClass, XDocument grammar) + { + var ids = new List(); + foreach (XElement segment in segmentClass.Elements("Segment")) + { + string? segmentId = (string?)segment.Attribute("segment"); + if (segmentId is null) + return SegmentResolution.No(); + XElement? segmentDef = FindSegmentDefinition(grammar, segmentId); + if (segmentDef is null) + return SegmentResolution.No(); + if (IsActiveElement(segmentDef)) + ids.Add(segmentId); + } + return SegmentResolution.Ok(ids); + } + + private static SegmentResolution ResolveFeatureNaturalClass(XElement featureClass, XDocument grammar) + { + var constraints = new List<(string Feature, HashSet Symbols)>(); + foreach (XElement featureValue in featureClass.Elements("FeatureValue")) + { + if (!IsActiveElement(featureValue)) + continue; + if (featureValue.Elements("FeatureValue").Any()) + return SegmentResolution.No(); + + string? feature = (string?)featureValue.Attribute("feature"); + string? symbolValues = (string?)featureValue.Attribute("symbolValues"); + if (feature is null || symbolValues is null) + return SegmentResolution.No(); + constraints.Add((feature, SplitIdrefs(symbolValues).ToHashSet(StringComparer.Ordinal))); + } + + var members = new List(); + foreach (XElement segmentDef in grammar.Descendants("SegmentDefinition")) + { + if (!IsActiveElement(segmentDef)) + continue; + string? segmentId = (string?)segmentDef.Attribute("id"); + if (segmentId is null) + continue; + + bool? matches = MatchesEveryConstraint(segmentDef, constraints); + if (matches is null) + return SegmentResolution.No(); + if (matches.Value) + members.Add(segmentId); + } + return SegmentResolution.Ok(members); + } + + private static bool? MatchesEveryConstraint( + XElement segmentDef, + List<(string Feature, HashSet Symbols)> constraints + ) + { + foreach ((string feature, HashSet symbols) in constraints) + { + XElement? declared = segmentDef + .Elements("FeatureValue") + .FirstOrDefault(fv => IsActiveElement(fv) && (string?)fv.Attribute("feature") == feature); + if (declared is null) + return null; + + string? declaredSymbols = (string?)declared.Attribute("symbolValues"); + HashSet declaredSet = declaredSymbols is null + ? new HashSet(StringComparer.Ordinal) + : SplitIdrefs(declaredSymbols).ToHashSet(StringComparer.Ordinal); + if (!declaredSet.Overlaps(symbols)) + return false; + } + return true; + } + + private static string[] SplitIdrefs(string value) => + value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + + private static XElement? FindSegmentDefinition(XDocument grammar, string id) => + grammar.Descendants("SegmentDefinition").FirstOrDefault(e => (string?)e.Attribute("id") == id); + + private static XElement? FindElementById(XDocument grammar, string id) => + grammar.Descendants().FirstOrDefault(e => (string?)e.Attribute("id") == id); + + private static bool IsActiveElement(XElement element) => (string?)element.Attribute("isActive") != "no"; +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/FoldInCandidateLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/FoldInCandidateLedger.cs new file mode 100644 index 000000000..2d08e0337 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/FoldInCandidateLedger.cs @@ -0,0 +1,240 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Which obligations a language-family grammar (conformance/languages/*) could pick up by +/// growing an existing fixture, rather than by authoring a new fabricated one -- the direct input to +/// that fold-in work, not a footnote of it. Two independent layers, each keyed on WITNESS (a real +/// word-level counterfactual delta), never mere presence -- see +/// and 's own doc comments for why presence alone would overclaim here. +/// +public enum FoldInCategory +{ + /// Every fixture that witnesses this obligation is an edge-case; no language fixture + /// witnesses it, and (surface layer only) no language fixture's grammar even structurally contains + /// it, so folding it in needs new grammar content, not just new words. + EdgeCaseOnly, + + /// + /// No language fixture reaches the same verdict as the recorded evidence ('s witnessed_by column, not just EvidenceLedger's single + /// recorded fixture -- a language fixture that only TIES is still a real witness and rules this + /// category out; see ), but at least one language fixture's + /// grammar.xml already structurally contains the surface (). A + /// weaker, cheaper fold-in target: extending that language fixture's WORDS may be enough, with no + /// new grammar content required. + /// + PresentInLanguageGrammarAlready, + + /// Present somewhere in the corpus but never reaches a word-level witness anywhere -- + /// not a fold-in candidate (there is no existing evidence to relocate), but worth naming: presence + /// alone was exactly the overclaim this whole ledger set exists to stop repeating. + NeverWitnessed, +} + +/// +/// Computes for the interface layer (from +/// + ) and the unit-surface +/// layer (from + ). Cheap: every source +/// is either an already-checked-in ledger or a structural (no-reparse) grammar scan. +/// +public static class FoldInCandidateLedger +{ + public const string RelativePath = "conformance/fold-in-candidates.tsv"; + + private const int ColumnCount = 4; + + public sealed record Row(ObligationLayer Layer, string Obligation, FoldInCategory Category, string Detail); + + private const string LanguagesPrefix = "languages/"; + + private static IReadOnlyList ComputeInterfaceLayer(string repositoryRoot) + { + var rows = new List(); + IReadOnlyList witnesses = InterfaceWitnessLedger.Read(repositoryRoot); + foreach (InterfaceInventoryLedger.Row declared in InterfaceInventoryLedger.Read(repositoryRoot)) + { + if (!declared.Present) + continue; + + string obligation = $"{declared.Element}.{declared.Attribute}"; + string[] evidencedFixtures = witnesses + .Where(w => w.Element == declared.Element && w.Attribute == declared.Attribute) + .Where(w => w.Verdict == CounterfactualVerdict.Evidenced) + .Select(w => w.FixtureId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + if (evidencedFixtures.Length == 0) + { + rows.Add( + new Row( + ObligationLayer.Interface, + obligation, + FoldInCategory.NeverWitnessed, + $"present in {declared.Fixtures.Count} fixture(s), witnessed by none" + ) + ); + continue; + } + + bool onlyEdgeCases = evidencedFixtures.All(id => !id.StartsWith(LanguagesPrefix, StringComparison.Ordinal)); + if (onlyEdgeCases) + { + rows.Add( + new Row( + ObligationLayer.Interface, + obligation, + FoldInCategory.EdgeCaseOnly, + $"witnessed only by: {string.Join(",", evidencedFixtures)}" + ) + ); + } + } + + return rows; + } + + private static IReadOnlyList ComputeSurfaceLayer(string repositoryRoot) + { + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(repositoryRoot); + var languageSurfaces = new HashSet(StringComparer.Ordinal); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + if (!fixture.Id.StartsWith(LanguagesPrefix, StringComparison.Ordinal)) + continue; + XDocument grammar = XDocument.Load(fixture.GrammarPath); + foreach (string surfaceId in GrammarFeatureUsage.Read(grammar, inventory)) + languageSurfaces.Add(surfaceId); + } + + // Keyed on EVERY fixture that reached the recorded verdict, not just EvidenceLedger's single + // recorded fixture: CounterfactualLedger.Sweep keeps only the first-discovered fixture per + // surface as EvidenceLedger's row, and discovery order sorts edge-cases before languages/*, so + // a language fixture that merely TIES for the same verdict would otherwise be invisible here -- + // exactly the defect that made 21 of 30 recorded fold-in candidates wrong. + var witnessesBySurface = CounterfactualLedger + .Read(repositoryRoot) + .ToDictionary( + r => r.SurfaceId, + r => (IReadOnlyList)(r.WitnessingFixtures ?? new[] { r.FixtureId }), + StringComparer.Ordinal + ); + + var rows = new List(); + foreach (EvidenceLedger.Row item in EvidenceLedger.Read(repositoryRoot)) + { + if (item.Kind != CoverageItemKind.Surface) + continue; + if (item.Verdict is not (CounterfactualVerdict.Evidenced or CounterfactualVerdict.EvidencedJointly)) + continue; + + IReadOnlyList witnesses = witnessesBySurface.TryGetValue( + item.ItemId, + out IReadOnlyList? recorded + ) + ? recorded + : new[] { item.Fixture }; + if (witnesses.Any(fixtureId => fixtureId.StartsWith(LanguagesPrefix, StringComparison.Ordinal))) + continue; // a language grammar already reaches this same verdict; not a fold-in candidate + + bool structurallyPresentElsewhere = languageSurfaces.Contains(item.ItemId); + rows.Add( + structurallyPresentElsewhere + ? new Row( + ObligationLayer.Surface, + item.ItemId, + FoldInCategory.PresentInLanguageGrammarAlready, + $"recorded best evidence: {item.Fixture}; also structurally present in a languages/* grammar" + ) + : new Row( + ObligationLayer.Surface, + item.ItemId, + FoldInCategory.EdgeCaseOnly, + $"recorded best evidence: {item.Fixture}; no languages/* grammar contains this surface at all" + ) + ); + } + + return rows; + } + + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + return ComputeInterfaceLayer(repositoryRoot) + .Concat(ComputeSurfaceLayer(repositoryRoot)) + .OrderBy(r => r.Layer) + .ThenBy(r => r.Obligation, StringComparer.Ordinal) + .ToArray(); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine("# GENERATED by hc-conformance --write-coverage-traceability. Obligations a language-"); + writer.WriteLine("# family grammar could pick up by growing an existing fixture, keyed on WITNESS (a real"); + writer.WriteLine("# word-level counterfactual delta) never mere presence -- see FoldInCategory's own doc"); + writer.WriteLine("# comments for exactly what each category claims and does not claim."); + writer.WriteLine("# EdgeCaseOnly only a fabricated edge case witnesses this; folding"); + writer.WriteLine("# it in needs new grammar content"); + writer.WriteLine("# PresentInLanguageGrammarAlready surface layer only: a language grammar already"); + writer.WriteLine("# structurally contains it; new WORDS may be enough"); + writer.WriteLine("# NeverWitnessed interface layer only: present somewhere, witnessed"); + writer.WriteLine("# nowhere -- not a fold-in target, a named gap"); + writer.WriteLine("layer\tobligation\tcategory\tdetail"); + foreach (Row row in rows.OrderBy(r => r.Layer).ThenBy(r => r.Obligation, StringComparer.Ordinal)) + writer.WriteLine(string.Join('\t', row.Layer, row.Obligation, row.Category, row.Detail)); + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("layer\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[0], out ObligationLayer layer)) + throw new FormatException($"{RelativePath}: unknown layer '{fields[0]}'"); + if (!Enum.TryParse(fields[2], out FoldInCategory category)) + throw new FormatException($"{RelativePath}: unknown category '{fields[2]}'"); + + rows.Add(new Row(layer, fields[1], category, fields[3])); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GateObligationLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GateObligationLedger.cs new file mode 100644 index 000000000..65410785e --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GateObligationLedger.cs @@ -0,0 +1,667 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Whether a gate obligation's arm has a real, checked witness -- never a guess. +public enum GateArmStatus +{ + Evidenced, + NotEvidenced, +} + +/// +/// The checked-in denominator for MC/DC obligations keyed to -- HermitCrab's +/// OWN 23 engine decision points () -- rather than to a DTD +/// attribute pair (). +/// +/// +/// Why this ledger, and why it is primary now. enumerates +/// four MC/DC arms per writer/reader chain but can only ever CERTIFY one of them +/// (FindPairedWitness derives the satisfied arm from the reader attribute's own name: +/// required* -> AbsentGatedForm, excluded* -> PresentGatedForm, anything else -> +/// null) -- of 346 enumerated cells, 28 are even certifiable. Worse, it cannot NAME a gate the DTD fuses +/// into no single attribute at all: six of the 23 values +/// () have no row there whatsoever. This ledger +/// starts from the ENGINE's own 23 gates instead, so every one of them gets a denominator row regardless +/// of whether the schema names it with an attribute, and MC/DC's two arms per gate are evidenced with +/// the engine's own vocabulary: +/// +/// Blocked -- a word that fails, and HermitCrab's own trace tree NAMES this exact +/// somewhere in that failure, and severing the construct that feeds the +/// gate () flips that SAME word to a successful parse. This is +/// stronger evidence than 's chain pairing: the trace attributes +/// the failure to the gate directly, rather than inferring an arm from an attribute's spelling. +/// Control -- a word (in the same fixture) where the SAME grammar rule instance that fed +/// the Blocked arm's gate fires in a SUCCESSFUL parse, proving the rule can apply at all and that the +/// Blocked arm's failure is attributable to the gate rather than to a rule that never runs. Resolvable +/// when the gated construct sits directly on a rule element can name +/// (MorphologicalRule/CompoundingRule/RealizationalRule/PhonologicalRule/ +/// MetathesisRule), or on one of four child element kinds can walk up to a rule ancestor from +/// (MorphologicalInput, PhonologicalSubrule always resolve this way; Allomorph +/// and AffixTemplate never do -- neither ever has a rule ancestor, see that method's own doc +/// comment). A co-occurrence or bare slot construct has no "Applied" trace event to check against at +/// all (the same documented gap already records for allomorph +/// identity), and is reported naming exactly that limitation, +/// never guessed. +/// +/// +/// +/// +/// Every obligation also carries its two layer verdicts, so a miss says WHERE it is blocked. +/// xml_reachable is whether any DTD attribute or element reaches the gate at all (from +/// ; five of its six "-" entries are reachable +/// only via element content -- -- and one, +/// , is a pure engine-internal check no grammar construct +/// feeds at all). flex_producible is FieldWorks' own HCLoader capability +/// (conformance/fieldworks-producibility.tsv, treated as fixed -- see that file's own doc +/// comment). An obligation is worth_covering only when both are Yes: 21 of the 23 gates today +/// ( fails the first, the second). A gate that IS worth covering can +/// still be unevidenced for two further, honestly distinct reasons: the current corpus never witnesses +/// it at all (), or it is witnessed but has no DTD attribute to +/// sever (the three "-" gates that ARE reachable and producible -- , , -- for which this ledger has no isolable element-content severance +/// primitive yet). Every one of these is named in the row's own evidence text, never collapsed to a +/// single "Unknown". +/// +/// +/// +/// is kept, not superseded. It answers a genuinely +/// different question this ledger does not: whether a specific WRITER/READER PAYLOAD PAIR survives the +/// full MC/DC treatment (n-condition vectors, the four mutator-kill classes) for the 40 write/read +/// chains derives from the DTD. This ledger answers whether each of +/// the engine's 23 OWN DECISION POINTS is independently shown to matter. +/// +/// +public static class GateObligationLedger +{ + public const string RelativePath = "conformance/gate-obligations.tsv"; + + private const int ColumnCount = 9; + private const string NoValue = "-"; + private const string BlockedArm = "Blocked"; + private const string ControlArm = "Control"; + + public sealed record Row( + string Gate, + string Arm, // "Blocked" | "Control" + string XmlReachable, // "Yes" | "No" + string FlexProducible, // "Yes" | "No" + string WorthCovering, // "Yes" | "No" -- derived: XmlReachable == Yes && FlexProducible == Yes + GateArmStatus Status, + string Fixture, + string Word, + string Evidence + ); + + /// + /// The five of 's six "-" gates that are + /// still reachable from a fixture -- via child ELEMENTS (), + /// PhoneticSequence element CONTENT (//), or allomorph + /// sibling structure () -- as opposed to , a pure engine-internal reconstruction check with no + /// grammar input at all. Deliberately a fixed set, not re-derived: which of these five have an + /// isolable severance primitive built (three do not yet -- see this class's own doc comment) is a + /// tooling question, not something a fixture sweep can answer for us. + /// + private static readonly HashSet ElementContentReachableWithoutAttribute = new(StringComparer.Ordinal) + { + "Environments", + "DisjunctiveAllomorph", + "Pattern", + "HeadPattern", + "NonHeadPattern", + }; + + /// Rule elements that carry their own id attribute directly -- needs no ancestor walk to name the rule these belong to. + private static readonly HashSet RuleIndexedElements = new(StringComparer.Ordinal) + { + "MorphologicalRule", + "CompoundingRule", + "RealizationalRule", + "PhonologicalRule", + "MetathesisRule", + }; + + /// Elements with no rule id of their own that + /// can still name by walking up to the nearest rule-element ancestor. Not every instance resolves: an + /// Allomorph is always a child of LexicalEntry, never of a rule, and an AffixTemplate has no + /// id attribute of its own (the DTD never declares one) and sits under Stratum, never + /// under a rule either -- both genuinely have no rule to attribute a Control arm to. + private static readonly HashSet AncestorResolvableElements = new(StringComparer.Ordinal) + { + "Allomorph", + "MorphologicalInput", + "AffixTemplate", + "PhonologicalSubrule", + }; + + private static bool IsXmlReachable(EngineGateInventoryLedger.Row gateRow) => + gateRow.DtdAttributes != NoValue || ElementContentReachableWithoutAttribute.Contains(gateRow.Gate); + + private static string XmlUnreachableReason(string gate) => + gate == nameof(FailureReason.SurfaceFormMismatch) + ? "pure engine-internal reconstruction check (Morpher.cs's confirming-synthesis IsMatch) with no grammar attribute or element input at all -- see EngineGateInventoryLedger.DtdAttributes" + : "no DTD attribute, and not one of the five known element-content-reachable gates -- see EngineGateInventoryLedger.DtdAttributes"; + + private static string FlexUnproducibleReason(string gate) => + gate == nameof(FailureReason.ObligatorySyntacticFeatures) + ? "FieldWorks' HCLoader never sets AffixProcessRule/CompoundingRule.ObligatorySyntacticFeatures for any construct FLEx exposes -- conformance/fieldworks-producibility.tsv" + : "conformance/fieldworks-producibility.tsv records this construct as not producible by FieldWorks' HCLoader"; + + /// failure-reason subject -> producible == "Yes", read straight from the hand-verified, + /// checked-in ledger this class treats as fixed (see that file's own doc comment). + private static IReadOnlyDictionary ReadFlexProducibility(string repositoryRoot) + { + string path = Path.Combine(repositoryRoot, "conformance", "fieldworks-producibility.tsv"); + if (!File.Exists(path)) + { + throw new InvalidOperationException( + "conformance/fieldworks-producibility.tsv is missing; GateObligationLedger needs it to compute flex_producible" + ); + } + + var result = new Dictionary(StringComparer.Ordinal); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("subject_kind\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length < 3 || fields[0] != "failure-reason") + continue; + result[fields[1]] = fields[2] == "Yes"; + } + return result; + } + + // ---------------------------------------------------------------------------------------- + // Per-fixture baseline: one traced parse per word, shared by every gate that touches this + // fixture, so a corpus-wide sweep costs one traced pass per fixture, not one per (gate, fixture). + // ---------------------------------------------------------------------------------------- + + private sealed record WordBaseline( + bool Succeeded, + IReadOnlySet ObservedGates, + IReadOnlySet FiredRuleIds + ); + + private static void WalkFailureReasons(Trace node, HashSet gates) + { + if (node.FailureReason != FailureReason.None) + gates.Add(node.FailureReason.ToString()); + foreach (Trace child in node.Children) + WalkFailureReasons(child, gates); + } + + private static IReadOnlyDictionary BuildWordBaselines(Fixture fixture) + { + var byWord = new Dictionary(StringComparer.Ordinal); + + Language language; + try + { + language = XmlLanguageLoader.Load(fixture.GrammarPath); + } + catch + { + return byWord; + } + + GrammarRuleIndex ruleIndex = GrammarRuleIndex.Load(fixture.GrammarPath); + var morpher = new Morpher(new TraceManager { IsTracing = true }, language); + + foreach (WordEntry entry in fixture.Words.Words) + { + bool guessRoot = entry.Parses.Any(p => p.Guess); + List results; + object? trace; + try + { + results = morpher.ParseWord(entry.Word, out trace, guessRoot).ToList(); + } + catch + { + // Mirrors EngineGateWitnessSweep: a word the engine cannot even trace evidences nothing. + continue; + } + + var observedGates = new HashSet(StringComparer.Ordinal); + if (trace is Trace root) + WalkFailureReasons(root, observedGates); + + var firedRuleIds = new HashSet(StringComparer.Ordinal); + foreach (Word result in results) + { + foreach (string id in TraceRuleAttributor.MorphologicalRuleIds(result, ruleIndex)) + firedRuleIds.Add(id); + } + if (trace is not null) + { + foreach (string id in TraceRuleAttributor.WordLevelRuleIds(trace, ruleIndex)) + firedRuleIds.Add(id); + } + + byWord[entry.Word] = new WordBaseline(results.Count > 0, observedGates, firedRuleIds); + } + + return byWord; + } + + // ---------------------------------------------------------------------------------------- + // Compute + // ---------------------------------------------------------------------------------------- + + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + + IReadOnlyList gateRows = EngineGateInventoryLedger.Read(repositoryRoot); + if (gateRows.Count == 0) + { + throw new InvalidOperationException( + $"{EngineGateInventoryLedger.RelativePath} is missing or empty; regenerate it first with --write-engine-gate-inventory" + ); + } + + IReadOnlyDictionary flexProducible = ReadFlexProducibility(repositoryRoot); + + Dictionary fixturesById = Fixture + .DiscoverAll(Path.Combine(repositoryRoot, "conformance")) + .ToDictionary(f => f.Id, StringComparer.Ordinal); + + var witnessByKey = new Dictionary<(string Element, string Attribute, string Fixture), InterfaceWitnessResult>(); + foreach (InterfaceWitnessResult w in InterfaceWitnessLedger.Read(repositoryRoot)) + witnessByKey[(w.Element, w.Attribute, w.FixtureId)] = w; + + SemanticInventory? inventoryCache = null; + SemanticInventory GetInventory() => inventoryCache ??= GrammarCoverageGate.ReadInventory(repositoryRoot); + + var wordBaselineCache = new Dictionary>( + StringComparer.Ordinal + ); + var plainBaselineCache = new Dictionary>(StringComparer.Ordinal); + string scratch = Path.Combine(Path.GetTempPath(), "hc-gate-obligations"); + + IReadOnlyDictionary GetWordBaselines(string fixtureId) + { + if (wordBaselineCache.TryGetValue(fixtureId, out IReadOnlyDictionary? cached)) + return cached; + cached = fixturesById.TryGetValue(fixtureId, out Fixture? fx) + ? BuildWordBaselines(fx) + : new Dictionary(StringComparer.Ordinal); + wordBaselineCache[fixtureId] = cached; + return cached; + } + + // Reuses conformance/interface-witness.tsv's already-computed severance where it exists (every + // IDREF/IDREFS attribute); falls back to a fresh InterfaceWitnessGate.Evaluate run only for the + // boolean/non-IDREF attributes that ledger's own scope (InterfaceInventoryLedger) never covers + // (Allomorph.isBound, Slot.optional, AffixTemplate.final, MorphologicalRule.partial, + // *.multipleApplication). + InterfaceWitnessResult? GetSeveranceResult(string element, string attribute, string fixtureId) + { + if (witnessByKey.TryGetValue((element, attribute, fixtureId), out InterfaceWitnessResult? cached)) + return cached; + if (!fixturesById.TryGetValue(fixtureId, out Fixture? fixture)) + return null; + + if (!plainBaselineCache.TryGetValue(fixtureId, out IReadOnlyList? cachedBaseline)) + { + try + { + cachedBaseline = CounterfactualGate.EvaluateWithTimeout( + fixture.GrammarPath, + fixture.Words.Words.Select(w => w.Word).ToArray() + ); + } + catch (Exception) + { + // A fixture whose own unmutated baseline cannot be evaluated evidences nothing for + // any gate; the caller's loop simply moves on to the next fixture/attribute. + return null; + } + plainBaselineCache[fixtureId] = cachedBaseline; + } + + return InterfaceWitnessGate.Evaluate(fixture, element, attribute, GetInventory(), cachedBaseline!, scratch); + } + + var rows = new List(); + foreach (FailureReason reason in Enum.GetValues()) + { + if (reason == FailureReason.None) + continue; + + string gate = reason.ToString(); + EngineGateInventoryLedger.Row gateRow = + gateRows.FirstOrDefault(r => r.Gate == gate) + ?? throw new InvalidOperationException( + $"{EngineGateInventoryLedger.RelativePath} has no row for {gate}" + ); + + bool xmlReachable = IsXmlReachable(gateRow); + bool flex = flexProducible.TryGetValue(gate, out bool producible) && producible; + bool worthCovering = xmlReachable && flex; + + (ArmResult blocked, ArmResult control) = EvaluateGate( + gateRow, + xmlReachable, + worthCovering, + GetWordBaselines, + GetSeveranceResult, + fixturesById + ); + + rows.Add( + new Row( + gate, + BlockedArm, + YesNo(xmlReachable), + YesNo(flex), + YesNo(worthCovering), + blocked.Status, + blocked.Fixture, + blocked.Word, + blocked.Evidence + ) + ); + rows.Add( + new Row( + gate, + ControlArm, + YesNo(xmlReachable), + YesNo(flex), + YesNo(worthCovering), + control.Status, + control.Fixture, + control.Word, + control.Evidence + ) + ); + } + + return Sort(rows); + } + + private static string YesNo(bool value) => value ? "Yes" : "No"; + + private sealed record ArmResult(GateArmStatus Status, string Fixture, string Word, string Evidence); + + private static ArmResult NotEvidencedArm(string reason) => + new(GateArmStatus.NotEvidenced, NoValue, NoValue, reason); + + private static (ArmResult Blocked, ArmResult Control) BothNotEvidenced(string reason) => + (NotEvidencedArm(reason), NotEvidencedArm(reason)); + + private static (ArmResult Blocked, ArmResult Control) EvaluateGate( + EngineGateInventoryLedger.Row gateRow, + bool xmlReachable, + bool worthCovering, + Func> getWordBaselines, + Func getSeverance, + IReadOnlyDictionary fixturesById + ) + { + if (!worthCovering) + { + return BothNotEvidenced( + !xmlReachable + ? $"not worth covering: xml_reachable=No -- {XmlUnreachableReason(gateRow.Gate)}" + : $"not worth covering: flex_producible=No -- {FlexUnproducibleReason(gateRow.Gate)}" + ); + } + + if (gateRow.Status == EngineGateStatus.Unreached) + { + return BothNotEvidenced( + "gate never witnessed by any fixture in the current corpus (conformance/engine-gate-inventory.tsv: status=Unreached) -- no candidate word exists to evidence either arm" + ); + } + + if (gateRow.DtdAttributes == NoValue) + { + return BothNotEvidenced( + "xml_reachable=Yes via element content, not an attribute -- no isolable severance primitive exists in this ledger for a bare element-content construct yet (conformance/docs/how-it-is-computed.md's gate-obligations section)" + ); + } + + (string Element, string Attribute)[] attributePairs = gateRow + .DtdAttributes.Split(';') + .Select(pair => pair.Split('.')) + .Where(parts => parts.Length == 2) + .Select(parts => (parts[0], parts[1])) + .ToArray(); + + string[] fixtureIds = + gateRow.TriggeredByFixtures == NoValue ? Array.Empty() : gateRow.TriggeredByFixtures.Split(';'); + + foreach (string fixtureId in fixtureIds) + { + IReadOnlyDictionary baselines = getWordBaselines(fixtureId); + foreach ((string element, string attribute) in attributePairs) + { + InterfaceWitnessResult? severance = getSeverance(element, attribute, fixtureId); + if (severance is null || severance.Verdict != CounterfactualVerdict.Evidenced) + continue; + if (!DataflowObligationLedger.IsFailOutcome(severance.ExampleOutcome)) + continue; + if (DataflowObligationLedger.IsFailOutcome(severance.CounterexampleOutcome)) + continue; + + string? candidateWord = severance.ExampleWord; + if ( + candidateWord is null + || !baselines.TryGetValue(candidateWord, out WordBaseline? wb) + || wb.Succeeded + || !wb.ObservedGates.Contains(gateRow.Gate) + ) + { + continue; + } + + var blocked = new ArmResult( + GateArmStatus.Evidenced, + fixtureId, + candidateWord, + $"severing {element}.{attribute} in {fixtureId} flips '{candidateWord}' from " + + $"{severance.ExampleOutcome} to {severance.CounterexampleOutcome} (conformance/interface-witness.tsv " + + $"or a fresh equivalent severance run), and '{candidateWord}''s own baseline trace names " + + $"{gateRow.Gate} directly (this ledger's own traced sweep)" + ); + ArmResult control = EvaluateControl(element, attribute, fixtureId, fixturesById, baselines); + return (blocked, control); + } + } + + string attributeList = string.Join(", ", attributePairs.Select(p => $"{p.Element}.{p.Attribute}")); + string fixtureList = string.Join(", ", fixtureIds); + string blockedReason = + fixtureIds.Length == 0 + ? "no triggering fixture recorded for this gate in conformance/engine-gate-inventory.tsv" + : $"no severance of {{{attributeList}}} across {{{fixtureList}}} produced a same-word fail-to-pass flip " + + $"whose baseline trace also names {gateRow.Gate} -- the gate may only fire as noise against a " + + "candidate unrelated to the word's final result (see FailureRuleAttributor's own doc comment)"; + return ( + NotEvidencedArm(blockedReason), + NotEvidencedArm( + "Blocked arm unevidenced; Control arm requires a confirmed blocking instance to identify which rule to check" + ) + ); + } + + private static ArmResult EvaluateControl( + string element, + string attribute, + string fixtureId, + IReadOnlyDictionary fixturesById, + IReadOnlyDictionary baselines + ) + { + bool ancestorResolvable = AncestorResolvableElements.Contains(element); + if (!RuleIndexedElements.Contains(element) && !ancestorResolvable) + { + return NotEvidencedArm( + $"{element} is not a rule element GrammarRuleIndex resolves to a fired-rule id, directly or by " + + "ancestor -- co-occurrence and template/slot constructs have no \"Applied\" trace event to " + + "check against (the same gap FailureRuleAttributor's own doc comment records for allomorph identity)" + ); + } + + if (!fixturesById.TryGetValue(fixtureId, out Fixture? fixture)) + return NotEvidencedArm($"fixture {fixtureId} could not be reloaded to resolve a rule id"); + + string? ruleId = null; + try + { + XDocument doc = XDocument.Load(fixture.GrammarPath); + XElement? instance = doc.Descendants(element) + .FirstOrDefault(e => !string.IsNullOrEmpty((string?)e.Attribute(attribute))); + if (instance is not null) + { + ruleId = ancestorResolvable + ? GrammarRuleIndex.ResolveAncestorRuleId(instance) + : (string?)instance.Attribute("id"); + } + } + catch + { + // ruleId stays null; handled by the check below. + } + + if (ruleId is null) + { + string reason = ancestorResolvable + ? $"the {element} instance carrying {attribute} in {fixtureId} has no rule-element ancestor " + + "GrammarRuleIndex can resolve (conformance/docs/severance-mechanics.md) -- it sits outside " + + "any rule, so no rule id exists to attribute a Control arm to" + : $"the {element} instance carrying {attribute} in {fixtureId} has no XML id attribute; rule-id attribution not possible"; + return NotEvidencedArm(reason); + } + + foreach ((string word, WordBaseline wb) in baselines) + { + if (wb.Succeeded && wb.FiredRuleIds.Contains(ruleId)) + { + return new ArmResult( + GateArmStatus.Evidenced, + fixtureId, + word, + $"rule '{ruleId}' ({element}) also fires in a successful parse of '{word}' in {fixtureId} " + + "(TraceRuleAttributor over this ledger's own baseline sweep), proving it can apply outside the blocked condition" + ); + } + } + + return NotEvidencedArm( + $"rule '{ruleId}' ({element}) never fires in any successful parse within {fixtureId} -- cannot confirm the rule applies at all outside the blocked condition" + ); + } + + private static IReadOnlyList Sort(IEnumerable rows) => + rows.OrderBy(r => r.Gate, StringComparer.Ordinal).ThenBy(r => r.Arm, StringComparer.Ordinal).ToArray(); + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine("# GENERATED by hc-conformance --write-gate-obligations. One row per (gate, arm) pair, gate"); + writer.WriteLine( + "# ranging over all 23 SIL.Machine.Morphology.HermitCrab.FailureReason members (excluding None)" + ); + writer.WriteLine("# and arm in {Blocked, Control} -- the two arms MC/DC demands for each of the engine's own"); + writer.WriteLine("# decision points, as opposed to conformance/dataflow-obligations.tsv's DTD-attribute-pair"); + writer.WriteLine( + "# denominator (kept, not superseded -- see conformance/docs/how-it-is-computed.md). xml_reachable" + ); + writer.WriteLine("# and flex_producible are the two layer verdicts a gate must clear to be worth_covering;"); + writer.WriteLine( + "# status is Evidenced only for a same-word severance flip whose baseline trace names the gate" + ); + writer.WriteLine( + "# directly (Blocked) or a same-fixture rule-id match proving the gated rule fires successfully" + ); + writer.WriteLine( + "# elsewhere (Control); evidence always names which layer or mechanism blocks an unevidenced cell" + ); + writer.WriteLine("# rather than collapsing to a bare \"Unknown\"."); + writer.WriteLine("gate\tarm\txml_reachable\tflex_producible\tworth_covering\tstatus\tfixture\tword\tevidence"); + foreach (Row row in Sort(rows)) + { + writer.WriteLine( + string.Join( + '\t', + row.Gate, + row.Arm, + row.XmlReachable, + row.FlexProducible, + row.WorthCovering, + row.Status, + row.Fixture, + row.Word, + row.Evidence + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("gate\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[5], out GateArmStatus status)) + throw new FormatException($"{RelativePath}: unknown status '{fields[5]}'"); + + rows.Add( + new Row(fields[0], fields[1], fields[2], fields[3], fields[4], status, fields[6], fields[7], fields[8]) + ); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarCoverageGate.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarCoverageGate.cs new file mode 100644 index 000000000..48ba314cb --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarCoverageGate.cs @@ -0,0 +1,368 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +public sealed record GrammarCoverageResult( + IReadOnlyList Observable, + IReadOnlyList Covered, + IReadOnlyList Uncovered, + IReadOnlyDictionary> FixturesBySurface +); + +/// +/// Recomputes which grammar-observable surfaces the checked-in fixtures exercise and compares the +/// uncovered set to a baseline file. Coverage is read from each grammar document rather than +/// declared by hand, so a fixture cannot claim a surface it does not contain. +/// +public static class GrammarCoverageGate +{ + public const string BaselineRelativePath = "conformance/semantic-coverage-baseline.txt"; + + /// The published copy of the grammar DTD, under conformance/. + /// A consumer can receive conformance/ alone, sparse-checked-out with no other + /// part of this repository present, so the authority a published product names has to live inside + /// it. The library's + /// own copy stays where it is because it is an embedded resource + /// (SIL.Machine.Morphology.HermitCrab.HermitCrabInput.dtd) that + /// XmlLanguageLoader reads by manifest name; the two are held byte-identical by + /// PublishedDtdMatchesTheLibraryResource. + public const string DtdRelativePath = "conformance/HermitCrabInput.dtd"; + + /// The library's embedded copy, authoritative for the shipped assembly. + public const string LibraryDtdRelativePath = "src/SIL.Machine.Morphology.HermitCrab/HermitCrabInput.dtd"; + + public static SemanticInventory ReadInventory(string repositoryRoot) => + SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd( + "HermitCrabInput.dtd", + File.ReadAllText( + Path.Combine(repositoryRoot, DtdRelativePath.Replace('/', Path.DirectorySeparatorChar)) + ) + ) + ); + + /// Every fixture grammar under conformance/, keyed by its directory name. + public static IReadOnlyList<(string FixtureId, string GrammarPath)> DiscoverGrammars(string repositoryRoot) + { + string conformance = Path.Combine(repositoryRoot, "conformance"); + if (!Directory.Exists(conformance)) + return Array.Empty<(string, string)>(); + return Directory + .GetFiles(conformance, "grammar.xml", SearchOption.AllDirectories) + .Select(path => (FixtureId: FixtureIdFor(path), GrammarPath: path)) + .OrderBy(item => item.FixtureId, StringComparer.Ordinal) + .ToArray(); + } + + /// + /// Grades every covered surface by the strongest evidence any fixture offers for it, using each + /// fixture's verified fired-rule lists. Trace strength means a parse was attributed to the rule + /// that owns the construct; presence means the construct was declared and never exercised. + /// + public static IReadOnlyList GradeEvidence(string repositoryRoot, SemanticInventory inventory) + { + ArgumentNullException.ThrowIfNull(inventory); + var best = new Dictionary(StringComparer.Ordinal); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + var fired = new HashSet(StringComparer.Ordinal); + bool hasVerifiedParse = false; + var neutralized = new HashSet(StringComparer.Ordinal); + + // A fixture CI never validates cannot supply trace data. budget_ms fixtures are excluded + // from every default run, and an expect_crash fixture passes on any exception with no word + // results at all, so neither one's rules: lists are ever compared against a real trace. + // They are still GRADED, at presence: skipping them outright let their surfaces escape the + // presence gate instead of failing it. + bool validated = fixture.Words.BudgetMs is null && !fixture.Words.ExpectCrash; + + foreach ( + WordEntry word in validated ? (IEnumerable)fixture.Words.Words : Array.Empty() + ) + { + foreach (string declarationId in word.Neutralizes) + neutralized.Add(declarationId); + + // blocked_by is deliberately NOT folded in. Runner verifies each parse's rules list + // against the trace by set equality, but an expect_fail word returns before that + // check, so blocked_by is an author's assertion no engine run confirms. + foreach (ParseEntry parse in word.Parses) + { + hasVerifiedParse = true; + foreach (string ruleId in parse.Rules) + fired.Add(ruleId); + } + } + + foreach ( + SurfaceEvidence evidence in TraceEvidence.Grade( + fixture.Id, + XDocument.Load(fixture.GrammarPath), + inventory, + fired, + hasVerifiedParse, + neutralized + ) + ) + { + if ( + best.TryGetValue(evidence.SurfaceId, out SurfaceEvidence? existing) + && existing.Strength >= evidence.Strength + ) + { + continue; + } + best[evidence.SurfaceId] = evidence; + } + } + + return best.Values.OrderBy(item => item.SurfaceId, StringComparer.Ordinal).ToArray(); + } + + /// Matches Fixture.Id (category/name), so the two discovery paths cannot collide. + private static string FixtureIdFor(string grammarPath) + { + string? dir = Path.GetDirectoryName(grammarPath); + string name = Path.GetFileName(dir) ?? grammarPath; + string? category = Path.GetFileName(Path.GetDirectoryName(dir)); + return string.IsNullOrEmpty(category) ? name : $"{category}/{name}"; + } + + public static GrammarCoverageResult Compute(string repositoryRoot, SemanticInventory inventory) + { + ArgumentNullException.ThrowIfNull(inventory); + var observable = GrammarFeatureUsage.Observable(inventory).ToHashSet(StringComparer.Ordinal); + var fixturesBySurface = new SortedDictionary>(StringComparer.Ordinal); + foreach ((string fixtureId, string grammarPath) in DiscoverGrammars(repositoryRoot)) + { + foreach (string surfaceId in GrammarFeatureUsage.Read(XDocument.Load(grammarPath), inventory)) + { + if (!fixturesBySurface.TryGetValue(surfaceId, out List? fixtures)) + { + fixtures = new List(); + fixturesBySurface[surfaceId] = fixtures; + } + + if (!fixtures.Contains(fixtureId, StringComparer.Ordinal)) + fixtures.Add(fixtureId); + } + } + + string[] covered = fixturesBySurface + .Keys.Where(observable.Contains) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] uncovered = observable + .Except(covered, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + return new GrammarCoverageResult( + observable.OrderBy(id => id, StringComparer.Ordinal).ToArray(), + covered, + uncovered, + fixturesBySurface.ToDictionary( + pair => pair.Key, + pair => (IReadOnlyList)pair.Value.OrderBy(id => id, StringComparer.Ordinal).ToArray(), + StringComparer.Ordinal + ) + ); + } + + /// Schema the implementation never consumes; no grammar can cover it. + public const string DeadSchema = "dead-schema"; + + /// Coverable by a fixture that nobody has written yet. + public const string Todo = "todo"; + + /// + /// One value of an enumerated alphabet whose mechanism a sibling value already covers, such as + /// the Greek letter naming a phonological variable. Declaring the remaining letters in a grammar + /// exercises no further behaviour, so they are quotiented rather than padded for. Valid only + /// while a sibling IS covered, which the gate checks. + /// + public const string AlphabetQuotient = "alphabet-quotient"; + + /// + /// An enumerated value identical to its attribute's DTD default. The loader reads the grammar with + /// ValidationType.DTD, so the parser supplies that value for EVERY document; a fixture that writes + /// it and one that omits it are indistinguishable, and no word can discriminate them. Recomputed + /// from the inventory's own attribute-default surface, never trusted from the ledger. + /// + public const string DtdDefault = "dtd-default"; + + public sealed record LedgerEntry(string SurfaceId, string Classification); + + /// Whether an enumerated surface's value is that attribute's declared DTD default. + public static bool IsDtdDefault(string surfaceId, IReadOnlySet declaredSurfaces) + { + ArgumentNullException.ThrowIfNull(surfaceId); + ArgumentNullException.ThrowIfNull(declaredSurfaces); + if (!surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + return false; + string rest = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..]; + string[] parts = rest.Split('/'); + if (parts.Length != 3) + return false; + return declaredSurfaces.Contains($"dtd:attribute-default/{parts[0]}/{parts[1]}/default/{parts[2]}"); + } + + /// The dtd:enum/Element/attribute prefix an enumerated value belongs to. + public static string? EnumeratedAttribute(string surfaceId) + { + ArgumentNullException.ThrowIfNull(surfaceId); + if (!surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + return null; + int lastSlash = surfaceId.LastIndexOf('/'); + return lastSlash <= GrammarFeatureUsage.EnumPrefix.Length ? null : surfaceId[..lastSlash]; + } + + /// + /// Quotient lines whose attribute has no covered sibling. Such a line claims a mechanism is + /// exercised elsewhere when nothing exercises it, so it is a real gap wearing a waiver. + /// + public static IReadOnlyList UnbackedQuotients( + IReadOnlyList ledger, + IReadOnlyList covered + ) + { + ArgumentNullException.ThrowIfNull(ledger); + ArgumentNullException.ThrowIfNull(covered); + var coveredAttributes = covered + .Select(EnumeratedAttribute) + .Where(prefix => prefix is not null) + .ToHashSet(StringComparer.Ordinal)!; + return ledger + .Where(entry => entry.Classification == AlphabetQuotient) + .Where(entry => + { + string? attribute = EnumeratedAttribute(entry.SurfaceId); + return attribute is null || !coveredAttributes.Contains(attribute); + }) + .Select(entry => entry.SurfaceId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + } + + public const string PresenceWaiverRelativePath = "conformance/semantic-coverage-presence-waivers.txt"; + + /// + /// Surfaces knowingly counted as covered on presence alone. Read from a file so the CLI and the + /// test suite gate on the same list rather than each carrying its own copy. + /// + public static IReadOnlyList ReadPresenceWaivers(string repositoryRoot) => + ReadListFile( + Path.Combine(repositoryRoot, PresenceWaiverRelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + private static IReadOnlyList ReadListFile(string path) => + File.ReadAllLines(path) + .Select(line => line.Trim()) + .Where(line => line.Length != 0 && !line.StartsWith("#", StringComparison.Ordinal)) + .OrderBy(line => line, StringComparer.Ordinal) + .ToArray(); + + public static IReadOnlyList ReadBaseline(string repositoryRoot) + { + string path = Path.Combine(repositoryRoot, BaselineRelativePath.Replace('/', Path.DirectorySeparatorChar)); + var entries = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + continue; + string[] fields = line.Split('\t', StringSplitOptions.RemoveEmptyEntries); + if (fields.Length < 2) + { + throw new FormatException( + $"{BaselineRelativePath}: '{line}' must be ''" + ); + } + string classification = fields[1].Trim(); + if (classification is not (DeadSchema or Todo or AlphabetQuotient or DtdDefault)) + { + throw new FormatException( + $"{BaselineRelativePath}: unknown classification '{classification}' for '{fields[0]}'" + ); + } + entries.Add(new LedgerEntry(fields[0].Trim(), classification)); + } + + return entries.OrderBy(entry => entry.SurfaceId, StringComparer.Ordinal).ToArray(); + } + + /// + /// Classifies each uncovered surface by whether the engine references its owning element, so the + /// justification is recomputed rather than trusted. + /// + /// + /// Reclassifies the uncovered set. Dead schema is always recomputed from the engine source; an + /// existing alphabet-quotient decision is human judgement and is carried forward, still subject + /// to . + /// + public static IReadOnlyList Classify( + string repositoryRoot, + IReadOnlyList uncovered, + IReadOnlyList existing + ) + { + ArgumentNullException.ThrowIfNull(existing); + var quotiented = existing + .Where(entry => entry.Classification == AlphabetQuotient) + .Select(entry => entry.SurfaceId) + .ToHashSet(StringComparer.Ordinal); + return Classify(repositoryRoot, uncovered) + .Select(entry => + entry.Classification == Todo && quotiented.Contains(entry.SurfaceId) + ? entry with + { + Classification = AlphabetQuotient, + } + : entry + ) + .ToArray(); + } + + public static IReadOnlyList Classify(string repositoryRoot, IReadOnlyList uncovered) + { + var elements = uncovered + .Select(DeadSchemaDetector.OwningElement) + .Where(name => name is not null) + .Select(name => name!) + .ToArray(); + IReadOnlySet unreferenced = DeadSchemaDetector.FindUnreferenced(repositoryRoot, elements); + IReadOnlySet declared = ReadInventory(repositoryRoot) + .Surfaces.Select(surface => surface.Id) + .ToHashSet(StringComparer.Ordinal); + return uncovered + .OrderBy(id => id, StringComparer.Ordinal) + .Select(id => + { + string? owner = DeadSchemaDetector.OwningElement(id); + if (owner is not null && unreferenced.Contains(owner)) + return new LedgerEntry(id, DeadSchema); + return new LedgerEntry(id, IsDtdDefault(id, declared) ? DtdDefault : Todo); + }) + .ToArray(); + } + + /// Rewrites the ledger in place, preserving its comment header. + public static void WriteBaseline(string repositoryRoot, IReadOnlyList entries) + { + string path = Path.Combine(repositoryRoot, BaselineRelativePath.Replace('/', Path.DirectorySeparatorChar)); + string[] header = File.ReadAllLines(path) + .TakeWhile(line => line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + .ToArray(); + var text = new StringBuilder(); + foreach (string line in header) + text.Append(line).Append('\n'); + foreach (LedgerEntry entry in entries.OrderBy(item => item.SurfaceId, StringComparer.Ordinal)) + text.Append(entry.SurfaceId).Append('\t').Append(entry.Classification).Append('\n'); + File.WriteAllText(path, text.ToString()); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarCoverageLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarCoverageLedger.cs new file mode 100644 index 000000000..743189d97 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarCoverageLedger.cs @@ -0,0 +1,225 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Which of the three layers reports an obligation from. +/// A fourth layer -- chains/junctions -- is out of scope here; it is owned by a separate generator +/// (conformance/interaction-chains.tsv). +public enum ObligationLayer +{ + Surface, + Interface, + Construct, +} + +/// +/// Per-fixture rollup: for each of the 33 fixtures, which obligations it witnesses, joined from the +/// three already-checked-in ledgers rather than recomputed -- (unit +/// surfaces), + (interface +/// edges), and (the coarse, self-reported constructs). +/// Deliberately cheap: every source it reads is already a file on disk, so this answers "what would I +/// lose if I deleted this fixture" without a single re-parse of its own -- the expensive part +/// (severance sweeps) already happened when those ledgers were generated. +/// +public static class GrammarCoverageLedger +{ + public const string RelativePath = "conformance/grammar-coverage-ledger.tsv"; + + private const int ColumnCount = 5; + + public sealed record Row(string Fixture, ObligationLayer Layer, string Obligation, string Status, string Detail); + + private static string SurfaceStatus(CounterfactualVerdict verdict) => + verdict switch + { + CounterfactualVerdict.Evidenced or CounterfactualVerdict.EvidencedJointly => "witnessed", + CounterfactualVerdict.RequiredByLoader => "required-by-loader", + CounterfactualVerdict.RequiredByDtd => "required-by-dtd", + CounterfactualVerdict.Timeout => "timeout", + _ => "unobservable", + }; + + private static string InterfaceStatus(CounterfactualVerdict verdict) => + verdict switch + { + CounterfactualVerdict.Evidenced => "witnessed", + CounterfactualVerdict.RequiredByLoader => "required-by-loader", + CounterfactualVerdict.RequiredByDtd => "required-by-dtd", + CounterfactualVerdict.Timeout => "timeout", + _ => "present-but-inert", + }; + + private static string ConstructStatus(ConstructClaimStatus status) => + status switch + { + ConstructClaimStatus.Confirmed => "claimed-confirmed", + ConstructClaimStatus.Contradicted => "claimed-contradicted", + _ => "claimed-unmapped", + }; + + // Badness order for rolling several claims of the same (fixture, construct) up into one status: + // a single Contradicted sibling is a real problem even if nine others are Confirmed, and an + // Unmapped sibling is a weaker, more neutral gap than either -- neither is ConstructClaimStatus's + // own declaration order (Confirmed, Contradicted, Unmapped), so this cannot be a bare Min(). + private static int Badness(ConstructClaimStatus status) => + status switch + { + ConstructClaimStatus.Contradicted => 0, + ConstructClaimStatus.Unmapped => 1, + _ => 2, + }; + + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + var rows = new List(); + + foreach (EvidenceLedger.Row item in EvidenceLedger.Read(repositoryRoot)) + { + if (item.Kind != CoverageItemKind.Surface) + continue; + rows.Add( + new Row( + item.Fixture, + ObligationLayer.Surface, + item.ItemId, + SurfaceStatus(item.Verdict), + $"{item.Verdict}" + ) + ); + } + + var witnessByKey = InterfaceWitnessLedger + .Read(repositoryRoot) + .ToDictionary(w => (w.Element, w.Attribute, w.FixtureId), w => w); + foreach (InterfaceInventoryLedger.Row declared in InterfaceInventoryLedger.Read(repositoryRoot)) + { + if (!declared.Present) + continue; + foreach (string fixtureId in declared.Fixtures) + { + string obligation = $"{declared.Element}.{declared.Attribute}"; + if ( + witnessByKey.TryGetValue( + (declared.Element, declared.Attribute, fixtureId), + out InterfaceWitnessResult? witness + ) + ) + { + rows.Add( + new Row( + fixtureId, + ObligationLayer.Interface, + obligation, + InterfaceStatus(witness.Verdict), + $"{witness.Verdict}" + ) + ); + } + else + { + rows.Add( + new Row(fixtureId, ObligationLayer.Interface, obligation, "witness-not-yet-computed", "-") + ); + } + } + } + + foreach ( + var group in ConstructClaimCorroboration + .Read(repositoryRoot) + .GroupBy(claim => (claim.Fixture, claim.Construct)) + ) + { + // A construct can be claimed by several words in the same fixture; the fixture-level fact + // (does the grammar contain what the text names) is the same for all of them, so the worst + // status among the group is the honest one -- one contradicted claim is a real problem even + // if nine siblings are confirmed for the identical construct. + ConstructClaimStatus worst = group.OrderBy(claim => Badness(claim.Status)).First().Status; + rows.Add( + new Row( + group.Key.Fixture, + ObligationLayer.Construct, + group.Key.Construct, + ConstructStatus(worst), + $"{group.Count()} claim(s)" + ) + ); + } + + return rows.OrderBy(r => r.Fixture, StringComparer.Ordinal) + .ThenBy(r => r.Layer) + .ThenBy(r => r.Obligation, StringComparer.Ordinal) + .ToArray(); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine("# GENERATED by hc-conformance --write-coverage-traceability. One row per (fixture,"); + writer.WriteLine("# obligation) pair this fixture witnesses, joined from three already-checked-in ledgers --"); + writer.WriteLine("# never recomputed here, so this file costs no re-parse of its own. layer is Surface"); + writer.WriteLine("# (semantic-coverage-evidence.tsv), Interface (interface-inventory.tsv +"); + writer.WriteLine("# interface-witness.tsv), or Construct (construct-claim-corroboration.tsv); the chain/"); + writer.WriteLine("# junction layer is out of scope (owned by interaction-chains.tsv's own generator)."); + writer.WriteLine("# status vocabulary differs per layer -- see GrammarCoverageLedger's *Status methods --"); + writer.WriteLine("# but 'witnessed' always means the same thing: a word-level counterfactual delta, never"); + writer.WriteLine("# mere presence. detail carries the underlying verdict/claim-count for that reason."); + writer.WriteLine("fixture\tlayer\tobligation\tstatus\tdetail"); + foreach ( + Row row in rows.OrderBy(r => r.Fixture, StringComparer.Ordinal) + .ThenBy(r => r.Layer) + .ThenBy(r => r.Obligation, StringComparer.Ordinal) + ) + { + writer.WriteLine(string.Join('\t', row.Fixture, row.Layer, row.Obligation, row.Status, row.Detail)); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("fixture\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[1], out ObligationLayer layer)) + throw new FormatException($"{RelativePath}: unknown layer '{fields[1]}'"); + + rows.Add(new Row(fields[0], layer, fields[2], fields[3], fields[4])); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarFeatureUsage.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarFeatureUsage.cs new file mode 100644 index 000000000..b4734cb8c --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarFeatureUsage.cs @@ -0,0 +1,59 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Reads the generated surfaces a fixture's grammar.xml actually exercises. Only surfaces a +/// grammar author can control are observable this way: an element appears in the document, or an +/// enumerated attribute carries one of its declared values. +/// +public static class GrammarFeatureUsage +{ + public const string ElementPrefix = "dtd:element/"; + public const string EnumPrefix = "dtd:enum/"; + + /// + /// Surfaces observable from a grammar document, restricted to IDs the inventory actually + /// declares so a typo in a fixture cannot invent coverage. + /// + public static IReadOnlyCollection Read(XDocument grammar, SemanticInventory inventory) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(inventory); + var declared = new HashSet(inventory.Surfaces.Select(surface => surface.Id), StringComparer.Ordinal); + var used = new HashSet(StringComparer.Ordinal); + // Every ID component is percent-encoded by the inventory, so a Greek VariableFeature name + // read raw here would never match its generated surface. + foreach (XElement element in grammar.Descendants()) + { + string encodedElement = CanonicalIdCodec.Encode(element.Name.LocalName); + string elementId = ElementPrefix + encodedElement; + if (declared.Contains(elementId)) + used.Add(elementId); + foreach (XAttribute attribute in element.Attributes()) + { + string enumId = + $"{EnumPrefix}{encodedElement}/{CanonicalIdCodec.Encode(attribute.Name.LocalName)}" + + $"/{CanonicalIdCodec.Encode(attribute.Value)}"; + if (declared.Contains(enumId)) + used.Add(enumId); + } + } + + return used; + } + + /// Every surface in the inventory that a grammar document could ever exercise. + public static IReadOnlyCollection Observable(SemanticInventory inventory) + { + ArgumentNullException.ThrowIfNull(inventory); + return inventory + .Surfaces.Where(surface => surface.Kind is "element" or "enum") + .Select(surface => surface.Id) + .ToHashSet(StringComparer.Ordinal); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarMutator.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarMutator.cs new file mode 100644 index 000000000..4ad7c7b4b --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarMutator.cs @@ -0,0 +1,375 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// How a surface was neutralized, so the counterfactual's delta can name what changed. +/// +public sealed record GrammarMutation(string SurfaceId, string Kind, string Detail, XDocument Mutated); + +/// +/// Produces a grammar with one generated surface neutralized, so a counterfactual run can show whether +/// that surface influences any result. A mutation that leaves the document semantically identical is a +/// bug here, not evidence, which is why every mutation reports what it changed and refuses to return a +/// document it did not actually modify. +/// +public static class GrammarMutator +{ + public const string DeletedElements = "deleted-elements"; + public const string RewroteAttribute = "rewrote-attribute"; + public const string RemovedAttribute = "removed-attribute"; + public const string EmptiedChildren = "emptied-children"; + + /// Only one of a joint pair was activated; on its own this is not evidence for either surface. + public const string ActivatedPartnerAlone = "activated-partner-alone"; + + /// Both halves of a joint pair were activated together; see . + public const string ActivatedJointly = "activated-jointly"; + + /// + /// Neutralizes in a copy of , or returns null + /// when the document does not contain it. + /// + public static GrammarMutation? Mutate(XDocument grammar, string surfaceId, SemanticInventory inventory) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(surfaceId); + ArgumentNullException.ThrowIfNull(inventory); + + var copy = new XDocument(grammar); + if (surfaceId.StartsWith(GrammarFeatureUsage.ElementPrefix, StringComparison.Ordinal)) + return DeleteElement(copy, surfaceId); + if (surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + return NeutralizeEnumValue(copy, surfaceId, inventory); + return null; + } + + private static GrammarMutation? DeleteElement(XDocument copy, string surfaceId) + { + string name = Decode(surfaceId[GrammarFeatureUsage.ElementPrefix.Length..]); + List targets = copy.Descendants(name).ToList(); + if (targets.Count == 0) + return null; + foreach (XElement target in targets) + target.Remove(); + return new GrammarMutation(surfaceId, DeletedElements, $"removed {targets.Count} <{name}> element(s)", copy); + } + + /// One enum surface's parsed id components plus the attributes it targets in a document. + private sealed record EnumTargets(string Element, string Attribute, string Value, XAttribute[] Attributes); + + private static EnumTargets? LocateEnumTargets(XDocument copy, string surfaceId) + { + string[] parts = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..].Split('/'); + if (parts.Length != 3) + return null; + string element = Decode(parts[0]); + string attribute = Decode(parts[1]); + string value = Decode(parts[2]); + + XAttribute[] targets = copy.Descendants(element) + .Select(item => item.Attribute(attribute)) + .Where(attr => attr is not null && attr.Value == value) + .Select(attr => attr!) + .ToArray(); + return targets.Length == 0 ? null : new EnumTargets(element, attribute, value, targets); + } + + private static GrammarMutation? NeutralizeEnumValue(XDocument copy, string surfaceId, SemanticInventory inventory) + { + EnumTargets? located = LocateEnumTargets(copy, surfaceId); + if (located is null) + return null; + string[] parts = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..].Split('/'); + + // Writing a value equal to the DTD default is indistinguishable from omitting it, so the only + // available mutation is removal; the parser then supplies the same value, which is exactly what + // makes such a surface unobservable and is the proof this mutation produces. + string? sibling = Sibling(inventory, parts[0], parts[1], located.Value); + if (sibling is null) + { + foreach (XAttribute target in located.Attributes) + target.Remove(); + return new GrammarMutation( + surfaceId, + RemovedAttribute, + $"removed {located.Attributes.Length} {located.Element}@{located.Attribute}=\"{located.Value}\" (no declared sibling value)", + copy + ); + } + + return RewriteEnumTargets(copy, surfaceId, located, sibling); + } + + private static GrammarMutation RewriteEnumTargets( + XDocument copy, + string surfaceId, + EnumTargets located, + string sibling + ) + { + foreach (XAttribute target in located.Attributes) + target.Value = sibling; + return new GrammarMutation( + surfaceId, + RewroteAttribute, + $"rewrote {located.Attributes.Length} {located.Element}@{located.Attribute} from \"{located.Value}\" to \"{sibling}\"", + copy + ); + } + + /// One candidate neutralization of an enum surface against a specific declared sibling. + public sealed record EnumSiblingCandidate(string Sibling, GrammarMutation Mutation); + + /// + /// Builds one neutralizing mutation per declared sibling value of 's + /// enumerated attribute, in the same deterministic (ordinal) order uses -- + /// a caller that tries only 's pick can miss a sibling that discriminates + /// where the first one happens not to. Empty when is not an enum + /// surface, the document does not contain it, or it has no declared sibling at all (that last + /// case has only 's removal fallback to offer). + /// + public static IReadOnlyList MutateEnumAgainstEverySibling( + XDocument grammar, + string surfaceId, + SemanticInventory inventory + ) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(surfaceId); + ArgumentNullException.ThrowIfNull(inventory); + if (!surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + return Array.Empty(); + string[] parts = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..].Split('/'); + if (parts.Length != 3) + return Array.Empty(); + string value = Decode(parts[2]); + + var candidates = new List(); + foreach (string sibling in Siblings(inventory, parts[0], parts[1], value)) + { + var copy = new XDocument(grammar); + EnumTargets? located = LocateEnumTargets(copy, surfaceId); + if (located is null) + continue; + candidates.Add(new EnumSiblingCandidate(sibling, RewriteEnumTargets(copy, surfaceId, located, sibling))); + } + return candidates; + } + + /// + /// Empties every occurrence of 's element instead of removing it, for a + /// caller whose full deletion left the search space unconstrained rather than genuinely neutralized. + /// Returns null when the surface is not an element surface, the document lacks it, or it is already + /// empty (emptying it again would not be a real mutation). + /// + public static GrammarMutation? MutateByEmptyingElementChildren(XDocument grammar, string surfaceId) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(surfaceId); + if (!surfaceId.StartsWith(GrammarFeatureUsage.ElementPrefix, StringComparison.Ordinal)) + return null; + + var copy = new XDocument(grammar); + string name = Decode(surfaceId[GrammarFeatureUsage.ElementPrefix.Length..]); + List targets = copy.Descendants(name).ToList(); + if (targets.Count == 0) + return null; + + int removedNodes = targets.Sum(target => target.Nodes().Count()); + if (removedNodes == 0) + return null; + + foreach (XElement target in targets) + target.RemoveNodes(); + return new GrammarMutation( + surfaceId, + EmptiedChildren, + $"emptied {targets.Count} <{name}> element(s) ({removedNodes} child node(s) removed) rather than deleting them", + copy + ); + } + + /// + /// Identifies a joint-mutation pair for an isActive="no" surface that a single flip cannot + /// evidence: / is an + /// independently inactive declaration elsewhere in the same document whose IDREF names + /// . Carries only names and ids, not references, + /// so the same descriptor can be replayed against any number of fresh document clones. + /// + public sealed record JointPartner( + string TargetElement, + string TargetId, + string PartnerElement, + string PartnerAttribute + ); + + /// + /// Finds a declaration that references an inactive instance of 's + /// element while itself staying inactive -- the pair a joint mutation needs. Only applies to + /// isActive="no" enum surfaces, since that is the only shape with a "dangling reference if + /// activated alone" hazard for something else to guard against; returns null for anything else, for + /// a target the document does not contain, or when no such partner exists in the document. + /// + public static JointPartner? FindJointPartner(XDocument grammar, string surfaceId) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(surfaceId); + if (!surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + return null; + string[] parts = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..].Split('/'); + if (parts.Length != 3) + return null; + string element = Decode(parts[0]); + string attribute = Decode(parts[1]); + string value = Decode(parts[2]); + if (attribute != "isActive" || value != "no") + return null; + + XElement[] targets = grammar + .Descendants(element) + .Where(e => (string?)e.Attribute(attribute) == value && e.Attribute("id") is not null) + .ToArray(); + + foreach (XElement target in targets) + { + var targetId = (string)target.Attribute("id")!; + foreach (XElement candidate in grammar.Descendants()) + { + if (ReferenceEquals(candidate, target) || (string?)candidate.Attribute("isActive") != "no") + continue; + + // The reference may sit on a nested element rather than on the deactivated one itself, + // as a rule's pattern names a natural class from inside its own subrule. + XAttribute? reference = candidate + .DescendantsAndSelf() + .Attributes() + .FirstOrDefault(a => + a.Name.LocalName is not ("id" or "isActive") + && a.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries).Contains(targetId) + ); + if (reference is not null) + return new JointPartner(element, targetId, candidate.Name.LocalName, reference.Name.LocalName); + } + } + + return null; + } + + private static XElement? LocatePartner(XDocument document, JointPartner partner) => + document + .Descendants(partner.PartnerElement) + .FirstOrDefault(e => + (string?)e.Attribute("isActive") == "no" + // The reference may sit on a nested element rather than on the deactivated one + // itself, matching FindJointPartner's own search. + && e.DescendantsAndSelf() + .Attributes() + .Any(a => + a.Name.LocalName == partner.PartnerAttribute + && a.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries).Contains(partner.TargetId) + ) + ); + + private static string DescribePartner(XElement partnerElement) => + (string?)partnerElement.Attribute("id") ?? (string?)partnerElement.Element("Name") ?? "(unidentified)"; + + /// + /// Activates only 's referencing declaration, leaving the target it + /// names still isActive="no". Run alone -- never as evidence for the target -- to confirm + /// the delta a joint mutation produces is not already fully explained by the partner by itself. + /// + public static GrammarMutation? MutatePartnerAlone(XDocument grammar, JointPartner partner) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(partner); + + var copy = new XDocument(grammar); + XElement? partnerElement = LocatePartner(copy, partner); + if (partnerElement is null) + return null; + XAttribute isActive = partnerElement.Attribute("isActive")!; + isActive.Value = "yes"; + return new GrammarMutation( + $"{GrammarFeatureUsage.EnumPrefix}{Encode(partner.TargetElement)}/isActive/no", + ActivatedPartnerAlone, + $"activated only its referencing <{partner.PartnerElement}> ({DescribePartner(partnerElement)}) via " + + $"{partner.PartnerAttribute}=\"{partner.TargetId}\", while {partner.TargetElement}@isActive stayed \"no\"", + copy + ); + } + + /// + /// Activates 's target(s) exactly as would, then + /// additionally activates 's referencing declaration in the same + /// document, so the reference resolves instead of dangling. This is weaker evidence than a single + /// flip: see for why both flips must be shown + /// necessary before the delta counts for the target. + /// + public static GrammarMutation? MutateJointly( + XDocument grammar, + string surfaceId, + JointPartner partner, + SemanticInventory inventory + ) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(surfaceId); + ArgumentNullException.ThrowIfNull(partner); + ArgumentNullException.ThrowIfNull(inventory); + + GrammarMutation? targetMutation = Mutate(grammar, surfaceId, inventory); + if (targetMutation is null) + return null; + + XElement? partnerElement = LocatePartner(targetMutation.Mutated, partner); + if (partnerElement is null) + return null; + XAttribute isActive = partnerElement.Attribute("isActive")!; + isActive.Value = "yes"; + + return new GrammarMutation( + surfaceId, + ActivatedJointly, + $"{targetMutation.Detail}; jointly activated its sole referencing <{partner.PartnerElement}> " + + $"({DescribePartner(partnerElement)}) via {partner.PartnerAttribute}=\"{partner.TargetId}\", " + + "itself rewritten from isActive=\"no\" to \"yes\"", + targetMutation.Mutated + ); + } + + /// Every other declared value of the same enumerated attribute, in deterministic order. + public static IReadOnlyList Siblings( + SemanticInventory inventory, + string encodedElement, + string encodedAttribute, + string value + ) + { + ArgumentNullException.ThrowIfNull(inventory); + string prefix = $"{GrammarFeatureUsage.EnumPrefix}{encodedElement}/{encodedAttribute}/"; + return inventory + .Surfaces.Where(surface => surface.Id.StartsWith(prefix, StringComparison.Ordinal)) + .Select(surface => Decode(surface.Id[prefix.Length..])) + .Where(other => other != value) + .Distinct() + .OrderBy(other => other, StringComparer.Ordinal) + .ToArray(); + } + + /// The deterministically first other declared value of the same enumerated attribute. + public static string? Sibling( + SemanticInventory inventory, + string encodedElement, + string encodedAttribute, + string value + ) => Siblings(inventory, encodedElement, encodedAttribute, value).FirstOrDefault(); + + private static string Decode(string encoded) => Uri.UnescapeDataString(encoded); + + private static string Encode(string authoredValue) => CanonicalIdCodec.Encode(authoredValue); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarValidation.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarValidation.cs new file mode 100644 index 000000000..1359f65db --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GrammarValidation.cs @@ -0,0 +1,75 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Validates a fixture grammar against the pinned DTD with no external reach. +/// The only admitted external subset is the exact system identifier +/// HermitCrabInput.dtd, remapped to the repository's canonical DTD whatever directory the +/// fixture lives in. Network access and filesystem fallback are refused rather than attempted. +public static class GrammarValidation +{ + public const string AdmittedSystemId = "HermitCrabInput.dtd"; + + /// Validates , returning every validation message. + public static IReadOnlyList Validate(string grammarPath, string dtdPath) + { + ArgumentException.ThrowIfNullOrWhiteSpace(grammarPath); + ArgumentException.ThrowIfNullOrWhiteSpace(dtdPath); + + var messages = new List(); + var settings = new XmlReaderSettings + { + DtdProcessing = DtdProcessing.Parse, + ValidationType = ValidationType.DTD, + XmlResolver = new PinnedDtdResolver(Path.GetFullPath(dtdPath)), + }; + settings.ValidationEventHandler += (_, args) => messages.Add($"{args.Severity}: {args.Message}"); + + // The document is opened here so the resolver is consulted only for the DTD, never for the + // grammar's own URI. + using var grammar = new FileStream(grammarPath, FileMode.Open, FileAccess.Read, FileShare.Read); + using XmlReader reader = XmlReader.Create( + grammar, + settings, + new Uri(Path.GetFullPath(grammarPath)).AbsoluteUri + ); + while (reader.Read()) + { + // Validation is reported through the event handler; the read loop only drives it. + } + + return messages; + } + + private sealed class PinnedDtdResolver(string dtdPath) : XmlResolver + { + private readonly string _dtdPath = dtdPath; + + // Called for the document's own base URI as well as for external subsets, so admission is + // decided in GetEntity, which is where content would actually be opened. + public override Uri ResolveUri(Uri? baseUri, string? relativeUri) => + string.Equals(relativeUri, AdmittedSystemId, StringComparison.Ordinal) + ? new Uri(_dtdPath) + : base.ResolveUri(baseUri, relativeUri); + + public override object GetEntity(Uri absoluteUri, string? role, Type? typeOfObjectToReturn) + { + ArgumentNullException.ThrowIfNull(absoluteUri); + if ( + !absoluteUri.IsFile + || !string.Equals(Path.GetFullPath(absoluteUri.LocalPath), _dtdPath, StringComparison.OrdinalIgnoreCase) + ) + { + throw new XmlException( + $"External entity '{absoluteUri}' is not admitted; only '{AdmittedSystemId}' may be referenced." + ); + } + + return new FileStream(_dtdPath, FileMode.Open, FileAccess.Read, FileShare.Read); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GraphSemanticCensus.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GraphSemanticCensus.cs new file mode 100644 index 000000000..7d6b29953 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/GraphSemanticCensus.cs @@ -0,0 +1,59 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// The semantic inventory of the compilations the pinned compiler actually produced. +/// Replaces the pre-cutover pairing of a repository directory scan with +/// 's runtime reference approximation. Sources, symbols, +/// options and references all come from captured compiler inputs, so nothing here is inferred from +/// the process that happens to be running the census. +public static class GraphSemanticCensus +{ + private static readonly string[] CensusedProjects = { "hc", "hc-tool" }; + + public static SemanticInventory Read( + string repositoryRoot, + IReadOnlyList auditedScopes, + CancellationToken cancellationToken + ) + { + ArgumentException.ThrowIfNullOrWhiteSpace(repositoryRoot); + ArgumentNullException.ThrowIfNull(auditedScopes); + // Capturing compiler inputs costs an MSBuild pass, so an unusable scope is refused first. + foreach (string scope in auditedScopes) + { + if (ScopeValidation.HasPattern(scope)) + { + throw new ArgumentException( + $"Audited source scope '{scope}' must be exact; patterns are not allowed.", + nameof(auditedScopes) + ); + } + } + + RepositoryCompilationGraph captured = new RepositoryCompilationGraphLoader(new MsBuildProcessRunner()) + .LoadAsync(new RepositoryRoot(repositoryRoot), cancellationToken) + .AsTask() + .GetAwaiter() + .GetResult(); + RoslynCompilationGraph graph = RoslynCompilationGraph.Build(captured); + // The semantic coverage program audits the grammar format, not the C# engine's + // internals; an empty scope list names nothing to census rather than "census + // everything", so the C# reader (which requires at least one exact scope) is skipped + // and the composed inventory is the DTD's surfaces alone. + SemanticInventory csharp = + auditedScopes.Count == 0 + ? new SemanticInventory(string.Empty, string.Empty, Array.Empty()) + : CSharpInventoryReader.ReadFromGraph(graph, captured, repositoryRoot, CensusedProjects, auditedScopes); + + string dtdPath = GrammarCoverageGate.DtdRelativePath; + string dtdText = File.ReadAllText( + Path.Combine(repositoryRoot, dtdPath.Replace('/', Path.DirectorySeparatorChar)) + ); + return SemanticCoverageInventory.Compose(dtdPath, dtdText, csharp, captured.Hashes.GraphHash); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ImpossibilityProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ImpossibilityProofs.cs new file mode 100644 index 000000000..6c04c820a --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ImpossibilityProofs.cs @@ -0,0 +1,136 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +public sealed record ImpossibilityProof(string SurfaceId, string Kind, string Evidence); + +/// +/// The claims that evidence for a surface is impossible rather than merely missing. A surface whose +/// counterfactual verdict is not evidence fails the gate unless it is claimed here, so the file is the +/// only way a non-evidenced surface can pass, and every kind names a check rather than an argument. +/// +public static class ImpossibilityProofs +{ + public const string RelativePath = "conformance/semantic-coverage-proofs.tsv"; + + /// Value equals its attribute's DTD default, so the parser supplies it either way. + public const string DtdDefault = "dtd-default"; + + /// The engine contains no reference to the owning element. + public const string NoConsumer = "no-consumer"; + + /// The surface's data is carried by the model but never reaches a control-flow decision or + /// the comparison signature. + public const string NotInSignature = "not-in-signature"; + + /// An engine defect prevents any word from exercising it; must name fixture and issue. + public const string BlockedByDefect = "blocked-by-defect"; + + private static readonly HashSet Kinds = new(StringComparer.Ordinal) + { + DtdDefault, + NoConsumer, + NotInSignature, + BlockedByDefect, + }; + + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + var proofs = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields[0] == "surface") + { + continue; + } + + if (fields.Length != 3) + { + throw new FormatException($"{RelativePath}: '{line}' must be surface, kind and evidence"); + } + + if (!Kinds.Contains(fields[1])) + { + throw new FormatException($"{RelativePath}: unknown proof kind '{fields[1]}' for '{fields[0]}'"); + } + + if (fields[2].Trim().Length == 0) + { + throw new FormatException($"{RelativePath}: '{fields[0]}' claims {fields[1]} with no evidence"); + } + + proofs.Add(new ImpossibilityProof(fields[0], fields[1], fields[2])); + } + + return proofs.OrderBy(proof => proof.SurfaceId, StringComparer.Ordinal).ToArray(); + } + + /// + /// Surfaces whose verdict is not evidence and that no proof claims. Each is a real gap: neither a + /// recorded delta nor a claim that one is impossible. + /// + public static IReadOnlyList Unaccounted( + IReadOnlyList verdicts, + IReadOnlyList proofs + ) + { + ArgumentNullException.ThrowIfNull(verdicts); + ArgumentNullException.ThrowIfNull(proofs); + var claimed = proofs.Select(proof => proof.SurfaceId).ToHashSet(StringComparer.Ordinal); + return verdicts + .Where(verdict => + verdict.Verdict + is not ( + CounterfactualVerdict.Evidenced + or CounterfactualVerdict.RequiredByDtd + or CounterfactualVerdict.RequiredByLoader + or CounterfactualVerdict.EvidencedJointly + ) + ) + .Where(verdict => !claimed.Contains(verdict.SurfaceId)) + .OrderBy(verdict => verdict.SurfaceId, StringComparer.Ordinal) + .ToArray(); + } + + /// + /// Proofs that name a surface the sweep now evidences, or no longer measures at all. Either way the + /// claim is stale and must be deleted rather than left standing. + /// + public static IReadOnlyList Stale( + IReadOnlyList verdicts, + IReadOnlyList proofs + ) + { + ArgumentNullException.ThrowIfNull(verdicts); + ArgumentNullException.ThrowIfNull(proofs); + var evidenced = verdicts + .Where(verdict => + verdict.Verdict + is CounterfactualVerdict.Evidenced + or CounterfactualVerdict.RequiredByDtd + or CounterfactualVerdict.RequiredByLoader + or CounterfactualVerdict.EvidencedJointly + ) + .Select(verdict => verdict.SurfaceId) + .ToHashSet(StringComparer.Ordinal); + var measured = verdicts.Select(verdict => verdict.SurfaceId).ToHashSet(StringComparer.Ordinal); + return proofs + .Where(proof => evidenced.Contains(proof.SurfaceId) || !measured.Contains(proof.SurfaceId)) + .Select(proof => proof.SurfaceId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InactiveMemberProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InactiveMemberProofs.cs new file mode 100644 index 000000000..09fc91569 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InactiveMemberProofs.cs @@ -0,0 +1,184 @@ +#nullable enable +using System; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind : one member of an adjacent +/// pair can never affect the resolved rule list, regardless of which sibling it sits next to, because +/// XmlLanguageLoader either drops the member outright or the member itself resolves to nothing. +/// Two mechanisms, both recomputed from the current document: +/// +/// the member itself carries isActive="no", so LoadStratum's +/// MorphologicalRuleDefinitions/PhonologicalRuleDefinitions filters or +/// LoadAffixTemplate's Slot filter drop it before it is ever placed in the loaded collection an +/// IDREFS list orders; +/// for an AffixTemplateSlots pair, the member Slot is itself active but every id its +/// morphologicalRules attribute names is either inactive or undeclared (including a Slot with no +/// such attribute at all), so LoadAffixTemplate's per-id TryGetValue against the +/// already-filtered rule dictionary silently drops every one of them and the Slot contributes no +/// morpheme wherever it sits. +/// +/// Re-activating a member, or adding an id that resolves to an active rule to an empty Slot, invalidates +/// the corresponding proof. +/// +public static class InactiveMemberProofs +{ + public const string Kind = "inactive-member"; + + /// Builds a proof for , or null when neither + /// member is inactive or empty. + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + InactiveMemberCheck check = Check(grammar, item); + return check.HasInactiveMember ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies : true only when 's freshly + /// generated adjacent pairs still contain an item with 's id AND at least one + /// current member either carries isActive="no" itself or (for an AffixTemplateSlots pair) + /// resolves to no active rule. A stale id, an unresolvable member, and two contributing members all + /// fail closed to false. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return Check(grammar, item).HasInactiveMember; + } + + private sealed record InactiveMemberCheck(string ItemId, bool HasInactiveMember, string Reason); + + private static InactiveMemberCheck Check(XDocument grammar, OrderingItem item) => + item.Kind == OrderingListKind.AffixTemplateSlots ? CheckSlotPair(grammar, item) : CheckIdrefPair(grammar, item); + + // StratumMorphologicalRules/StratumPhonologicalRules members are IDREFS, unique document-wide, so + // any element carrying a matching id attribute is the declaration -- regardless of element type. + private static InactiveMemberCheck CheckIdrefPair(XDocument grammar, OrderingItem item) + { + XElement? elementA = FindElementById(grammar, item.MemberA); + XElement? elementB = FindElementById(grammar, item.MemberB); + if (elementA is null || elementB is null) + { + string missing = elementA is null ? item.MemberA : item.MemberB; + return new InactiveMemberCheck( + item.Id, + false, + $"'{missing}' was not found as an element with a matching id attribute" + ); + } + + if (!IsActiveElement(elementA)) + { + return new InactiveMemberCheck( + item.Id, + true, + $"'{item.MemberA}' (<{elementA.Name.LocalName}>) has isActive=\"no\"" + ); + } + if (!IsActiveElement(elementB)) + { + return new InactiveMemberCheck( + item.Id, + true, + $"'{item.MemberB}' (<{elementB.Name.LocalName}>) has isActive=\"no\"" + ); + } + return new InactiveMemberCheck(item.Id, false, "both members are active"); + } + + // AffixTemplateSlots members are a Slot's free-text Name, not a unique id, so the pair is relocated + // positionally within its owning AffixTemplate -- the same resolution OrderingGenerator.Swap uses. + // An active Slot whose morphologicalRules all fail to resolve is equally a no-op (EmptySlotReason). + private static InactiveMemberCheck CheckSlotPair(XDocument grammar, OrderingItem item) + { + XElement[] templates = grammar.Descendants("AffixTemplate").ToArray(); + if (item.OwnerOrdinal < 0 || item.OwnerOrdinal >= templates.Length) + { + return new InactiveMemberCheck( + item.Id, + false, + "owning AffixTemplate ordinal is out of range for the current document" + ); + } + + var slots = templates[item.OwnerOrdinal].Elements("Slot").ToList(); + if (item.PairIndex < 0 || item.PairIndex + 1 >= slots.Count) + return new InactiveMemberCheck(item.Id, false, "Slot pair index is out of range for the current document"); + + XElement slotA = slots[item.PairIndex]; + XElement slotB = slots[item.PairIndex + 1]; + if (SlotLabel(slotA, item.PairIndex) != item.MemberA || SlotLabel(slotB, item.PairIndex + 1) != item.MemberB) + { + return new InactiveMemberCheck( + item.Id, + false, + "the Slot pair no longer matches the document at this position" + ); + } + + if (!IsActiveElement(slotA)) + return new InactiveMemberCheck(item.Id, true, $"Slot '{item.MemberA}' has isActive=\"no\""); + if (!IsActiveElement(slotB)) + return new InactiveMemberCheck(item.Id, true, $"Slot '{item.MemberB}' has isActive=\"no\""); + + string? emptyA = EmptySlotReason(grammar, slotA, item.MemberA); + if (emptyA is not null) + return new InactiveMemberCheck(item.Id, true, emptyA); + string? emptyB = EmptySlotReason(grammar, slotB, item.MemberB); + if (emptyB is not null) + return new InactiveMemberCheck(item.Id, true, emptyB); + + return new InactiveMemberCheck( + item.Id, + false, + "both Slot members are active and resolve to at least one active rule" + ); + } + + // Mirrors LoadAffixTemplate's own resolution exactly: split the Slot's morphologicalRules IDREFS + // (absent counts as zero ids, matching an #IMPLIED-style empty list), and keep only ids that name a + // declared AND active rule. Null return means the Slot resolves to at least one active rule, so it + // is not empty. + private static string? EmptySlotReason(XDocument grammar, XElement slot, string slotLabel) + { + string? rulesAttribute = (string?)slot.Attribute("morphologicalRules"); + string[] ruleIds = string.IsNullOrEmpty(rulesAttribute) + ? Array.Empty() + : rulesAttribute.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + + if (ruleIds.Length == 0) + return $"Slot '{slotLabel}' declares no morphologicalRules and so resolves to no rule"; + + bool anyActive = ruleIds.Any(ruleId => + { + XElement? rule = FindElementById(grammar, ruleId); + return rule is not null && IsActiveElement(rule); + }); + return anyActive + ? null + : $"Slot '{slotLabel}''s referenced rule(s) {{{string.Join(",", ruleIds)}}} all fail to resolve to an active rule definition"; + } + + private static string SlotLabel(XElement slot, int index) + { + string? name = (string?)slot.Element("Name"); + return string.IsNullOrEmpty(name) ? $"Slot#{index}" : name; + } + + private static XElement? FindElementById(XDocument grammar, string id) => + grammar.Descendants().FirstOrDefault(e => (string?)e.Attribute("id") == id); + + private static bool IsActiveElement(XElement element) => (string?)element.Attribute("isActive") != "no"; +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InteractionChainLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InteractionChainLedger.cs new file mode 100644 index 000000000..4f0bad168 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InteractionChainLedger.cs @@ -0,0 +1,605 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// The write/read/ref direction of every declared IDREF/IDREFS interface, as a SEMANTIC judgment +/// checked against what the engine actually does with each value -- deliberately not +/// 's , which infers +/// direction from an attribute-name prefix. That heuristic is demonstrably wrong: a real field grammar +/// (a Bantu language) writes zero MorphologicalOutput.MPRFeatures and instead carries all of its +/// inflection-class/productivity-restriction features through LexicalEntry.ruleFeatures -- +/// which the prefix rule calls "ref" (it starts with neither output nor assigned) even +/// though XmlLanguageLoader.TryLoadLexEntry unions it straight into entry.MprFeatures, the +/// exact accumulator required/excludedMPRFeatures later gate on. A prefix is a +/// correlation the DTD's authors mostly followed, not a rule the engine enforces, so every one of the +/// 60 declared interfaces below was re-decided on what it does: WRITE places a value into derivation +/// state that something else later reads; READ gates on derivation state something else placed there; +/// REF is a structural pointer to a fixed definition, participating in no write/read pair. Two more +/// reclassifications fell out of applying that same test rather than patching the one reported case: +/// LexicalEntry.partOfSpeech seeds entry.SyntacticFeatureStruct exactly as +/// ruleFeatures seeds entry.MprFeatures (read by every requiredPartsOfSpeech-family +/// gate), and Allomorph.stemName labels allomorph.StemName, read by +/// MorphologicalRule.requiredStemName (SynthesisAffixProcessRule) -- a junction +/// (StemName) the prefix heuristic could not see at all, since InterfaceInventoryLedger +/// only asks the writer/reader question of the two payload types it already found writers and readers +/// for one at a time by name. +/// +internal static class SemanticInterfaceDirection +{ + // Grouped by element for review. A short rationale sits next to every reclassified or otherwise + // non-obvious entry; an unremarked entry means the prefix-implied direction and the semantic one + // agree. "dead" means the DTD declares it but no engine source references the attribute at all + // (grep-confirmed against src/SIL.Machine.Morphology.HermitCrab); syntactic subcategorization and + // the two LexicalEntry obligatory*Features attributes are exceptions, direction is recorded for + // completeness but neither can ever form a junction. + private static readonly IReadOnlyDictionary<(string Element, string Attribute), InterfaceDirection> Table = + new Dictionary<(string, string), InterfaceDirection> + { + [("AffixTemplate", "requiredPartsOfSpeech")] = InterfaceDirection.Read, + [("AffixTemplate", "requiredSubcategorizedRules")] = InterfaceDirection.Read, // dead (subcategorization) + + // Constrains against which OTHER allomorphs/morphemes the derivation already selected -- + // structural membership, not a value any declared attribute writes (MorphemeCoOccurrenceRule / + // AllomorphCoOccurrenceRule match on Word/Morpheme identity directly). + [("Allomorph", "stemName")] = InterfaceDirection.Write, // RECLASSIFIED: seeds allomorph.StemName (XmlLanguageLoader), read by MorphologicalRule.requiredStemName + [("AllomorphCoOccurrenceRule", "otherAllomorphs")] = InterfaceDirection.Ref, + [("AllomorphCoOccurrenceRule", "primaryAllomorph")] = InterfaceDirection.Ref, + [("AlphaVariable", "variableFeature")] = InterfaceDirection.Ref, + [("BoundaryMarker", "boundary")] = InterfaceDirection.Ref, + + [("CompoundingRule", "headPartsOfSpeech")] = InterfaceDirection.Read, + [("CompoundingRule", "headProdRestrictionsMprFeatures")] = InterfaceDirection.Read, + [("CompoundingRule", "headSubcategorizedRules")] = InterfaceDirection.Read, // dead (subcategorization) + [("CompoundingRule", "nonHeadPartsOfSpeech")] = InterfaceDirection.Read, + [("CompoundingRule", "nonHeadProdRestrictionsMprFeatures")] = InterfaceDirection.Read, + [("CompoundingRule", "nonHeadSubcategorizedRules")] = InterfaceDirection.Read, // dead (subcategorization) + [("CompoundingRule", "outputObligatoryFeatures")] = InterfaceDirection.Write, // writes Word.ObligatorySyntacticFeatures; only read by Morpher's own final-word validation, not by another declared attribute -- no junction forms + [("CompoundingRule", "outputPartOfSpeech")] = InterfaceDirection.Write, + [("CompoundingRule", "outputProdRestrictionsMprFeatures")] = InterfaceDirection.Write, + [("CompoundingRule", "outputSubcategorization")] = InterfaceDirection.Write, // dead (subcategorization) + + [("CopyFromInput", "index")] = InterfaceDirection.Ref, + [("FeatureValue", "feature")] = InterfaceDirection.Ref, + [("FeatureValue", "symbolValues")] = InterfaceDirection.Ref, + + [("HeadMorphologicalInput", "excludedMPRFeatures")] = InterfaceDirection.Read, + [("HeadMorphologicalInput", "requiredMPRFeatures")] = InterfaceDirection.Read, + + [("InsertSegments", "characterDefinitionTable")] = InterfaceDirection.Ref, + + // LexicalEntry.family blocks other members of the SAME family from also matching -- checked + // directly against family membership, not against a value any other declared attribute reads. + [("LexicalEntry", "family")] = InterfaceDirection.Ref, + [("LexicalEntry", "morphologicalRules")] = InterfaceDirection.Ref, // dead: no loader reference at all + [("LexicalEntry", "obligatoryFootFeatures")] = InterfaceDirection.Read, // dead: no loader reference at all + [("LexicalEntry", "obligatoryHeadFeatures")] = InterfaceDirection.Read, // dead: no loader reference at all + [("LexicalEntry", "partOfSpeech")] = InterfaceDirection.Write, // RECLASSIFIED: seeds entry.SyntacticFeatureStruct (XmlLanguageLoader.TryLoadLexEntry), read by every requiredPartsOfSpeech-family gate + [("LexicalEntry", "ruleFeatures")] = InterfaceDirection.Write, // RECLASSIFIED: seeds entry.MprFeatures (XmlLanguageLoader.TryLoadLexEntry), read by every required/excludedMPRFeatures-family gate + [("LexicalEntry", "subcategorizations")] = InterfaceDirection.Ref, // dead (subcategorization) + + [("MetathesisRule", "leftSwitch")] = InterfaceDirection.Ref, + [("MetathesisRule", "rightSwitch")] = InterfaceDirection.Ref, + [("ModifyFromInput", "index")] = InterfaceDirection.Ref, + [("MorphemeCoOccurrenceRule", "otherMorphemes")] = InterfaceDirection.Ref, + [("MorphemeCoOccurrenceRule", "primaryMorpheme")] = InterfaceDirection.Ref, + + [("MorphologicalInput", "excludedMPRFeatures")] = InterfaceDirection.Read, + [("MorphologicalInput", "requiredMPRFeatures")] = InterfaceDirection.Read, + [("MorphologicalOutput", "MPRFeatures")] = InterfaceDirection.Write, + + // The mutator's own group membership -- consumed by MprFeatureSet.AddOutput as configuration, + // not itself a write or read of the derivation payload. + [("MorphologicalPhonologicalRuleFeatureGroup", "features")] = InterfaceDirection.Ref, + + [("MorphologicalRule", "outputObligatoryFeatures")] = InterfaceDirection.Write, // see CompoundingRule.outputObligatoryFeatures: no attribute reads it, no junction + [("MorphologicalRule", "outputPartOfSpeech")] = InterfaceDirection.Write, + [("MorphologicalRule", "outputSubcategorization")] = InterfaceDirection.Write, // dead (subcategorization) + [("MorphologicalRule", "requiredPartsOfSpeech")] = InterfaceDirection.Read, + [("MorphologicalRule", "requiredStemName")] = InterfaceDirection.Read, // reads input.RootAllomorph.StemName (SynthesisAffixProcessRule) + [("MorphologicalRule", "requiredSubcategorizedRules")] = InterfaceDirection.Read, // dead (subcategorization) + + [("OutputSubcategorizationOverride", "inputSubcategorization")] = InterfaceDirection.Ref, // dead (subcategorization) + [("OutputSubcategorizationOverride", "outputSubcategorization")] = InterfaceDirection.Write, // dead (subcategorization) + + [("PhonologicalSubrule", "excludedMPRFeatures")] = InterfaceDirection.Read, + [("PhonologicalSubrule", "requiredMPRFeatures")] = InterfaceDirection.Read, + [("PhonologicalSubrule", "requiredPartsOfSpeech")] = InterfaceDirection.Read, + + [("Segment", "segment")] = InterfaceDirection.Ref, + [("Segments", "characterDefinitionTable")] = InterfaceDirection.Ref, + [("SimpleContext", "naturalClass")] = InterfaceDirection.Ref, + [("Slot", "morphologicalRules")] = InterfaceDirection.Ref, + + // Configures the StemName DEFINITION's own applicability domain (which POS a region covers), + // not a per-derivation write/read of the word's current POS -- unlike Allomorph.stemName, + // which labels one specific allomorph instance and is what requiredStemName actually reads. + [("StemName", "partsOfSpeech")] = InterfaceDirection.Ref, + + [("Stratum", "characterDefinitionTable")] = InterfaceDirection.Ref, + [("Stratum", "morphologicalRules")] = InterfaceDirection.Ref, + [("Stratum", "phonologicalRules")] = InterfaceDirection.Ref, + [("SymbolicFeature", "defaultSymbol")] = InterfaceDirection.Ref, + [("VariableFeature", "phonologicalFeature")] = InterfaceDirection.Ref, + }; + + /// + /// Every (element, attribute) pair the table above must classify -- one per declared IDREF/IDREFS + /// interface, so a DTD change that adds or removes one is a loud failure + /// rather than a silent fallback. + /// + public static IReadOnlyCollection<(string Element, string Attribute)> ClassifiedInterfaces => Table.Keys.ToArray(); + + public static InterfaceDirection Classify(string element, string attribute) + { + if (Table.TryGetValue((element, attribute), out InterfaceDirection direction)) + return direction; + + throw new InvalidOperationException( + $"no semantic direction recorded for {element}.{attribute} -- add it to " + + $"{nameof(SemanticInterfaceDirection)}.{nameof(Table)} rather than falling back to a guess" + ); + } +} + +/// +/// The DTD/engine-verified target payload type for a declared Write/Read interface that no fixture +/// currently exercises. resolves target types by looking up an +/// attribute's IDREF(S) tokens against a real fixture's own id-to-element map, which only works when +/// some fixture sets a non-empty value -- exactly the interfaces this layer most needs to see are the +/// ones with none. The DTD's own prose comments cannot fill that gap (they are inconsistent -- compare +/// CopyFromInput.index's comment, which names the wrong element entirely, against the corpus- +/// resolved truth), so every entry here was instead confirmed against the engine: the C# field type +/// each attribute loads into, and, for the two Read entries, the actual gate that consumes it. +/// +internal static class UnexercisedInterfaceDeclaredPayloadTypes +{ + // CompoundingRule.headProdRestrictionsMprFeatures is corpus-exercised and already resolves to + // MorphologicalPhonologicalRuleFeature. Its nonHead and output siblings load through the exact + // same mechanism -- XmlLanguageLoader.LoadMprFeatures into a MprFeatureSet field -- and are read + // (AnalysisCompoundingRule.CompoundMprFeaturesMatch) / written (SynthesisCompoundingRule's + // outWord.MprFeatures.AddOutput(_rule.OutputProdRestrictionsMprFeatures)) exactly like their + // exercised sibling; only the corpus never sets them. PhonologicalSubrule's pair loads through the + // same LoadMprFeatures call and is read by SynthesisRewriteSubruleSpec's RequiredMprFeatures / + // ExcludedMprFeatures gate -- this is the literal construct the whole chain layer exists to test. + private static readonly IReadOnlyDictionary<(string Element, string Attribute), string> Table = new Dictionary< + (string, string), + string + > + { + [("CompoundingRule", "nonHeadProdRestrictionsMprFeatures")] = "MorphologicalPhonologicalRuleFeature", + [("CompoundingRule", "outputProdRestrictionsMprFeatures")] = "MorphologicalPhonologicalRuleFeature", + [("PhonologicalSubrule", "requiredMPRFeatures")] = "MorphologicalPhonologicalRuleFeature", + [("PhonologicalSubrule", "excludedMPRFeatures")] = "MorphologicalPhonologicalRuleFeature", + }; + + public static string? Lookup(string element, string attribute) => + Table.TryGetValue((element, attribute), out string? type) ? type : null; +} + +/// +/// A construct that can alter an already-written payload before a later reader gates on it. The only +/// known instance anywhere in the grammar is +/// MorphologicalPhonologicalRuleFeatureGroup: +/// drops every other member of a group whose outputType is (or, per +/// XmlLanguageLoader.GetGroupOutput's fallthrough, defaults to) overwrite before unioning +/// in a new write. PartOfSpeech has no analogous entry: every writer applies its value with a single +/// FeatureStruct PriorityUnion (e.g. SynthesisCompoundingRule), never through a separate +/// group construct with its own overwrite/append toggle -- so is empty for +/// every payload type except the one registered below. +/// +internal static class MutatingConstructs +{ + public static IReadOnlySet MutableIds(string payloadType, XDocument grammar) + { + ArgumentNullException.ThrowIfNull(payloadType); + ArgumentNullException.ThrowIfNull(grammar); + + var ids = new HashSet(StringComparer.Ordinal); + if (payloadType != "MorphologicalPhonologicalRuleFeature") + return ids; + + foreach (XElement group in grammar.Descendants("MorphologicalPhonologicalRuleFeatureGroup")) + { + // GetGroupOutput treats anything other than the literal string "append" as overwrite + // (including a missing attribute, matching the DTD's own "overwrite" default) -- mirrored + // here rather than only checking for the literal string "overwrite". + string outputType = (string?)group.Attribute("outputType") ?? "overwrite"; + if (outputType == "append") + continue; + + string? features = (string?)group.Attribute("features"); + if (string.IsNullOrEmpty(features)) + continue; + + foreach (string id in features.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)) + ids.Add(id); + } + + return ids; + } +} + +/// +/// A payload type reached by at least one declared interface and +/// at least one declared interface, per +/// -- the semantic replacement for +/// , which the same field-grammar evidence that +/// motivated shows undercounting: it never asks the +/// writer/reader question of a payload type it has not already found a writer AND a reader for by +/// attribute name, so StemName (written by Allomorph.stemName, read by +/// MorphologicalRule.requiredStemName) never surfaces there at all. +/// +public sealed record ChainJunction( + string PayloadType, + IReadOnlyList<(string Element, string Attribute)> Writers, + IReadOnlyList<(string Element, string Attribute)> Readers +); + +/// +/// The checked-in denominator for the interaction-chain layer: one row per (writer edge, payload type, +/// reader edge) at each . Unlike the edge ledger, whose rows are DTD-declared +/// interfaces one at a time, a row here is a PATH: the composition an edge test cannot see, because +/// passing both edges in isolation says nothing about what happens to the payload between them, the +/// way an intervening overwrite can. The denominator is junctions x their +/// writers x their readers, taken from the DTD/engine ( decides +/// which declared interfaces are writers/readers at all; +/// fills in the payload type for the ones no fixture exercises, so an entirely-untested reader cannot +/// silently vanish from its own denominator); only "exercised" and "hazardous" move with the corpus. +/// +public static class InteractionChainLedger +{ + public const string RelativePath = "conformance/interaction-chains.tsv"; + + private const int ColumnCount = 8; + + public sealed record Row( + string WriterElement, + string WriterAttribute, + string PayloadType, + string ReaderElement, + string ReaderAttribute, + bool Exercised, + IReadOnlyList ExercisingFixtures, + bool Hazardous + ); + + private sealed record FixtureIndex( + string FixtureId, + IReadOnlyDictionary<(string Element, string Attribute), HashSet> IdsByInterface, + IReadOnlyDictionary> MutableIdsByPayload + ); + + /// + /// Groups every declared interface by payload type using + /// (not ), then keeps only payload types reached + /// by at least one writer AND at least one reader. + /// + public static IReadOnlyList ComputeJunctions(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + + (var writersByPayload, var readersByPayload, _) = GroupDeclaredInterfacesByPayload( + InterfaceInventoryLedger.Compute(repositoryRoot) + ); + + return writersByPayload + .Keys.Where(readersByPayload.ContainsKey) + .OrderBy(t => t, StringComparer.Ordinal) + .Select(t => new ChainJunction(t, writersByPayload[t], readersByPayload[t])) + .ToArray(); + } + + private static ( + Dictionary> WritersByPayload, + Dictionary> ReadersByPayload, + IReadOnlyDictionary<(string Element, string Attribute), IReadOnlyList> DeclaredTypes + ) GroupDeclaredInterfacesByPayload(IReadOnlyList edgeRows) + { + var declaredTypes = new Dictionary<(string Element, string Attribute), IReadOnlyList>(); + foreach (InterfaceInventoryLedger.Row row in edgeRows) + { + InterfaceDirection direction = SemanticInterfaceDirection.Classify(row.Element, row.Attribute); + if (direction == InterfaceDirection.Ref) + continue; + + if (row.ObservedTargetTypes.Count > 0) + { + declaredTypes[(row.Element, row.Attribute)] = row.ObservedTargetTypes; + continue; + } + + string? declared = UnexercisedInterfaceDeclaredPayloadTypes.Lookup(row.Element, row.Attribute); + if (declared != null) + declaredTypes[(row.Element, row.Attribute)] = new[] { declared }; + } + + var writersByPayload = GroupByPayload(edgeRows, declaredTypes, InterfaceDirection.Write); + var readersByPayload = GroupByPayload(edgeRows, declaredTypes, InterfaceDirection.Read); + return (writersByPayload, readersByPayload, declaredTypes); + } + + /// + /// Enumerates every (writer, payload, reader) chain at each , then checks + /// each one against every fixture: a chain is exercised in a fixture when the SAME id appears in + /// both the writer's and the reader's attribute values there (a stronger claim than "both attributes + /// are non-empty somewhere in the grammar", matching the level of rigor + /// already applies to a single edge), and hazardous when at + /// least one exercising fixture also has a entry covering that + /// shared id. + /// + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + + IReadOnlyList edgeRows = InterfaceInventoryLedger.Compute(repositoryRoot); + (var writersByPayload, var readersByPayload, var declaredTypes) = GroupDeclaredInterfacesByPayload(edgeRows); + + IReadOnlyList junctions = writersByPayload + .Keys.Where(readersByPayload.ContainsKey) + .OrderBy(t => t, StringComparer.Ordinal) + .Select(t => new ChainJunction(t, writersByPayload[t], readersByPayload[t])) + .ToArray(); + + IReadOnlyList fixtureIndexes = IndexFixtures( + repositoryRoot, + declaredTypes.Keys, + junctions.Select(j => j.PayloadType).ToArray() + ); + + var rows = new List(); + foreach (ChainJunction junction in junctions) + { + IReadOnlyList<(string Element, string Attribute)> writers = junction.Writers; + IReadOnlyList<(string Element, string Attribute)> readers = junction.Readers; + + foreach ((string writerElement, string writerAttribute) in writers) + { + foreach ((string readerElement, string readerAttribute) in readers) + { + var exercisingFixtures = new List(); + bool hazardous = false; + foreach (FixtureIndex fixture in fixtureIndexes) + { + if ( + !fixture.IdsByInterface.TryGetValue( + (writerElement, writerAttribute), + out HashSet? writerIds + ) + || !fixture.IdsByInterface.TryGetValue( + (readerElement, readerAttribute), + out HashSet? readerIds + ) + ) + { + continue; + } + + var shared = new HashSet(writerIds, StringComparer.Ordinal); + shared.IntersectWith(readerIds); + if (shared.Count == 0) + continue; + + exercisingFixtures.Add(fixture.FixtureId); + if ( + fixture.MutableIdsByPayload.TryGetValue( + junction.PayloadType, + out IReadOnlySet? mutable + ) && shared.Any(mutable.Contains) + ) + { + hazardous = true; + } + } + + rows.Add( + new Row( + writerElement, + writerAttribute, + junction.PayloadType, + readerElement, + readerAttribute, + exercisingFixtures.Count > 0, + exercisingFixtures.OrderBy(f => f, StringComparer.Ordinal).ToArray(), + hazardous + ) + ); + } + } + } + + return rows.OrderBy(r => r.PayloadType, StringComparer.Ordinal) + .ThenBy(r => r.WriterElement, StringComparer.Ordinal) + .ThenBy(r => r.WriterAttribute, StringComparer.Ordinal) + .ThenBy(r => r.ReaderElement, StringComparer.Ordinal) + .ThenBy(r => r.ReaderAttribute, StringComparer.Ordinal) + .ToArray(); + } + + private static Dictionary> GroupByPayload( + IReadOnlyList edgeRows, + IReadOnlyDictionary<(string Element, string Attribute), IReadOnlyList> declaredTypes, + InterfaceDirection direction + ) + { + var byPayload = new Dictionary>(StringComparer.Ordinal); + foreach (InterfaceInventoryLedger.Row row in edgeRows) + { + if (SemanticInterfaceDirection.Classify(row.Element, row.Attribute) != direction) + continue; + if (!declaredTypes.TryGetValue((row.Element, row.Attribute), out IReadOnlyList? types)) + continue; + + foreach (string type in types) + { + if (!byPayload.TryGetValue(type, out List<(string, string)>? list)) + { + list = new List<(string, string)>(); + byPayload[type] = list; + } + list.Add((row.Element, row.Attribute)); + } + } + return byPayload; + } + + private static IReadOnlyList IndexFixtures( + string repositoryRoot, + IEnumerable<(string Element, string Attribute)> declaredInterfaces, + IReadOnlyList payloadTypes + ) + { + IReadOnlyList<(string Element, string Attribute)> interfaces = declaredInterfaces.ToArray(); + + var indexes = new List(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + + var idsByInterface = new Dictionary<(string, string), HashSet>(); + foreach ((string element, string attribute) in interfaces) + { + foreach (XElement owner in grammar.Descendants(element)) + { + string? value = (string?)owner.Attribute(attribute); + if (string.IsNullOrEmpty(value)) + continue; + + var key = (element, attribute); + if (!idsByInterface.TryGetValue(key, out HashSet? ids)) + { + ids = new HashSet(StringComparer.Ordinal); + idsByInterface[key] = ids; + } + foreach (string token in value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)) + ids.Add(token); + } + } + + var mutableIdsByPayload = new Dictionary>(StringComparer.Ordinal); + foreach (string payloadType in payloadTypes) + mutableIdsByPayload[payloadType] = MutatingConstructs.MutableIds(payloadType, grammar); + + indexes.Add(new FixtureIndex(fixture.Id, idsByInterface, mutableIdsByPayload)); + } + + return indexes; + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + /// + /// Renders the ledger deterministically (payload type, then writer, then reader) so two runs over + /// an unchanged DTD/engine/corpus byte-for-byte agree -- the drift gate depends on this. + /// + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine("# GENERATED by hc-conformance --write-interaction-chains. One row per (writer edge, payload"); + writer.WriteLine("# type, reader edge) at each ChainJunction -- a payload type reached by both a write- and a"); + writer.WriteLine( + "# read-direction declared interface, per SemanticInterfaceDirection's engine-checked judgment" + ); + writer.WriteLine( + "# of what each interface does (NOT interface-inventory.tsv's own name-prefix heuristic, which" + ); + writer.WriteLine( + "# a real field grammar disproved -- see SemanticInterfaceDirection's doc comment). payload_type" + ); + writer.WriteLine( + "# also covers interfaces no fixture exercises yet (see UnexercisedInterfaceDeclaredPayloadTypes)," + ); + writer.WriteLine("# so an entirely-untested reader still appears in its own denominator instead of silently"); + writer.WriteLine("# vanishing. exercising_fixtures lists every fixture where the SAME id appears in both the"); + writer.WriteLine( + "# writer's and the reader's attribute values; hazardous means at least one of those fixtures" + ); + writer.WriteLine("# also has a MutatingConstructs entry (today: an overwrite-type"); + writer.WriteLine("# MorphologicalPhonologicalRuleFeatureGroup) covering that id."); + writer.WriteLine( + "writer_element\twriter_attribute\tpayload_type\treader_element\treader_attribute\texercised\texercising_fixtures\thazardous" + ); + foreach ( + Row row in rows.OrderBy(r => r.PayloadType, StringComparer.Ordinal) + .ThenBy(r => r.WriterElement, StringComparer.Ordinal) + .ThenBy(r => r.WriterAttribute, StringComparer.Ordinal) + .ThenBy(r => r.ReaderElement, StringComparer.Ordinal) + .ThenBy(r => r.ReaderAttribute, StringComparer.Ordinal) + ) + { + writer.WriteLine( + string.Join( + '\t', + row.WriterElement, + row.WriterAttribute, + row.PayloadType, + row.ReaderElement, + row.ReaderAttribute, + row.Exercised ? "yes" : "no", + string.Join(",", row.ExercisingFixtures), + row.Hazardous ? "yes" : "no" + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("writer_element\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (fields[5] is not ("yes" or "no")) + throw new FormatException($"{RelativePath}: unknown exercised flag '{fields[5]}'"); + if (fields[7] is not ("yes" or "no")) + throw new FormatException($"{RelativePath}: unknown hazardous flag '{fields[7]}'"); + + IReadOnlyList fixtures = fields[6].Length == 0 ? Array.Empty() : fields[6].Split(','); + rows.Add( + new Row( + fields[0], + fields[1], + fields[2], + fields[3], + fields[4], + fields[5] == "yes", + fixtures, + fields[7] == "yes" + ) + ); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceInventoryLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceInventoryLedger.cs new file mode 100644 index 000000000..c5cacdb1d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceInventoryLedger.cs @@ -0,0 +1,382 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Whether a declared interface is a single IDREF or a list-valued IDREFS. +public enum InterfaceRefKind +{ + IdRef, + IdRefs, +} + +/// +/// Whether a declared interface produces a payload (), gates on one +/// (), or neither -- a plain structural handoff (). See +/// for how this is judged. +/// +public enum InterfaceDirection +{ + Write, + Read, + Ref, +} + +/// +/// Infers a declared interface's from its attribute name. Superseded +/// by : this prefix guess disagrees with the engine-checked +/// table on Allomorph.stemName, LexicalEntry.partOfSpeech, and +/// LexicalEntry.ruleFeatures (all three seed a payload the prefix rule cannot recognise as a +/// write). no longer calls this; it is kept, unused, +/// only because 's doc comment cross-references it by name. +/// +internal static class InterfaceDirectionClassifier +{ + private static readonly string[] WritePrefixes = { "output", "assigned" }; + private static readonly string[] ReadPrefixes = { "required", "excluded", "obligatory", "head", "nonHead" }; + + public static InterfaceDirection Classify(string attributeName) + { + ArgumentNullException.ThrowIfNull(attributeName); + + if ( + attributeName == "MPRFeatures" + || WritePrefixes.Any(prefix => attributeName.StartsWith(prefix, StringComparison.Ordinal)) + ) + { + return InterfaceDirection.Write; + } + + if (ReadPrefixes.Any(prefix => attributeName.StartsWith(prefix, StringComparison.Ordinal))) + { + return InterfaceDirection.Read; + } + + return InterfaceDirection.Ref; + } +} + +/// A payload element type that is both written and read by at least one declared interface each. +public sealed record InterfaceJunction(string TargetType, int WriterCount, int ReaderCount); + +/// +/// The checked-in denominator for interface coverage: one row per IDREF/IDREFS +/// attribute declared anywhere in HermitCrabInput.dtd, resolved against the real corpus to +/// find which element types it actually points at. Unlike (a +/// corpus statistic that grows with the fixture set), this ledger's denominator is fixed by the DTD +/// alone -- adding a fixture can only change which declared interfaces are marked present and what +/// their observed target types are, never how many rows exist. "Present" here is structural only; see +/// 's own doc comment and for the semantic claim. +/// +public static class InterfaceInventoryLedger +{ + public const string RelativePath = "conformance/interface-inventory.tsv"; + + // Read() trims each raw line (matching every other ledger's Read), which strips a trailing tab + // along with real whitespace -- fine while the last column is never empty, but fixtures (added + // after direction, now the last column) legitimately is empty for a not-present row. "-" instead + // of "" for that case is the same sentinel the rest of this directory already uses for exactly + // this reason (see EvidenceLedger's NullField), not a new convention. + private const string NullField = "-"; + private const int ColumnCount = 7; + + /// + /// is a STRUCTURAL claim only: the attribute resolves to a real IDREF + /// somewhere in the corpus. It is NOT evidence that the interface carries anything -- an attribute + /// can be present and inert, where deleting it changes no parse. The semantic claim -- does severing + /// it ever change a word's parse -- is 's job, kept out of this + /// cheap, reparse-free ledger on purpose. is every fixture where the + /// attribute is present; it answers "what would I lose if I deleted this fixture" for PRESENCE only. + /// + public sealed record Row( + string Element, + string Attribute, + InterfaceRefKind RefKind, + IReadOnlyList ObservedTargetTypes, + bool Present, + InterfaceDirection Direction, + IReadOnlyList Fixtures + ); + + /// + /// Declares every IDREF/IDREFS attribute in the DTD, then resolves each one against + /// every fixture's grammar: for every element in the corpus that carries the declared attribute + /// with a non-empty value, its IDREF(S) tokens are looked up in that fixture's own id-to-element + /// map, and every element type found is recorded as an observed target type for that interface. + /// A declared interface with no matching element anywhere in the corpus is not present anywhere. + /// This stays cheap and reparse-free on purpose -- see for the + /// separate, expensive severance sweep that answers whether presence is also witness. + /// + public static IReadOnlyList Compute(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + + string dtdPath = Path.Combine( + repositoryRoot, + GrammarCoverageGate.DtdRelativePath.Replace('/', Path.DirectorySeparatorChar) + ); + string dtdText = File.ReadAllText(dtdPath); + IReadOnlyList<(string Element, string Attribute, InterfaceRefKind RefKind)> declared = DeclaredInterfaces( + GrammarCoverageGate.DtdRelativePath, + dtdText + ); + + var observedTargets = new Dictionary<(string Element, string Attribute), HashSet>(); + var present = new HashSet<(string Element, string Attribute)>(); + var presentFixtures = new Dictionary<(string Element, string Attribute), SortedSet>(); + + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + var idToElement = new Dictionary(StringComparer.Ordinal); + foreach (XElement candidate in grammar.Descendants()) + { + string? id = (string?)candidate.Attribute("id"); + if (id is not null) + idToElement[id] = candidate.Name.LocalName; + } + + foreach ((string element, string attribute, InterfaceRefKind _) in declared) + { + foreach (XElement owner in grammar.Descendants(element)) + { + string? value = (string?)owner.Attribute(attribute); + if (string.IsNullOrEmpty(value)) + continue; + + var key = (element, attribute); + present.Add(key); + if (!presentFixtures.TryGetValue(key, out SortedSet? fixtureIds)) + { + fixtureIds = new SortedSet(StringComparer.Ordinal); + presentFixtures[key] = fixtureIds; + } + fixtureIds.Add(fixture.Id); + + foreach (string token in SplitIdrefs(value)) + { + if (!idToElement.TryGetValue(token, out string? targetType)) + continue; + + if (!observedTargets.TryGetValue(key, out HashSet? targets)) + { + targets = new HashSet(StringComparer.Ordinal); + observedTargets[key] = targets; + } + targets.Add(targetType); + } + } + } + } + + var rows = new List(); + foreach ((string element, string attribute, InterfaceRefKind refKind) in declared) + { + var key = (element, attribute); + IReadOnlyList targets = observedTargets.TryGetValue(key, out HashSet? set) + ? set.OrderBy(t => t, StringComparer.Ordinal).ToArray() + : Array.Empty(); + IReadOnlyList fixtureIds = presentFixtures.TryGetValue(key, out SortedSet? ids) + ? ids.ToArray() + : Array.Empty(); + rows.Add( + new Row( + element, + attribute, + refKind, + targets, + present.Contains(key), + SemanticInterfaceDirection.Classify(element, attribute), + fixtureIds + ) + ); + } + + return rows.OrderBy(r => r.Element, StringComparer.Ordinal) + .ThenBy(r => r.Attribute, StringComparer.Ordinal) + .ToArray(); + } + + /// + /// Groups every observed (element, attribute) -> target-type edge by target type and reports + /// the payload types that have at least one edge AND at + /// least one edge -- the junctions where a chained + /// interaction (something writes a payload another construct later reads) is actually possible. + /// edges contribute to neither count. Since Row.Direction + /// is now 's judgment, this agrees with + /// by construction rather than by convention. + /// + public static IReadOnlyList ComputeJunctions(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + + var writers = new Dictionary(StringComparer.Ordinal); + var readers = new Dictionary(StringComparer.Ordinal); + foreach (Row row in rows) + { + if (row.Direction == InterfaceDirection.Ref) + continue; + + Dictionary counts = row.Direction == InterfaceDirection.Write ? writers : readers; + foreach (string targetType in row.ObservedTargetTypes) + counts[targetType] = counts.GetValueOrDefault(targetType) + 1; + } + + return writers + .Keys.Where(readers.ContainsKey) + .OrderBy(t => t, StringComparer.Ordinal) + .Select(t => new InterfaceJunction(t, writers[t], readers[t])) + .ToArray(); + } + + /// Every IDREF/IDREFS attribute the DTD declares. + private static IReadOnlyList<(string Element, string Attribute, InterfaceRefKind RefKind)> DeclaredInterfaces( + string dtdPath, + string dtdText + ) + { + SemanticInventory inventory = DtdInventoryReader.Read(dtdPath, dtdText); + var declared = new List<(string, string, InterfaceRefKind)>(); + foreach (InventorySurface surface in inventory.Surfaces) + { + if (surface.Kind != "attribute" || surface.Parent is null) + continue; + + string? type = ParseDeclaredType(surface.Value); + if (type == "IDREF") + declared.Add((surface.Parent, surface.Name, InterfaceRefKind.IdRef)); + else if (type == "IDREFS") + declared.Add((surface.Parent, surface.Name, InterfaceRefKind.IdRefs)); + } + + return declared; + } + + // DtdInventoryReader encodes an "attribute" surface's Value as "type=X;default=Y;fixed=Z"; this + // reads only the leading type field back out. + private static string? ParseDeclaredType(string? value) + { + if (value is null) + return null; + + foreach (string field in value.Split(';')) + { + if (field.StartsWith("type=", StringComparison.Ordinal)) + return field["type=".Length..]; + } + + return null; + } + + private static string[] SplitIdrefs(string value) => + value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + /// + /// Renders the ledger deterministically (element, then attribute) so two runs over an unchanged + /// DTD and corpus byte-for-byte agree -- CheckedInInterfaceInventoryLedgerIsUpToDate depends + /// on this for its drift check. + /// + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine( + "# GENERATED by hc-conformance --write-interface-inventory. One row per IDREF/IDREFS attribute" + ); + writer.WriteLine( + "# declared anywhere in HermitCrabInput.dtd -- a fixed denominator that moves only when the DTD" + ); + writer.WriteLine( + "# changes, never when a fixture is added. observed_target_types is the set of element types the" + ); + writer.WriteLine( + "# attribute's IDREF(S) tokens actually resolved to, across every fixture's own id-to-element map;" + ); + writer.WriteLine( + "# empty when not present. direction (write/read/ref) is SemanticInterfaceDirection's engine-" + ); + writer.WriteLine( + "# checked judgment, not a naming-convention guess -- see its doc comment for what each entry means." + ); + writer.WriteLine( + "# present is STRUCTURAL ONLY -- the attribute resolves to a real IDREF somewhere in fixtures" + ); + writer.WriteLine( + "# (comma-joined, sorted). It is NOT evidence the interface does anything: an attribute can be" + ); + writer.WriteLine("# present and inert. See conformance/interface-witness.tsv for the severance-tested claim."); + writer.WriteLine("element\tattribute\tref_kind\tobserved_target_types\tpresent\tdirection\tfixtures"); + foreach ( + Row row in rows.OrderBy(r => r.Element, StringComparer.Ordinal) + .ThenBy(r => r.Attribute, StringComparer.Ordinal) + ) + { + writer.WriteLine( + string.Join( + '\t', + row.Element, + row.Attribute, + row.RefKind, + string.Join(",", row.ObservedTargetTypes), + row.Present ? "yes" : "no", + row.Direction, + row.Fixtures.Count == 0 ? NullField : string.Join(",", row.Fixtures) + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("element\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[2], out InterfaceRefKind refKind)) + throw new FormatException($"{RelativePath}: unknown ref kind '{fields[2]}'"); + if (fields[4] is not ("yes" or "no")) + throw new FormatException($"{RelativePath}: unknown present flag '{fields[4]}'"); + if (!Enum.TryParse(fields[5], out InterfaceDirection direction)) + throw new FormatException($"{RelativePath}: unknown direction '{fields[5]}'"); + + IReadOnlyList targets = fields[3].Length == 0 ? Array.Empty() : fields[3].Split(','); + IReadOnlyList fixtures = fields[6] is "" or NullField + ? Array.Empty() + : fields[6].Split(','); + rows.Add(new Row(fields[0], fields[1], refKind, targets, fields[4] == "yes", direction, fixtures)); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceWitnessGate.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceWitnessGate.cs new file mode 100644 index 000000000..8cb50b54d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceWitnessGate.cs @@ -0,0 +1,223 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// One severance run: / emptied out of every +/// occurrence in 's grammar, then diffed against that fixture's baseline -- +/// the same counterfactual shape already uses for a unit surface, +/// applied to a declared instead. A row in +/// being present (the attribute resolves to a real IDREF +/// somewhere) is a structural fact; this is the semantic one -- whether severing it ever changes a +/// word's parse. +/// +public sealed record InterfaceWitnessResult( + string Element, + string Attribute, + string FixtureId, + CounterfactualVerdict Verdict, + string Mutation, + string Delta, + string? ExampleWord = null, + string? ExampleOutcome = null, + CounterexampleKind CounterexampleKind = CounterexampleKind.None, + string? CounterexampleOutcome = null +); + +/// +/// Runs severance mutations. Deliberately separate from +/// (which stays a cheap, DTD+presence-only read run on +/// every ordinary test pass): a severance run re-parses every word of every fixture the interface is +/// present in, the same order of cost as , and paying that on +/// every normal build would repeat this repo's own established mistake of taxing ordinary work with an +/// expensive gate. +/// +public static class InterfaceWitnessGate +{ + /// + /// Whether the DTD declares on as + /// #REQUIRED -- read back from 's own "attribute" surface + /// rather than re-parsing the DTD by hand. + /// + public static bool IsRequiredByDtd(SemanticInventory inventory, string element, string attribute) + { + ArgumentNullException.ThrowIfNull(inventory); + InventorySurface? surface = inventory.Surfaces.FirstOrDefault(s => + s.Kind == "attribute" && s.Parent == element && s.Name == attribute + ); + if (surface?.Value is null) + return false; + + foreach (string field in surface.Value.Split(';')) + { + if (field.StartsWith("default=", StringComparison.Ordinal)) + return field["default=".Length..] == "#REQUIRED"; + } + return false; + } + + /// + /// Removes every occurrence of on every in + /// a deep copy of . Returns null if the fixture's grammar carries no such + /// occurrence at all -- the interface is not present there, so there is nothing to sever. + /// + public static XDocument? Sever(XDocument grammar, string element, string attribute, out int removedCount) + { + ArgumentNullException.ThrowIfNull(grammar); + var copy = new XDocument(grammar); + removedCount = 0; + foreach (XElement owner in copy.Descendants(element)) + { + XAttribute? candidate = owner.Attribute(attribute); + if (candidate is null || string.IsNullOrEmpty(candidate.Value)) + continue; + candidate.Remove(); + removedCount++; + } + + return removedCount == 0 ? null : copy; + } + + // Shares CounterfactualGate's constant rather than keeping a second copy that could drift. + private static readonly TimeSpan DefaultTimeout = CounterfactualGate.DefaultTimeout; + + /// + /// Severs . in 's + /// grammar and diffs the reparse against . Both baseline and mutant run + /// through 's killable child process -- unlike + /// a unit-surface neutralization (which trusts an in-process, untimed baseline because it is the + /// fixture's own unmodified grammar), this corpus includes deliberately pathological and + /// expect_crash fixtures, so neither run gets an unprotected path here. + /// + public static InterfaceWitnessResult Evaluate( + Fixture fixture, + string element, + string attribute, + SemanticInventory inventory, + IReadOnlyList baseline, + string scratchDirectory, + TimeSpan? timeout = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(fixture); + ArgumentNullException.ThrowIfNull(inventory); + ArgumentNullException.ThrowIfNull(baseline); + + XDocument grammar = XDocument.Load(fixture.GrammarPath); + XDocument? mutant = Sever(grammar, element, attribute, out int removedCount); + if (mutant is null) + { + return new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + "the fixture does not carry this attribute" + ); + } + + string[] words = fixture.Words.Words.Select(word => word.Word).ToArray(); + TimeSpan effectiveTimeout = timeout ?? DefaultTimeout; + string mutation = $"removed {attribute} from {removedCount} <{element}> element(s)"; + + Directory.CreateDirectory(scratchDirectory); + string mutatedPath = Path.Combine(scratchDirectory, $"witness-{Guid.NewGuid():N}.xml"); + string? dtdSource = Path.Combine(Path.GetDirectoryName(fixture.GrammarPath)!, "HermitCrabInput.dtd"); + if (File.Exists(dtdSource)) + File.Copy(dtdSource, Path.Combine(scratchDirectory, "HermitCrabInput.dtd"), overwrite: true); + + try + { + IReadOnlyList mutated; + try + { + mutant.Save(mutatedPath); + mutated = CounterfactualGate.EvaluateWithTimeout(mutatedPath, words, effectiveTimeout, onWordTimed); + } + catch (TimeoutException) + { + return new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + CounterfactualVerdict.Timeout, + mutation, + $"the mutant did not terminate within {effectiveTimeout.TotalSeconds:0}s" + ); + } + catch (Exception ex) + { + string loadFailure = Summarize($"{ex.GetType().Name}: {ex.Message}"); + CounterfactualVerdict verdict = IsRequiredByDtd(inventory, element, attribute) + ? CounterfactualVerdict.RequiredByDtd + : CounterfactualVerdict.RequiredByLoader; + return new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + verdict, + mutation, + loadFailure, + ExampleWord: words.Length != 0 ? words[0] : null, + ExampleOutcome: words.Length != 0 ? baseline[0] : null, + CounterexampleKind: CounterexampleKind.LoadFailure, + CounterexampleOutcome: loadFailure + ); + } + + for (int i = 0; i < words.Length; i++) + { + if (baseline[i] != mutated[i]) + { + return new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + CounterfactualVerdict.Evidenced, + mutation, + $"'{words[i]}': {baseline[i]} -> {mutated[i]}", + ExampleWord: words[i], + ExampleOutcome: baseline[i], + CounterexampleKind: CounterexampleKind.Word, + CounterexampleOutcome: mutated[i] + ); + } + } + + return new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + CounterfactualVerdict.Unobservable, + mutation, + $"all {words.Length} word(s) unchanged" + ); + } + finally + { + try + { + if (File.Exists(mutatedPath)) + File.Delete(mutatedPath); + } + catch (IOException) + { + // Mirrors CounterfactualGate.RunMutation: a killed timed-out worker may still hold the + // file open, and blocking on that thread is worse than leaving one scratch file behind. + } + } + } + + private static string Summarize(string message) + { + string single = message.Replace('\n', ' ').Replace('\r', ' ').Trim(); + return single.Length <= 120 ? single : single[..120] + "..."; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceWitnessLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceWitnessLedger.cs new file mode 100644 index 000000000..065c39bb7 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InterfaceWitnessLedger.cs @@ -0,0 +1,249 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// The checked-in denominator for interface WITNESS (as opposed to +/// 's presence): one row per (element, attribute, fixture) triple +/// where already recorded the interface as present in that +/// fixture, with the severance verdict reaches for it. +/// Presence only means the attribute resolves to a real IDREF somewhere; it is silent on whether +/// severing it would ever change a parse. This ledger is the machine-checked answer to that question, +/// run the same way already answers it for a unit surface. +/// +public static class InterfaceWitnessLedger +{ + public const string RelativePath = "conformance/interface-witness.tsv"; + + private const string NullField = "-"; + private const int ColumnCount = 10; + + /// + /// Runs for every (element, attribute, fixture) triple + /// marks present. Baseline is computed once per fixture, + /// through the same killable child process the mutant uses (see + /// 's own doc comment for why neither run here gets an + /// unprotected path, unlike a unit-surface neutralization). + /// + public static IReadOnlyList Sweep( + string repositoryRoot, + Action? onFixtureStarted = null, + Action? onWordTimed = null + ) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(repositoryRoot); + IReadOnlyList declared = InterfaceInventoryLedger.Compute(repositoryRoot); + + var byFixture = new Dictionary>(StringComparer.Ordinal); + foreach (InterfaceInventoryLedger.Row row in declared) + { + if (!row.Present) + continue; + foreach (string fixtureId in row.Fixtures) + { + if (!byFixture.TryGetValue(fixtureId, out List<(string, string)>? interfaces)) + { + interfaces = new List<(string, string)>(); + byFixture[fixtureId] = interfaces; + } + interfaces.Add((row.Element, row.Attribute)); + } + } + + string scratch = Path.Combine(Path.GetTempPath(), "hc-interface-witness"); + var results = new List(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance"))) + { + if (!byFixture.TryGetValue(fixture.Id, out List<(string Element, string Attribute)>? interfaces)) + continue; + + onFixtureStarted?.Invoke(fixture.Id, interfaces.Count); + string[] words = fixture.Words.Words.Select(word => word.Word).ToArray(); + + IReadOnlyList baseline; + try + { + baseline = CounterfactualGate.EvaluateWithTimeout( + fixture.GrammarPath, + words, + onTimed: (word, ms) => onWordTimed?.Invoke(word, ms) + ); + } + catch (TimeoutException) + { + foreach ((string element, string attribute) in interfaces) + { + results.Add( + new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + CounterfactualVerdict.Timeout, + "none", + "the fixture's own unmutated baseline did not terminate within the timeout" + ) + ); + } + continue; + } + catch (Exception ex) + { + foreach ((string element, string attribute) in interfaces) + { + results.Add( + new InterfaceWitnessResult( + element, + attribute, + fixture.Id, + CounterfactualVerdict.Unobservable, + "none", + $"the fixture's own unmutated baseline failed to evaluate: {ex.GetType().Name}" + ) + ); + } + continue; + } + + foreach ((string element, string attribute) in interfaces) + { + results.Add( + InterfaceWitnessGate.Evaluate( + fixture, + element, + attribute, + inventory, + baseline, + scratch, + onWordTimed: (word, ms) => onWordTimed?.Invoke(word, ms) + ) + ); + } + } + + return results + .OrderBy(r => r.Element, StringComparer.Ordinal) + .ThenBy(r => r.Attribute, StringComparer.Ordinal) + .ThenBy(r => r.FixtureId, StringComparer.Ordinal) + .ToArray(); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + /// + /// Renders the ledger deterministically (element, attribute, fixture) so two runs over an + /// unchanged DTD and corpus byte-for-byte agree -- the same drift-check contract every other ledger + /// in this directory follows. + /// + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine( + "# GENERATED by hc-conformance --write-coverage-traceability. One row per (element, attribute," + ); + writer.WriteLine( + "# fixture) triple InterfaceInventoryLedger marks present -- i.e. one severance run per place the" + ); + writer.WriteLine("# interface actually shows up. Presence (interface-inventory.tsv) only means the attribute"); + writer.WriteLine( + "# resolves to a real IDREF somewhere; it says nothing about whether the interface DOES anything." + ); + writer.WriteLine( + "# This ledger answers that by emptying the attribute out of every occurrence in the fixture and" + ); + writer.WriteLine("# re-parsing every word against the mutant, exactly as CounterfactualLedger does for a unit"); + writer.WriteLine("# surface. verdict is CounterfactualVerdict: only Evidenced is a word-level witness;"); + writer.WriteLine( + "# RequiredByLoader/RequiredByDtd mean severing it made the grammar fail to load (a real but weaker" + ); + writer.WriteLine( + "# signal -- no word was ever reached); Unobservable means the interface is present but INERT in" + ); + writer.WriteLine("# this fixture -- every word parsed identically with it severed. Absent fields are \"-\"."); + writer.WriteLine( + "element\tattribute\tfixture\tverdict\tmutation\tdelta\texample_word\texample_outcome\tcounterexample_kind\tcounterexample_outcome" + ); + foreach ( + InterfaceWitnessResult row in rows.OrderBy(r => r.Element, StringComparer.Ordinal) + .ThenBy(r => r.Attribute, StringComparer.Ordinal) + .ThenBy(r => r.FixtureId, StringComparer.Ordinal) + ) + { + writer.WriteLine( + string.Join( + '\t', + row.Element, + row.Attribute, + row.FixtureId, + row.Verdict, + row.Mutation, + row.Delta, + row.ExampleWord ?? NullField, + row.ExampleOutcome ?? NullField, + row.CounterexampleKind, + row.CounterexampleOutcome ?? NullField + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("element\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[3], out CounterfactualVerdict verdict)) + throw new FormatException($"{RelativePath}: unknown verdict '{fields[3]}'"); + if (!Enum.TryParse(fields[8], out CounterexampleKind counterexampleKind)) + throw new FormatException($"{RelativePath}: unknown counterexample kind '{fields[8]}'"); + + rows.Add( + new InterfaceWitnessResult( + fields[0], + fields[1], + fields[2], + verdict, + fields[4], + fields[5], + fields[6] == NullField ? null : fields[6], + fields[7] == NullField ? null : fields[7], + counterexampleKind, + fields[9] == NullField ? null : fields[9] + ) + ); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InventoryModels.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InventoryModels.cs new file mode 100644 index 000000000..6eb5acf25 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/InventoryModels.cs @@ -0,0 +1,208 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +public sealed record InventorySurface( + string Id, + string Kind, + string Name, + string? Parent, + string Source, + string? Value = null, + // Comma-joined sorted configuration names, empty when the surface is not + // configuration-scoped. A string keeps record equality by value. + string Configurations = "" +); + +public sealed record InventoryDiagnostic(string Code, string SubjectId, string Message, string Configurations = "") +{ + public InventoryDiagnostic( + string code, + string subjectId, + string message, + IReadOnlyCollection? configurations + ) + : this(code, subjectId, message, JoinConfigurations(configurations)) { } + + public InventoryDiagnostic( + string code, + string subjectId, + string message, + IReadOnlyCollection? configurations, + string location + ) + : this(code, subjectId, message, JoinConfigurations(configurations)) + { + Location = location; + } + + public InventoryDiagnostic(string code, string subjectId, string message, string configurations, string location) + : this(code, subjectId, message, configurations) + { + Location = location; + } + + public string Location { get; init; } = ""; + + private static string JoinConfigurations(IReadOnlyCollection? configurations) => + configurations is null + ? string.Empty + : string.Join( + ",", + configurations + .Where(value => !string.IsNullOrEmpty(value)) + .Distinct(StringComparer.Ordinal) + .OrderBy(value => value, StringComparer.Ordinal) + ); +} + +public sealed record SemanticInventory +{ + public SemanticInventory( + string profile, + string sourceHash, + IReadOnlyList surfaces, + IReadOnlyList? diagnostics = null + ) + { + Profile = profile; + SourceHash = sourceHash; + Surfaces = surfaces; + Diagnostics = new ReadOnlyCollection( + (diagnostics ?? Array.Empty()).ToList() + ); + } + + public string Profile { get; init; } + + public string SourceHash { get; init; } + + public IReadOnlyList Surfaces { get; init; } + + public IReadOnlyList Diagnostics { get; init; } +} + +public sealed record CSharpInventoryInput +{ + public CSharpInventoryInput(string relativePath, string sourceText, IReadOnlyList? auditedScopes = null) + { + ArgumentException.ThrowIfNullOrEmpty(relativePath); + ArgumentNullException.ThrowIfNull(sourceText); + ValidateRelativePath(relativePath); + RelativePath = relativePath.Replace('\\', '/'); + SourceText = sourceText; + var scopes = auditedScopes ?? Array.Empty(); + if (scopes.Any(string.IsNullOrEmpty)) + { + throw new ArgumentException("Audited source scopes cannot be null or empty.", nameof(auditedScopes)); + } + + AuditedScopes = new ReadOnlyCollection( + scopes.Distinct(StringComparer.Ordinal).OrderBy(scope => scope, StringComparer.Ordinal).ToList() + ); + } + + public string RelativePath { get; } + + public string SourceText { get; } + + public IReadOnlyList AuditedScopes { get; } + + private static void ValidateRelativePath(string path) + { + if ( + Uri.TryCreate(path, UriKind.Absolute, out _) + || path.StartsWith("/", StringComparison.Ordinal) + || path.StartsWith("\\", StringComparison.Ordinal) + || (path.Length >= 2 && path[1] == ':') + ) + { + throw new ArgumentException("C# source paths must be canonical relative paths.", nameof(path)); + } + + string[] segments = path.Replace('\\', '/').Split('/'); + if (segments.Any(segment => segment is "." or ".." or "")) + { + throw new ArgumentException("C# source paths cannot contain '.', '..', or empty segments.", nameof(path)); + } + } +} + +/// Assembly names whose sources are present in full. Only such a +/// project may be dropped from the census reference set; a partial source set still needs its own +/// built assembly to resolve the files it does not carry. +public sealed record SemanticCoverageSourceSet( + string DtdPath, + string DtdText, + IReadOnlyList CSharpSources, + string ToolchainFingerprint = "", + IReadOnlyList? CompleteProjects = null +) +{ + public static SemanticCoverageSourceSet FromDtd(string path, string text) => + new(path, text, Array.Empty()); +} + +public sealed class SemanticCoverageParseException(string sourcePath, int line, int column, string detail) + : FormatException($"{sourcePath}:{line}:{column}: {detail}") +{ + public string SourcePath { get; } = sourcePath; + + public int Line { get; } = line; + + public int Column { get; } = column; +} + +internal static class CanonicalIdCodec +{ + public static string Encode(string authoredValue) + { + ArgumentNullException.ThrowIfNull(authoredValue); + var builder = new StringBuilder(); + foreach (byte value in Encoding.UTF8.GetBytes(authoredValue)) + { + if ( + (value >= 'A' && value <= 'Z') + || (value >= 'a' && value <= 'z') + || (value >= '0' && value <= '9') + || value is (byte)'-' or (byte)'.' or (byte)'_' or (byte)'~' + ) + { + builder.Append((char)value); + } + else + { + builder.Append('%').Append(value.ToString("X2")); + } + } + + return builder.ToString(); + } +} + +internal static class InventorySurfaceFactory +{ + public static IReadOnlyList Sort(IEnumerable surfaces) + { + var ids = new HashSet(StringComparer.Ordinal); + var ordered = new List(); + foreach (InventorySurface surface in surfaces) + { + if (!ids.Add(surface.Id)) + { + throw new InvalidOperationException($"Duplicate generated surface ID: {surface.Id}"); + } + + ordered.Add(surface); + } + + return new ReadOnlyCollection( + ordered.OrderBy(surface => surface.Id, StringComparer.Ordinal).ToList() + ); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/LogicalPathTokens.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/LogicalPathTokens.cs new file mode 100644 index 000000000..4b84225dd --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/LogicalPathTokens.cs @@ -0,0 +1,270 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record LogicalPathRoots +{ + internal LogicalPathRoots(string repositoryRoot, string sdkRoot, string nugetRoot, string generatedRoot) + : this(repositoryRoot, sdkRoot, new[] { nugetRoot }, generatedRoot) { } + + internal LogicalPathRoots( + string repositoryRoot, + string sdkRoot, + IReadOnlyList nugetRoots, + string generatedRoot + ) + { + RepositoryRoot = RequireAbsolute(repositoryRoot, nameof(repositoryRoot)); + SdkRoot = RequireAbsolute(sdkRoot, nameof(sdkRoot)); + ArgumentNullException.ThrowIfNull(nugetRoots); + if (nugetRoots.Count == 0) + throw new ArgumentException("At least one NuGet root is required.", nameof(nugetRoots)); + NuGetRoots = nugetRoots + .Select((root, index) => RequireAbsolute(root, $"{nameof(nugetRoots)}[{index}]")) + .ToImmutableArray(); + GeneratedRoot = RequireAbsolute(generatedRoot, nameof(generatedRoot)); + + var roots = new[] { RepositoryRoot, SdkRoot, GeneratedRoot }.Concat(NuGetRoots).ToArray(); + if (roots.Length != roots.Distinct(StringComparer.OrdinalIgnoreCase).Count()) + throw new InvalidDataException("Logical path roots must be distinct."); + for (int i = 0; i < roots.Length; i++) + { + for (int j = i + 1; j < roots.Length; j++) + { + if (LogicalPathTokens.IsFilesystemRoot(roots[i]) || LogicalPathTokens.IsFilesystemRoot(roots[j])) + continue; + if (LogicalPathTokens.IsUnder(roots[i], roots[j]) || LogicalPathTokens.IsUnder(roots[j], roots[i])) + throw new InvalidDataException("Logical path roots must be disjoint and unambiguous."); + } + } + } + + internal string RepositoryRoot { get; } + internal string SdkRoot { get; } + internal ImmutableArray NuGetRoots { get; } + internal string NuGetRoot => NuGetRoots[0]; + internal string GeneratedRoot { get; } + + private static string RequireAbsolute(string path, string parameterName) + { + if (string.IsNullOrWhiteSpace(path) || !LogicalPathTokens.IsAbsolute(path)) + throw new ArgumentException("A logical path root must be absolute.", parameterName); + return LogicalPathTokens.NormalizeAbsolute(path); + } +} + +internal static class LogicalPathTokens +{ + private const string AncestorEditorConfigToken = "ancestor-editorconfig"; + private const string EditorConfigFileName = ".editorconfig"; + + internal static bool IsLogicalPath(string path) => IsLogicalPathCore(path, out _); + + private static bool IsLogicalPathCore(string path, out string? token) + { + if (string.IsNullOrWhiteSpace(path)) + { + token = null; + return false; + } + token = new[] { "repo:/", "sdk:/", "nuget:/", "generated:/", AncestorEditorConfigToken + ":/" }.FirstOrDefault( + candidate => path.StartsWith(candidate, StringComparison.Ordinal) + ); + if (token is null || path.Contains('\\')) + return false; + string remainder = path[token.Length..]; + return remainder.Length == 0 + || ( + !remainder.StartsWith("/", StringComparison.Ordinal) + && !remainder.EndsWith("/", StringComparison.Ordinal) + && !remainder.Split('/').Any(segment => segment is "" or "." or "..") + ); + } + + internal static string FromAbsolute(string absolutePath, LogicalPathRoots roots) + { + ArgumentException.ThrowIfNullOrWhiteSpace(absolutePath); + ArgumentNullException.ThrowIfNull(roots); + + string normalized = NormalizeAbsolute(absolutePath); + var candidates = new List<(string Name, string Root, string? PackageId, string? Version)>(); + candidates.Add(("repo", roots.RepositoryRoot, null, null)); + candidates.Add(("sdk", roots.SdkRoot, null, null)); + candidates.Add(("generated", roots.GeneratedRoot, null, null)); + foreach (string nugetRoot in roots.NuGetRoots) + { + if (!IsUnder(normalized, nugetRoot)) + continue; + string relativeToRoot = + normalized.Length == nugetRoot.Length ? string.Empty : normalized[(nugetRoot.Length + 1)..]; + string[] segments = relativeToRoot.Split('/', StringSplitOptions.RemoveEmptyEntries); + if (segments.Length < 2 || !IsPackageId(segments[0]) || !IsPackageVersion(segments[1])) + { + throw new InvalidDataException( + $"NuGet path '{absolutePath}' is not decomposable into package ID and version." + ); + } + candidates.Add(("nuget", nugetRoot, segments[0], segments[1])); + } + + (string Name, string Root)[] matches = candidates + .Where(candidate => + candidate.Name != "nuget" && IsUnder(normalized, candidate.Root) || candidate.Name == "nuget" + ) + .OrderByDescending(candidate => candidate.Root.Length) + .Select(candidate => (candidate.Name, candidate.Root)) + .ToArray(); + if (matches.Length == 0) + throw new InvalidDataException($"Path '{absolutePath}' is outside all admitted logical roots."); + (string Name, string Root) match = matches[0]; + + bool rootIsSeparator = match.Root.EndsWith("/", StringComparison.Ordinal); + string relative = + normalized.Length == match.Root.Length + ? string.Empty + : normalized[(match.Root.Length + (rootIsSeparator ? 0 : 1))..]; + if (match.Name == "nuget") + { + string[] segments = relative.Split('/', StringSplitOptions.RemoveEmptyEntries); + relative = string.Join('/', segments); + } + return relative.Length == 0 ? match.Name + ":/" : match.Name + ":/" + relative; + } + + /// + /// Resolves like , but also admits an ancestor `.editorconfig`: MSBuild's + /// EditorConfigFiles item walks up from the project to every ancestor directory, which can land + /// outside every admitted root when a repository is checked out inside another one (this + /// repository's own worktree layout does exactly that). Such a file's content still affects + /// compilation and must be hashed, but admitting it by physical path would break relocation + /// invariance, so it is identified only by how many directory levels separate it from the + /// repository root. Everything else that falls outside the admitted roots still fails closed. + /// + internal static string FromAbsoluteAdmittingAncestorEditorConfig(string absolutePath, LogicalPathRoots roots) + { + try + { + return FromAbsolute(absolutePath, roots); + } + catch (InvalidDataException) + when (TryAncestorEditorConfigToken(absolutePath, roots.RepositoryRoot, out string? token)) + { + return token!; + } + } + + private static bool TryAncestorEditorConfigToken( + string absolutePath, + string repositoryRoot, + out string? logicalPath + ) + { + logicalPath = null; + // Segment the path with this class's own separator handling rather than Path.GetFileName, + // whose notion of a separator is the host's: a Windows-shaped path is admitted on Unix too. + if (!IsAbsolute(absolutePath) || HasTraversalSegment(absolutePath)) + return false; + + string[] fileSegments = NormalizeAbsolute(absolutePath).Split('/'); + if ( + fileSegments.Length < 2 + || !string.Equals(fileSegments[^1], EditorConfigFileName, StringComparison.OrdinalIgnoreCase) + ) + { + return false; + } + string[] parentSegments = fileSegments[..^1]; + string[] repositorySegments = repositoryRoot.Split('/'); + if ( + parentSegments.Length >= repositorySegments.Length + || !parentSegments + .AsSpan() + .SequenceEqual(repositorySegments.AsSpan(0, parentSegments.Length), StringComparer.OrdinalIgnoreCase) + ) + { + return false; + } + + logicalPath = $"{AncestorEditorConfigToken}:/{repositorySegments.Length - parentSegments.Length}"; + return true; + } + + private static bool IsPackageId(string value) => + !string.IsNullOrWhiteSpace(value) + && value.IndexOfAny(new[] { '/', '\\', ':', '*', '?', '"', '<', '>', '|' }) < 0; + + private static bool IsPackageVersion(string value) => + IsPackageId(value) && char.IsDigit(value[0]) && value.Any(char.IsLetterOrDigit); + + internal static void ValidateUnique(IEnumerable logicalPaths) + { + ArgumentNullException.ThrowIfNull(logicalPaths); + var seen = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (string? path in logicalPaths) + { + if (string.IsNullOrWhiteSpace(path)) + throw new InvalidDataException($"Logical paths contain a case-insensitive collision at '{path}'."); + if (seen.ContainsKey(path)) + { + throw new InvalidDataException($"Logical paths contain a case-insensitive collision at '{path}'."); + } + seen[path] = path; + } + } + + internal static string NormalizeAbsolute(string path) + { + ArgumentException.ThrowIfNullOrWhiteSpace(path); + if (!IsAbsolute(path)) + throw new InvalidDataException($"Path '{path}' is not absolute."); + if (HasTraversalSegment(path)) + throw new InvalidDataException($"Path '{path}' contains a traversal segment."); + + string normalized = path.Replace('\\', '/'); + bool isDriveRoot = normalized.Length >= 3 && normalized[1] == ':' && normalized[2] == '/'; + normalized = TrimTrailingSeparators(normalized, isDriveRoot); + return normalized; + } + + internal static bool IsAbsolute(string path) + { + if (string.IsNullOrWhiteSpace(path)) + return false; + return path.StartsWith("/", StringComparison.Ordinal) + || (path.Length >= 3 && char.IsLetter(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) + || path.StartsWith("//", StringComparison.Ordinal) + || path.StartsWith("\\\\", StringComparison.Ordinal); + } + + internal static bool IsUnder(string path, string root) => + path.Equals(root, StringComparison.OrdinalIgnoreCase) + || ( + path.Length > root.Length + && path.StartsWith(root, StringComparison.OrdinalIgnoreCase) + && (root.EndsWith("/", StringComparison.Ordinal) || path[root.Length] == '/') + ); + + internal static bool IsFilesystemRoot(string path) => + path == "/" || (path.Length == 3 && path[1] == ':' && path[2] == '/'); + + private static bool HasTraversalSegment(string path) => + path.Replace('\\', '/').Split('/').Any(segment => segment is "." or ".."); + + private static string TrimTrailingSeparators(string path, bool isDriveRoot) + { + int length = path.Length; + while (length > 0 && path[length - 1] == '/') + length--; + if (length == 0) + return "/"; + if (isDriveRoot && length == 2) + return path[..3]; + return path[..length]; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MsBuildCaptureProtocol.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MsBuildCaptureProtocol.cs new file mode 100644 index 000000000..f5f883623 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MsBuildCaptureProtocol.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record CapturedCompilerItem(string Identity, IReadOnlyDictionary Metadata); + +internal sealed record CapturedCompilerInputs( + IReadOnlyDictionary Properties, + IReadOnlyDictionary> Items +); + +internal static class MsBuildCaptureProtocol +{ + internal const string Version = "hc-semantic-msbuild/v1"; + + private static readonly string[] RequiredProperties = + { + "PanGlossCompilerInputProtocol", + "MSBuildAllProjects", + "AssemblyName", + "TargetFramework", + "LangVersion", + "Nullable", + "DefineConstants", + "AllowUnsafeBlocks", + "CheckForOverflowUnderflow", + "OutputType", + "NETCoreSdkVersion", + "MSBuildVersion", + "CscToolPath", + "RoslynAssembliesPath", + "GeneratedAssemblyInfoFile", + "TargetFrameworkMonikerAssemblyAttributesPath", + }; + + private static readonly string[] RequiredItemFamilies = + { + "CscCommandLineArgs", + "Compile", + "ProjectReference", + "ReferencePathWithRefAssemblies", + "Analyzer", + "AdditionalFiles", + "EditorConfigFiles", + "Using", + }; + + internal static CapturedCompilerInputs Parse(ReadOnlySpan utf8Json) + { + if (utf8Json.IsEmpty) + throw new InvalidDataException("MSBuild capture output is empty."); + + using JsonDocument document = ParseDocument(utf8Json); + JsonElement root = document.RootElement; + if (root.ValueKind != JsonValueKind.Object) + throw new InvalidDataException("MSBuild capture output must be a JSON object."); + + JsonElement properties = RequiredObject(root, "Properties"); + JsonElement items = RequiredObject(root, "Items"); + var propertyValues = new Dictionary(StringComparer.Ordinal); + foreach (string name in RequiredProperties) + { + JsonElement value = RequiredProperty(properties, name); + if (value.ValueKind != JsonValueKind.String) + throw new InvalidDataException($"MSBuild property '{name}' must be a string."); + propertyValues.Add( + name, + value.GetString() ?? throw new InvalidDataException($"MSBuild property '{name}' is null.") + ); + } + + if (!string.Equals(propertyValues["PanGlossCompilerInputProtocol"], Version, StringComparison.Ordinal)) + { + throw new InvalidDataException( + $"Unexpected MSBuild capture protocol '{propertyValues["PanGlossCompilerInputProtocol"]}'." + ); + } + + foreach (JsonProperty property in items.EnumerateObject()) + { + if ( + !Array.Exists( + RequiredItemFamilies, + family => string.Equals(family, property.Name, StringComparison.Ordinal) + ) + ) + { + throw new InvalidDataException($"Unknown MSBuild item family '{property.Name}'."); + } + } + + var itemValues = new Dictionary>(StringComparer.Ordinal); + foreach (string family in RequiredItemFamilies) + { + JsonElement familyValue = RequiredProperty(items, family); + if (familyValue.ValueKind != JsonValueKind.Array) + throw new InvalidDataException($"MSBuild item family '{family}' must be an array."); + + var parsed = new List(); + foreach (JsonElement item in familyValue.EnumerateArray()) + { + if (item.ValueKind != JsonValueKind.Object) + throw new InvalidDataException($"MSBuild item family '{family}' contains a non-object item."); + JsonElement identity = RequiredProperty(item, "Identity"); + if (identity.ValueKind != JsonValueKind.String || string.IsNullOrEmpty(identity.GetString())) + { + throw new InvalidDataException( + $"MSBuild item family '{family}' contains a null or empty Identity." + ); + } + + var metadata = new Dictionary(StringComparer.Ordinal); + foreach (JsonProperty property in item.EnumerateObject()) + { + if (property.NameEquals("Identity")) + continue; + if (property.Value.ValueKind != JsonValueKind.String) + { + throw new InvalidDataException( + $"Metadata '{property.Name}' on item family '{family}' must be a string." + ); + } + metadata.Add( + property.Name, + property.Value.GetString() + ?? throw new InvalidDataException($"Metadata '{property.Name}' is null.") + ); + } + + parsed.Add(new CapturedCompilerItem(identity.GetString()!, metadata)); + } + + itemValues.Add(family, parsed); + } + + return new CapturedCompilerInputs(propertyValues, itemValues); + } + + private static JsonDocument ParseDocument(ReadOnlySpan utf8Json) + { + try + { + var reader = new Utf8JsonReader(utf8Json, isFinalBlock: true, state: default); + EnsureNoDuplicateProperties(ref reader); + return JsonDocument.Parse(utf8Json.ToArray()); + } + catch (JsonException exception) + { + throw new InvalidDataException("MSBuild capture output is not valid UTF-8 JSON.", exception); + } + } + + private static void EnsureNoDuplicateProperties(ref Utf8JsonReader reader) + { + var objectPropertyNames = new Stack>(); + int rootValues = 0; + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.StartObject) + { + if (objectPropertyNames.Count == 0) + { + rootValues++; + } + objectPropertyNames.Push(new HashSet(StringComparer.Ordinal)); + } + else if (reader.TokenType == JsonTokenType.StartArray) + { + if (objectPropertyNames.Count == 0) + { + rootValues++; + } + } + else if (reader.TokenType == JsonTokenType.PropertyName) + { + if (objectPropertyNames.Count == 0 || !objectPropertyNames.Peek().Add(reader.GetString()!)) + { + throw new InvalidDataException($"Duplicate JSON property '{reader.GetString()}'."); + } + } + else if (reader.TokenType == JsonTokenType.EndObject) + { + objectPropertyNames.Pop(); + } + } + + if (rootValues != 1 || objectPropertyNames.Count != 0) + throw new InvalidDataException("MSBuild capture output must contain exactly one complete JSON value."); + } + + private static JsonElement RequiredObject(JsonElement parent, string name) + { + JsonElement value = RequiredProperty(parent, name); + if (value.ValueKind != JsonValueKind.Object) + throw new InvalidDataException($"MSBuild capture member '{name}' must be an object."); + return value; + } + + private static JsonElement RequiredProperty(JsonElement parent, string name) + { + if (!parent.TryGetProperty(name, out JsonElement value)) + throw new InvalidDataException($"MSBuild capture member '{name}' is missing."); + return value; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MsBuildProcessRunner.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MsBuildProcessRunner.cs new file mode 100644 index 000000000..1721f770e --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MsBuildProcessRunner.cs @@ -0,0 +1,134 @@ +#nullable enable + +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record ProcessCapture(int ExitCode, byte[] StandardOutput, string StandardError); + +internal interface IMsBuildProcessRunner +{ + ValueTask RunAsync( + ProcessStartInfo startInfo, + TimeSpan timeout, + int maxStandardOutputBytes, + CancellationToken cancellationToken + ); +} + +internal sealed class MsBuildProcessRunner : IMsBuildProcessRunner +{ + public async ValueTask RunAsync( + ProcessStartInfo startInfo, + TimeSpan timeout, + int maxStandardOutputBytes, + CancellationToken cancellationToken + ) + { + ArgumentNullException.ThrowIfNull(startInfo); + if (startInfo.UseShellExecute || !startInfo.RedirectStandardOutput || !startInfo.RedirectStandardError) + throw new ArgumentException("MSBuild must run shell-free with redirected output.", nameof(startInfo)); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(timeout, TimeSpan.Zero); + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(maxStandardOutputBytes); + + using var process = new Process { StartInfo = startInfo }; + try + { + if (!process.Start()) + throw new InvalidDataException("MSBuild process did not start."); + } + catch (Exception exception) when (exception is not InvalidDataException) + { + throw new InvalidDataException("MSBuild process could not be started.", exception); + } + + Task stdout = ReadBoundedAsync( + process.StandardOutput.BaseStream, + maxStandardOutputBytes, + cancellationToken + ); + Task stderr = process.StandardError.ReadToEndAsync(cancellationToken); + using var timeoutSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + timeoutSource.CancelAfter(timeout); + Task exit = process.WaitForExitAsync(timeoutSource.Token); + try + { + Task completed = await Task.WhenAny(exit, stdout).ConfigureAwait(false); + if (completed == stdout) + { + await stdout.ConfigureAwait(false); + await exit.ConfigureAwait(false); + } + else + { + await exit.ConfigureAwait(false); + } + } + catch (OperationCanceledException exception) when (!cancellationToken.IsCancellationRequested) + { + TryTerminate(process); + throw new InvalidDataException($"MSBuild exceeded the {timeout.TotalSeconds:0}-second timeout.", exception); + } + catch + { + TryTerminate(process); + throw; + } + + byte[] output; + try + { + output = await stdout.ConfigureAwait(false); + } + catch + { + TryTerminate(process); + throw; + } + return new ProcessCapture(process.ExitCode, output, await stderr.ConfigureAwait(false)); + } + + private static async Task ReadBoundedAsync( + Stream stream, + int maximumBytes, + CancellationToken cancellationToken + ) + { + using var output = new MemoryStream(); + byte[] buffer = new byte[81920]; + while (true) + { + int read = await stream + .ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken) + .ConfigureAwait(false); + if (read == 0) + return output.ToArray(); + if (output.Length + read > maximumBytes) + throw new InvalidDataException($"MSBuild standard output exceeded {maximumBytes} bytes."); + output.Write(buffer, 0, read); + } + } + + private static void TryTerminate(Process process) + { + try + { + if (!process.HasExited) + process.Kill(entireProcessTree: true); + if (!process.WaitForExit(5000) || !process.HasExited) + throw new InvalidDataException("MSBuild process-tree termination could not be confirmed."); + } + catch (InvalidDataException) + { + throw; + } + catch (Exception exception) + { + throw new InvalidDataException("MSBuild process-tree termination could not be confirmed.", exception); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MutatorClassDetectors.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MutatorClassDetectors.cs new file mode 100644 index 000000000..243d64e4e --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/MutatorClassDetectors.cs @@ -0,0 +1,173 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Structural (XML-static) detectors for the three members +/// declared but never checked against corpus content: +/// , , +/// ( +/// already has one -- , reused unmodified from +/// ). Each detector answers a NECESSARY-condition question about an +/// exercising fixture's grammar.xml -- "does this fixture even contain the construct the engine mechanism +/// needs to fire at all" -- never a sufficient/temporal-ordering proof. That is the same rigor +/// already applies to : +/// presence of the construct is a HAZARD signal, not a proof that some specific derivation actually routes +/// through it at the point where it would matter. A finding of "absent" IS definitive here (the cited +/// engine guard literally cannot fire without the construct), so +/// reports that as such; a finding of "present" only ever raises a cell to the same +/// Overwrite's own Hazardous rows already carry -- never +/// , which stays reserved for a same-word pair witness. +/// +internal static class MutatorClassDetectors +{ + private static XDocument? TryLoadGrammar(string repositoryRoot, string fixtureId) + { + string path = Path.Combine( + repositoryRoot, + "conformance", + fixtureId.Replace('/', Path.DirectorySeparatorChar), + "grammar.xml" + ); + return File.Exists(path) ? XDocument.Load(path) : null; + } + + /// + /// Scans in order and returns the first one whose grammar + /// satisfies , or null if none does. + /// + public static (bool Found, string? FixtureId) ScanForAny( + string repositoryRoot, + IReadOnlyList exercisingFixtures, + Func predicate + ) + { + foreach (string fixtureId in exercisingFixtures) + { + XDocument? grammar = TryLoadGrammar(repositoryRoot, fixtureId); + if (grammar != null && predicate(grammar)) + return (true, fixtureId); + } + return (false, null); + } + + /// Scans every exercising fixture and returns the largest count + /// finds, and which fixture realizes it (ties keep the first, matching the chain's own sorted + /// exercising-fixture order). + public static (int MaxCount, string? FixtureId) ScanForMax( + string repositoryRoot, + IReadOnlyList exercisingFixtures, + Func counter + ) + { + int best = 0; + string? bestFixture = null; + foreach (string fixtureId in exercisingFixtures) + { + XDocument? grammar = TryLoadGrammar(repositoryRoot, fixtureId); + if (grammar == null) + continue; + int count = counter(grammar); + if (count > best) + { + best = count; + bestFixture = fixtureId; + } + } + return (best, bestFixture); + } + + /// + /// 's operative precondition: Word.CheckBlocking + /// (Word.cs:472-497) returns false immediately unless the current root's LexEntry.Family is + /// non-null, which XmlLanguageLoader (line 460-464) populates only when this entry's + /// family IDREF names a <Family> shared by at least one OTHER + /// <LexicalEntry>. CheckBlocking also requires the sibling to share this word's + /// current Stratum (Word.cs:483), and LexicalEntry is only ever declared directly under + /// one <Stratum> (DTD: Stratum -> LexicalEntries -> LexicalEntry), so two + /// siblings sharing a family AND a nearest <Stratum> ancestor is exactly this + /// precondition, minus the one fact static XML cannot resolve: whether the current word's + /// SyntacticFeatureStruct actually Subsumes the sibling's (Word.cs:484) -- a runtime + /// fact over resolved feature structures, not decidable from the raw attribute strings alone. + /// + public static bool HasEligibleFamily(XDocument grammar) + { + ArgumentNullException.ThrowIfNull(grammar); + + var byFamily = new Dictionary>(StringComparer.Ordinal); + foreach (XElement entry in grammar.Descendants("LexicalEntry")) + { + string? family = (string?)entry.Attribute("family"); + if (string.IsNullOrEmpty(family)) + continue; + + if (!byFamily.TryGetValue(family, out List? entries)) + { + entries = new List(); + byFamily[family] = entries; + } + entries.Add(entry); + } + + foreach (List entries in byFamily.Values) + { + var byStratum = entries + .Select(e => e.Ancestors("Stratum").FirstOrDefault()) + .Where(s => s != null) + .GroupBy(s => s); + if (byStratum.Any(g => g.Count() >= 2)) + return true; + } + + return false; + } + + /// + /// 's operative precondition: the + /// PriorityUnion call (SynthesisAffixProcessRule.cs:181-182, + /// SynthesisCompoundingRule.cs:181-182) runs unconditionally on every MorphologicalRule/ + /// CompoundingRule application, but is a no-op whenever that rule's own + /// outputPartOfSpeech is empty -- so the mutator only ever has an effect where the fixture + /// contains a POS-writing rule to DO the clobbering. Counts every <MorphologicalRule>/ + /// <CompoundingRule> element with a non-empty outputPartOfSpeech in the fixture + /// (not just the chain's own writer/reader rule, which this static scan cannot single out by + /// instance identity). + /// + public static int CountPosWritingRuleElements(XDocument grammar) + { + ArgumentNullException.ThrowIfNull(grammar); + + int count = 0; + foreach (string elementName in new[] { "MorphologicalRule", "CompoundingRule" }) + { + foreach (XElement rule in grammar.Descendants(elementName)) + { + if (!string.IsNullOrEmpty((string?)rule.Attribute("outputPartOfSpeech"))) + count++; + } + } + return count; + } + + /// + /// 's entire operative precondition: + /// SynthesisCompoundingRule.ApplySubrule (SynthesisCompoundingRule.cs:236) builds its output + /// from headMatch.Input.Clone() alone, so the non-head's whole MprFeatureSet -- however + /// it was written (LexicalEntry.ruleFeatures, a prior MorphologicalOutput.MPRFeatures + /// write, or a prior CompoundingRule.outputProdRestrictionsMprFeatures write) -- is dropped in + /// one step, unconditionally, the moment that word is consumed as a non-head. No overwrite group, no + /// feature match, nothing else is needed for the drop itself to fire, so the presence of at least one + /// <CompoundingRule> (DTD-mandatory >=1 CompoundingSubrule, hence >=1 + /// HeadMorphologicalInput/NonHeadMorphologicalInput pair) is the whole precondition. + /// + public static bool HasCompoundingRule(XDocument grammar) + { + ArgumentNullException.ThrowIfNull(grammar); + return grammar.Descendants("CompoundingRule").Any(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/NeverFiresProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/NeverFiresProofs.cs new file mode 100644 index 000000000..c63d53e13 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/NeverFiresProofs.cs @@ -0,0 +1,292 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind : one member of a Stratum +/// phonologicalRules adjacent pair is a PhonologicalRule that can never fire in any +/// derivation, so its position in the rule list is a no-op regardless of which sibling it sits next to. +/// A rule can never fire when either its shared PhoneticInput, or every one of its active +/// PhonologicalSubrules' LeftEnvironment/RightEnvironment, requires a natural class +/// that resolves to zero active segments -- counting only active FeatureValue/SegmentDefinition +/// declarations, mirroring XmlLanguageLoader's own filtering. Only a DIRECT SimpleContext child +/// of a PhoneticSequence is checked; one nested inside an OptionalSegmentSequence is never +/// required (the option can simply not match), so an empty class there does not make the sequence +/// unmatchable and is deliberately ignored rather than risking a false "can never fire". +/// +public static class NeverFiresProofs +{ + public const string Kind = "never-fires"; + + /// Builds a proof for , or null when neither + /// member is provably dead. + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + NeverFiresCheck check = Check(grammar, item); + return check.CertifiesDead ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies : true only when 's freshly + /// generated adjacent pairs still contain an item with 's id AND at least one + /// current member still resolves to a permanently dead rule. A stale id, a reactivated + /// FeatureValue, and a newly-added qualifying segment all fail closed to false. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return Check(grammar, item).CertifiesDead; + } + + private sealed record NeverFiresCheck(string ItemId, bool CertifiesDead, string Reason); + + private static NeverFiresCheck Check(XDocument grammar, OrderingItem item) + { + if (item.Kind != OrderingListKind.StratumPhonologicalRules) + { + return new NeverFiresCheck( + item.Id, + false, + $"{item.Kind} pairs are not modeled -- this check only resolves a PhonologicalRule's " + + "PhoneticInput/Environment natural classes" + ); + } + + (bool deadA, string reasonA) = RuleNeverFires(grammar, item.MemberA); + if (deadA) + return new NeverFiresCheck(item.Id, true, $"'{item.MemberA}' can never fire: {reasonA}"); + + (bool deadB, string reasonB) = RuleNeverFires(grammar, item.MemberB); + if (deadB) + return new NeverFiresCheck(item.Id, true, $"'{item.MemberB}' can never fire: {reasonB}"); + + return new NeverFiresCheck( + item.Id, + false, + $"neither '{item.MemberA}' nor '{item.MemberB}' resolves to a PhoneticInput or active-subrule " + + "Environment naming a natural class with zero active qualifying segments" + ); + } + + // A rule never fires when its shared input can never match, or every one of its active subrules is + // individually dead (an environment side names an empty class). A rule with an active subrule that + // has NO Environment at all fires unconditionally wherever the input matches, so it is never dead by + // this mechanism. + private static (bool IsDead, string Reason) RuleNeverFires(XDocument grammar, string ruleId) + { + XElement? rule = FindElementById(grammar, ruleId); + if (rule is null || rule.Name.LocalName != "PhonologicalRule") + return (false, $"'{ruleId}' is not a in the current document"); + + XElement? inputSequence = rule.Element("PhoneticInput")?.Element("PhoneticSequence"); + if (TryFindEmptyDirectClass(inputSequence, grammar, out string? inputReason)) + { + return ( + true, + $"PhoneticInput requires {inputReason}, which resolves to zero active segments -- no site can ever match" + ); + } + + List subrules = + rule.Element("PhonologicalSubrules")?.Elements("PhonologicalSubrule").Where(IsActiveElement).ToList() + ?? new List(); + if (subrules.Count == 0) + return (false, "has no active PhonologicalSubrule -- not modeled by this check"); + + var deadReasons = new List(); + foreach (XElement subrule in subrules) + { + XElement? environment = subrule.Element("Environment"); + if (environment is null) + { + return ( + false, + "an active subrule has no Environment at all, so it fires unconditionally wherever the input matches" + ); + } + + XElement? left = environment + .Element("LeftEnvironment") + ?.Element("PhoneticTemplate") + ?.Element("PhoneticSequence"); + if (TryFindEmptyDirectClass(left, grammar, out string? leftReason)) + { + deadReasons.Add($"LeftEnvironment requires {leftReason}"); + continue; + } + + XElement? right = environment + .Element("RightEnvironment") + ?.Element("PhoneticTemplate") + ?.Element("PhoneticSequence"); + if (TryFindEmptyDirectClass(right, grammar, out string? rightReason)) + { + deadReasons.Add($"RightEnvironment requires {rightReason}"); + continue; + } + + return ( + false, + "an active subrule's Environment does not name a natural class with zero active segments on either side" + ); + } + + return (true, string.Join("; ", deadReasons) + ", each of which resolves to zero active segments"); + } + + /// + /// True when a DIRECT (non-optional) SimpleContext child of names a + /// natural class that fully resolves to zero active segments. Never descends into + /// OptionalSegmentSequence -- an empty class there is never required, so it cannot make the + /// sequence itself unmatchable. An absent (e.g. an epenthesis rule's empty + /// input) is never empty-by-class -- it is unconditioned, not impossible. + /// + private static bool TryFindEmptyDirectClass(XElement? sequence, XDocument grammar, out string? reason) + { + reason = null; + if (sequence is null) + return false; + + foreach (XElement child in sequence.Elements()) + { + if (child.Name.LocalName != "SimpleContext") + continue; + + string? naturalClassId = (string?)child.Attribute("naturalClass"); + if (naturalClassId is null) + continue; + + ClassResolution resolution = ResolveNaturalClass(naturalClassId, grammar); + if (resolution.IsResolved && resolution.Members.Count == 0) + { + reason = $"natural class '{naturalClassId}'"; + return true; + } + } + return false; + } + + private readonly record struct ClassResolution(bool IsResolved, IReadOnlySet Members) + { + public static ClassResolution Ok(IEnumerable members) => + new(true, members.ToHashSet(StringComparer.Ordinal)); + + public static ClassResolution No() => new(false, new HashSet()); + } + + private static ClassResolution ResolveNaturalClass(string naturalClassId, XDocument grammar) + { + XElement? segmentClass = grammar + .Descendants("SegmentNaturalClass") + .FirstOrDefault(e => (string?)e.Attribute("id") == naturalClassId); + if (segmentClass is not null) + return ResolveSegmentNaturalClass(segmentClass, grammar); + + XElement? featureClass = grammar + .Descendants("FeatureNaturalClass") + .FirstOrDefault(e => (string?)e.Attribute("id") == naturalClassId); + return featureClass is not null ? ResolveFeatureNaturalClass(featureClass, grammar) : ClassResolution.No(); + } + + private static ClassResolution ResolveSegmentNaturalClass(XElement segmentClass, XDocument grammar) + { + var ids = new List(); + foreach (XElement segment in segmentClass.Elements("Segment")) + { + string? segmentId = (string?)segment.Attribute("segment"); + if (segmentId is null) + return ClassResolution.No(); + XElement? segmentDef = FindSegmentDefinition(grammar, segmentId); + if (segmentDef is null) + return ClassResolution.No(); + if (IsActiveElement(segmentDef)) + ids.Add(segmentId); + } + return ClassResolution.Ok(ids); + } + + // Nested FeatureValue (ComplexFeature shape) and a missing feature/symbolValues are refused rather + // than guessed at; a SegmentDefinition that does not declare a value for a constrained feature is + // unresolved too, exactly matching OrderingGenerator's own FeatureNaturalClass resolution. + private static ClassResolution ResolveFeatureNaturalClass(XElement featureClass, XDocument grammar) + { + var constraints = new List<(string Feature, HashSet Symbols)>(); + foreach (XElement featureValue in featureClass.Elements("FeatureValue")) + { + if (!IsActiveElement(featureValue)) + continue; + if (featureValue.Elements("FeatureValue").Any()) + return ClassResolution.No(); + + string? feature = (string?)featureValue.Attribute("feature"); + string? symbolValues = (string?)featureValue.Attribute("symbolValues"); + if (feature is null || symbolValues is null) + return ClassResolution.No(); + constraints.Add((feature, SplitIdrefs(symbolValues).ToHashSet(StringComparer.Ordinal))); + } + + var members = new List(); + foreach (XElement segmentDef in grammar.Descendants("SegmentDefinition")) + { + if (!IsActiveElement(segmentDef)) + continue; + string? segmentId = (string?)segmentDef.Attribute("id"); + if (segmentId is null) + continue; + + bool? matches = MatchesEveryConstraint(segmentDef, constraints); + if (matches is null) + return ClassResolution.No(); + if (matches.Value) + members.Add(segmentId); + } + return ClassResolution.Ok(members); + } + + private static bool? MatchesEveryConstraint( + XElement segmentDef, + List<(string Feature, HashSet Symbols)> constraints + ) + { + foreach ((string feature, HashSet symbols) in constraints) + { + XElement? declared = segmentDef + .Elements("FeatureValue") + .FirstOrDefault(fv => IsActiveElement(fv) && (string?)fv.Attribute("feature") == feature); + if (declared is null) + return null; + + string? declaredSymbols = (string?)declared.Attribute("symbolValues"); + HashSet declaredSet = declaredSymbols is null + ? new HashSet(StringComparer.Ordinal) + : SplitIdrefs(declaredSymbols).ToHashSet(StringComparer.Ordinal); + if (!declaredSet.Overlaps(symbols)) + return false; + } + return true; + } + + private static string[] SplitIdrefs(string value) => + value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + + private static XElement? FindSegmentDefinition(XDocument grammar, string id) => + grammar.Descendants("SegmentDefinition").FirstOrDefault(e => (string?)e.Attribute("id") == id); + + private static XElement? FindElementById(XDocument grammar, string id) => + grammar.Descendants().FirstOrDefault(e => (string?)e.Attribute("id") == id); + + private static bool IsActiveElement(XElement element) => (string?)element.Attribute("isActive") != "no"; +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/NotInSignatureCheck.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/NotInSignatureCheck.cs new file mode 100644 index 000000000..720c1dd87 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/NotInSignatureCheck.cs @@ -0,0 +1,103 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Recomputes the two mechanical halves of a claim: +/// the parse-comparison signature's own source never reads the property, and neutralizing the owning +/// element changes no word's outcome in any fixture that declares one. Neither half alone is a full +/// proof that no code anywhere ever branches on the property's VALUE -- that would need whole-engine +/// dataflow analysis this does not attempt. What this DOES establish mechanically: the specific string +/// two parses are diffed by cannot depend on the property (a source-text fact, re-read every run), and +/// removing the property from every fixture that has one is observably a no-op (an evidence-shaped +/// fact, re-run every run). The remaining gap -- "and no OTHER code path anywhere reads it either" -- +/// is a human reading of every call site the property's name appears at, recorded as prose in the +/// proof's checked-in evidence rather than computed here. +/// +public static class NotInSignatureCheck +{ + public const string SignatureSourceRelativePath = "src/SIL.Machine.Morphology.HermitCrab.Tool/SignatureFormat.cs"; + + /// + /// True when the file that builds the parse-comparison signature contains no reference to + /// . A literal source-text scan, not a semantic one: it cannot see a + /// reference reached through an alias or reflection, but it does mean a future edit that starts + /// reading the property directly in BuildSignature is caught the next time this runs. + /// + public static bool SignatureSourceNeverReads(string repositoryRoot, string propertyName) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(propertyName); + string path = Path.Combine( + repositoryRoot, + SignatureSourceRelativePath.Replace('/', Path.DirectorySeparatorChar) + ); + string source = File.ReadAllText(path); + return !source.Contains($".{propertyName}", StringComparison.Ordinal); + } + + /// Every fixture whose grammar document declares at least one . + public static IReadOnlyList FixturesContaining(string repositoryRoot, string elementName) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(elementName); + return GrammarCoverageGate + .DiscoverGrammars(repositoryRoot) + .Where(pair => XDocument.Load(pair.GrammarPath).Descendants(elementName).Any()) + .Select(pair => pair.FixtureId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + } + + /// + /// Re-runs the counterfactual for against every fixture + /// finds for , requiring the + /// mutation to be genuinely applied (never a fixture reports as + /// not containing the surface at all) AND every one of that fixture's words to come back unchanged. + /// False if no fixture declares the element -- an untested claim is not evidence of anything. + /// + public static bool MutationChangesNoWordInAnyContainingFixture( + string repositoryRoot, + string surfaceId, + string elementName, + string scratchDirectory + ) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(surfaceId); + ArgumentNullException.ThrowIfNull(elementName); + ArgumentNullException.ThrowIfNull(scratchDirectory); + + IReadOnlyList fixtureIds = FixturesContaining(repositoryRoot, elementName); + if (fixtureIds.Count == 0) + return false; + + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(repositoryRoot); + IReadOnlyList allFixtures = Fixture.DiscoverAll(Path.Combine(repositoryRoot, "conformance")); + foreach (string fixtureId in fixtureIds) + { + Fixture fixture = allFixtures.Single(f => f.Id == fixtureId); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + surfaceId, + inventory, + baseline, + scratchDirectory + ); + + // "none" means nothing was actually removed, so this fixture would test nothing. + if (result.Mutation == "none") + return false; + if (result.Verdict != CounterfactualVerdict.Unobservable) + return false; + } + + return true; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OrderingGenerator.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OrderingGenerator.cs new file mode 100644 index 000000000..f5a1e4f25 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OrderingGenerator.cs @@ -0,0 +1,958 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Which ordered list an / came from. +public enum OrderingListKind +{ + /// A Stratum's phonologicalRules IDREFS attribute. + StratumPhonologicalRules, + + /// A Stratum's morphologicalRules IDREFS attribute. + StratumMorphologicalRules, + + /// An AffixTemplate's ordered Slot element children. + AffixTemplateSlots, + + /// + /// Not produced by -- a synthetic tag used only to + /// route a through + /// when it is not a PhonologicalRule/PhonologicalRule pair, so the reported reason names what it actually is. + /// + StratumPair, +} + +/// Which pipeline stage a belongs to, per +/// . +public enum StratumUnitKind +{ + /// A Stratum's morphologicalRules IDREFS member. + MorphologicalRule, + + /// + /// A whole AffixTemplate -- never one of its Slot rules individually. Slot order within one template is + /// already pinned by ; the template as a unit is what + /// competes with a Stratum's free morphological rules and phonological rules for pipeline position. + /// + AffixTemplate, + + /// A Stratum's phonologicalRules IDREFS member. + PhonologicalRule, +} + +/// One rule-bearing unit a relates -- see +/// . +public sealed record StratumUnit(StratumUnitKind Kind, string Label); + +/// +/// Why a is pipeline-permitted, per the engine's synthesis order +/// (SynthesisStratumRule.Apply): morphology (free rules and templates, mutually recursive) runs +/// before phonology within one Stratum, and one Stratum's phonological output is the next Stratum's +/// morphological input. +/// +public enum StratumPairKind +{ + /// Both units are in the same pipeline stage (both morphology, or both phonology) of one + /// Stratum. + SameStage, + + /// A morphology-stage unit paired with a phonology-stage unit of the SAME Stratum, in + /// that order only. + CrossStage, + + /// A phonology-stage unit of one Stratum paired with a morphology-stage unit of the NEXT + /// Stratum. + CrossStratum, +} + +/// +/// One pipeline-permitted ordered pair from -- the +/// denominator for rule-interaction coverage, complementing 's adjacent-only pairs +/// with every non-adjacent, cross-list, cross-stage, and cross-stratum pair the engine's pipeline order +/// actually permits. +/// +public sealed record StratumInteractionPair( + string Id, + string FixtureId, + StratumPairKind Kind, + string StratumALabel, + int StratumAOrdinal, + StratumUnit UnitA, + string StratumBLabel, + int StratumBOrdinal, + StratumUnit UnitB +); + +/// +/// One ordered declaration found in a fixture's grammar, with >= 2 members -- the unit +/// turns into adjacent-transposition items. +/// +public sealed record OrderedList( + string FixtureId, + OrderingListKind Kind, + string OwnerLabel, + int OwnerOrdinal, + IReadOnlyList Members +); + +/// +/// One adjacent pair from an . Adjacent transpositions generate the symmetric +/// group, so pinning every adjacent swap pins the whole declared order -- this is deliberately n-1 +/// items per list, never the C(n,2) pairs or n! permutations. +/// +public sealed record OrderingItem( + string Id, + string FixtureId, + OrderingListKind Kind, + string OwnerLabel, + int OwnerOrdinal, + int PairIndex, + string MemberA, + string MemberB +); + +/// The document produced by transposing one 's adjacent pair. +public sealed record OrderingSwap(string ItemId, string Detail, XDocument Mutated); + +/// +/// Whether an earlier rule can possibly affect anything the later rule is sensitive to, per +/// . Deliberately three-valued: an adjacent pair +/// whose interaction cannot be resolved must never be reported as , because that +/// would license the claim "these two provably do not interact" on nothing but an inability to look. +/// +public enum DomainRelation +{ + /// + /// The earlier rule's EFFECT (its output segments plus its own input segments, since altering or + /// consuming a segment can matter as much as producing one) and the later rule's SENSITIVE set (its + /// input segments plus every segment reachable from its Environment/LeftEnvironment/RightEnvironment + /// templates) do not intersect. + /// + Disjoint, + + /// They share at least one segment, so the pair can genuinely interact -- including + /// feeding and bleeding via Environment. + Overlaps, + + /// Something in the pair could not be resolved to a segment set. Never treated as Disjoint. + Undetermined, +} + +/// The disjoint-domains verdict for one , with the reasoning that +/// produced it. +public sealed record DisjointDomainsCheck(string ItemId, DomainRelation Relation, string Reason); + +/// +/// Generates the Ordering branch of the coverage inventory: every adjacent pair in a Stratum's +/// phonologicalRules/morphologicalRules IDREFS lists and every AffixTemplate's ordered +/// Slot children, plus the two operations a counterfactual sweep needs against them -- producing the +/// swapped grammar () and, where the swap is expected to show no delta, a static +/// independence check () that fails closed to +/// rather than ever guessing . +/// +public static class OrderingGenerator +{ + public const string IdPrefix = "ordering:"; + + /// Every ordered list in with two or more members. + public static IReadOnlyList EnumerateOrderedLists(XDocument grammar, string fixtureId) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + + var lists = new List(); + + XElement[] strata = grammar.Descendants("Stratum").ToArray(); + for (int i = 0; i < strata.Length; i++) + { + string ownerLabel = OwnerLabel(strata[i], "Stratum", i); + AddIdrefsList( + lists, + fixtureId, + OrderingListKind.StratumPhonologicalRules, + ownerLabel, + i, + strata[i].Attribute("phonologicalRules") + ); + AddIdrefsList( + lists, + fixtureId, + OrderingListKind.StratumMorphologicalRules, + ownerLabel, + i, + strata[i].Attribute("morphologicalRules") + ); + } + + XElement[] templates = grammar.Descendants("AffixTemplate").ToArray(); + for (int i = 0; i < templates.Length; i++) + { + string ownerLabel = OwnerLabel(templates[i], "AffixTemplate", i); + List slots = templates[i].Elements("Slot").ToList(); + List members = slots.Select(SlotLabel).ToList(); + if (members.Count >= 2) + lists.Add(new OrderedList(fixtureId, OrderingListKind.AffixTemplateSlots, ownerLabel, i, members)); + } + + return lists; + } + + /// Every adjacent pair across every list finds. + public static IReadOnlyList EnumerateAdjacentPairs(XDocument grammar, string fixtureId) + { + var items = new List(); + foreach (OrderedList list in EnumerateOrderedLists(grammar, fixtureId)) + { + for (int i = 0; i < list.Members.Count - 1; i++) + { + items.Add( + new OrderingItem( + BuildId(list, i), + list.FixtureId, + list.Kind, + list.OwnerLabel, + list.OwnerOrdinal, + i, + list.Members[i], + list.Members[i + 1] + ) + ); + } + } + return items; + } + + public const string StratumPairIdPrefix = "stratum-pair:"; + + /// + /// Every pipeline-permitted ordered pair of rule-bearing units, within a Stratum or between two + /// adjacent Strata -- the complement of 's adjacent-only, + /// single-list pairs. An AffixTemplate is one unit (see ); + /// self-pairs are included, because multipleApplicationOrder defaults every PhonologicalRule to + /// iterative (self-feeding) application and morphological rules can recur across an Unordered + /// stratum's mrules/template recursion -- excluding them would silently drop that default behavior. + /// + /// Within one Stratum, morphological rules and AffixTemplates are mutually recursive + /// (SynthesisStratumRule.ApplyMorphologicalRules calls ApplyTemplates and vice versa), so + /// every ordered pair between them, in both directions, is pipeline-permitted (). Phonological rules are always run through an unconditional + /// LinearRuleCascade (SynthesisStratumRule never branches on phonologicalRuleOrder), + /// so a same-stage phonology pair is permitted only forward or self, per the declared + /// phonologicalRules order -- a later rule can never feed an earlier one within one pass. + /// Morphology precedes phonology within one Stratum's synthesis pass and never the reverse, so + /// cross-stage pairs run one way only. Across Strata, one Stratum's phonological output is the next + /// Stratum's morphological input (Language.CompileSynthesisRule cascades Strata in declared + /// order); only that adjacent, forward relationship is modeled. + /// + public static IReadOnlyList EnumerateStratumPairs(XDocument grammar, string fixtureId) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + + XElement[] strata = grammar.Descendants("Stratum").ToArray(); + XElement[] allTemplates = grammar.Descendants("AffixTemplate").ToArray(); + + var stages = new (string Label, List Morphology, List Phonology)[strata.Length]; + for (int i = 0; i < strata.Length; i++) + { + string label = OwnerLabel(strata[i], "Stratum", i); + var morphology = new List(); + foreach (string id in SplitIdrefs(strata[i].Attribute("morphologicalRules")?.Value ?? "")) + morphology.Add(new StratumUnit(StratumUnitKind.MorphologicalRule, id)); + for (int t = 0; t < allTemplates.Length; t++) + { + if (allTemplates[t].Ancestors("Stratum").FirstOrDefault() == strata[i]) + { + morphology.Add( + new StratumUnit(StratumUnitKind.AffixTemplate, OwnerLabel(allTemplates[t], "AffixTemplate", t)) + ); + } + } + var phonology = SplitIdrefs(strata[i].Attribute("phonologicalRules")?.Value ?? "") + .Select(id => new StratumUnit(StratumUnitKind.PhonologicalRule, id)) + .ToList(); + stages[i] = (label, morphology, phonology); + } + + var pairs = new List(); + for (int i = 0; i < strata.Length; i++) + { + (string label, List morphology, List phonology) = stages[i]; + + foreach (StratumUnit a in morphology) + { + foreach (StratumUnit b in morphology) + pairs.Add(BuildStratumPair(fixtureId, StratumPairKind.SameStage, label, i, a, label, i, b)); + } + + for (int a = 0; a < phonology.Count; a++) + { + for (int b = a; b < phonology.Count; b++) + { + pairs.Add( + BuildStratumPair( + fixtureId, + StratumPairKind.SameStage, + label, + i, + phonology[a], + label, + i, + phonology[b] + ) + ); + } + } + + foreach (StratumUnit m in morphology) + { + foreach (StratumUnit p in phonology) + pairs.Add(BuildStratumPair(fixtureId, StratumPairKind.CrossStage, label, i, m, label, i, p)); + } + + if (i + 1 < strata.Length) + { + (string nextLabel, List nextMorphology, _) = stages[i + 1]; + foreach (StratumUnit p in phonology) + { + foreach (StratumUnit m in nextMorphology) + { + pairs.Add( + BuildStratumPair(fixtureId, StratumPairKind.CrossStratum, label, i, p, nextLabel, i + 1, m) + ); + } + } + } + } + + return pairs; + } + + /// + /// Classifies a by delegating to -- + /// only a PhonologicalRule/PhonologicalRule pair can ever resolve to + /// or ; every other unit-kind combination reports + /// by construction, matching that check's own stated scope. + /// + public static DisjointDomainsCheck CheckStratumPairDisjointDomains(XDocument grammar, StratumInteractionPair pair) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(pair); + + bool bothPhonological = + pair.UnitA.Kind == StratumUnitKind.PhonologicalRule && pair.UnitB.Kind == StratumUnitKind.PhonologicalRule; + var syntheticItem = new OrderingItem( + pair.Id, + pair.FixtureId, + bothPhonological ? OrderingListKind.StratumPhonologicalRules : OrderingListKind.StratumPair, + pair.StratumALabel, + pair.StratumAOrdinal, + 0, + pair.UnitA.Label, + pair.UnitB.Label + ); + return CheckDisjointDomains(grammar, syntheticItem); + } + + private static StratumInteractionPair BuildStratumPair( + string fixtureId, + StratumPairKind kind, + string stratumALabel, + int stratumAOrdinal, + StratumUnit unitA, + string stratumBLabel, + int stratumBOrdinal, + StratumUnit unitB + ) + { + string id = + $"{StratumPairIdPrefix}{fixtureId}/{stratumAOrdinal}:{StratumUnitTag(unitA.Kind)}:{Encode(unitA.Label)}" + + $"~{stratumBOrdinal}:{StratumUnitTag(unitB.Kind)}:{Encode(unitB.Label)}"; + return new StratumInteractionPair( + id, + fixtureId, + kind, + stratumALabel, + stratumAOrdinal, + unitA, + stratumBLabel, + stratumBOrdinal, + unitB + ); + } + + private static string StratumUnitTag(StratumUnitKind kind) => + kind switch + { + StratumUnitKind.MorphologicalRule => "mrule", + StratumUnitKind.AffixTemplate => "template", + StratumUnitKind.PhonologicalRule => "prule", + _ => throw new ArgumentOutOfRangeException(nameof(kind)), + }; + + /// + /// The same grammar with exactly 's adjacent pair transposed, so the result + /// can be saved and run through --evaluate-mutant. Never mutates + /// -- a copy is made first, matching 's established pattern. Returns + /// null when no longer matches the document (wrong owner count, member + /// order changed underneath it), rather than silently swapping the wrong pair. + /// + public static OrderingSwap? Swap(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + + var copy = new XDocument(grammar); + return item.Kind switch + { + OrderingListKind.StratumPhonologicalRules => SwapIdrefsAttribute(copy, item, "phonologicalRules"), + OrderingListKind.StratumMorphologicalRules => SwapIdrefsAttribute(copy, item, "morphologicalRules"), + OrderingListKind.AffixTemplateSlots => SwapSlots(copy, item), + _ => null, + }; + } + + /// + /// Decides whether 's earlier member can possibly affect anything its later + /// member is sensitive to, recomputed from . Only Stratum + /// phonologicalRules pairs between two PhonologicalRule elements are ever resolved to + /// or -- everything else + /// (MetathesisRule, morphological-rule pairs, Slot pairs, or any construct this check does not + /// model) is reported as with the specific reason, never + /// guessed. + /// + /// The earlier rule's EFFECT set is its output segments (what it produces) unioned with its own input + /// segments (what it consumes or alters) -- removing or changing a segment can destroy an environment + /// the later rule needed (bleeding) just as much as producing one can create it (feeding). The later + /// rule's SENSITIVE set is its input segments unioned with every segment reachable from its + /// Environment/LeftEnvironment/RightEnvironment templates, per PhonologicalSubrule, since a + /// rule that only fires in a given environment is affected by anything that can create or destroy that + /// environment. holds only when EFFECT and SENSITIVE do not + /// intersect. + /// + public static DisjointDomainsCheck CheckDisjointDomains(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + + if (item.Kind != OrderingListKind.StratumPhonologicalRules) + { + return new DisjointDomainsCheck( + item.Id, + DomainRelation.Undetermined, + $"{item.Kind} pairs are not modeled by this check -- only Stratum phonologicalRules pairs " + + "resolve an effect-segment-set against a sensitivity-segment-set" + ); + } + + XElement? ruleA = FindPhonologicalOrMetathesisRule(grammar, item.MemberA); + XElement? ruleB = FindPhonologicalOrMetathesisRule(grammar, item.MemberB); + if (ruleA is null || ruleB is null) + { + return new DisjointDomainsCheck( + item.Id, + DomainRelation.Undetermined, + $"'{item.MemberA}' or '{item.MemberB}' was not found as a PhonologicalRule/MetathesisRule in the document" + ); + } + if (ruleA.Name.LocalName != "PhonologicalRule" || ruleB.Name.LocalName != "PhonologicalRule") + { + return new DisjointDomainsCheck( + item.Id, + DomainRelation.Undetermined, + "MetathesisRule's StructuralDescription is not modeled by this check" + ); + } + + var cache = new Dictionary(StringComparer.Ordinal); + SegmentResolution effect = ResolveRuleEffectSegments(ruleA, grammar, cache); + if (!effect.IsResolved) + { + return new DisjointDomainsCheck( + item.Id, + DomainRelation.Undetermined, + $"could not resolve '{item.MemberA}''s effect segments: {effect.Reason}" + ); + } + + SegmentResolution sensitive = ResolveRuleSensitiveSegments(ruleB, grammar, cache); + if (!sensitive.IsResolved) + { + return new DisjointDomainsCheck( + item.Id, + DomainRelation.Undetermined, + $"could not resolve '{item.MemberB}''s sensitivity segments: {sensitive.Reason}" + ); + } + + string[] shared = effect + .Segments.Intersect(sensitive.Segments, StringComparer.Ordinal) + .OrderBy(s => s, StringComparer.Ordinal) + .ToArray(); + return shared.Length == 0 + ? new DisjointDomainsCheck( + item.Id, + DomainRelation.Disjoint, + $"'{item.MemberA}' effect (output+input) {{{string.Join(",", effect.Segments.OrderBy(s => s, StringComparer.Ordinal))}}} and " + + $"'{item.MemberB}' sensitivity (input+environment) {{{string.Join(",", sensitive.Segments.OrderBy(s => s, StringComparer.Ordinal))}}} do not intersect" + ) + : new DisjointDomainsCheck( + item.Id, + DomainRelation.Overlaps, + $"shared segment(s): {string.Join(",", shared)}" + ); + } + + private static void AddIdrefsList( + List lists, + string fixtureId, + OrderingListKind kind, + string ownerLabel, + int ownerOrdinal, + XAttribute? attribute + ) + { + if (attribute is null) + return; + string[] members = SplitIdrefs(attribute.Value); + if (members.Length >= 2) + lists.Add(new OrderedList(fixtureId, kind, ownerLabel, ownerOrdinal, members)); + } + + private static string[] SplitIdrefs(string value) => + value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + + private static string OwnerLabel(XElement element, string tag, int ordinal) + { + string? name = (string?)element.Element("Name"); + return string.IsNullOrEmpty(name) ? $"{tag}#{ordinal}" : name; + } + + private static string SlotLabel(XElement slot, int index) + { + string? name = (string?)slot.Element("Name"); + return string.IsNullOrEmpty(name) ? $"Slot#{index}" : name; + } + + private static string AttributeSlug(OrderingListKind kind) => + kind switch + { + OrderingListKind.StratumPhonologicalRules => "phonologicalRules", + OrderingListKind.StratumMorphologicalRules => "morphologicalRules", + OrderingListKind.AffixTemplateSlots => "slots", + _ => throw new ArgumentOutOfRangeException(nameof(kind)), + }; + + // fixtureId is kept raw (it is already a plain "category/name" path this repo controls), so only + // the member labels -- which a Slot's free-text Name can make arbitrary -- are percent-encoded. + // Deliberately omits OwnerOrdinal: within one fixture, IDREFS tokens are unique document-wide + // (XML ID uniqueness), so a member pair alone already disambiguates every Stratum list. The one + // gap that leaves is two AffixTemplates in the same fixture reusing an identical Slot Name pair, + // which this scheme cannot distinguish; see this file's caller-facing report for that limitation. + private static string BuildId(OrderedList list, int pairIndex) => + $"{IdPrefix}{list.FixtureId}/{AttributeSlug(list.Kind)}/{Encode(list.Members[pairIndex])}~{Encode(list.Members[pairIndex + 1])}"; + + private static string Encode(string value) => CanonicalIdCodec.Encode(value); + + private static OrderingSwap? SwapIdrefsAttribute(XDocument copy, OrderingItem item, string attributeName) + { + XElement[] strata = copy.Descendants("Stratum").ToArray(); + if (item.OwnerOrdinal < 0 || item.OwnerOrdinal >= strata.Length) + return null; + XElement owner = strata[item.OwnerOrdinal]; + XAttribute? attribute = owner.Attribute(attributeName); + if (attribute is null) + return null; + + string[] tokens = SplitIdrefs(attribute.Value); + if (item.PairIndex < 0 || item.PairIndex + 1 >= tokens.Length) + return null; + if (tokens[item.PairIndex] != item.MemberA || tokens[item.PairIndex + 1] != item.MemberB) + return null; + + (tokens[item.PairIndex], tokens[item.PairIndex + 1]) = (tokens[item.PairIndex + 1], tokens[item.PairIndex]); + attribute.Value = string.Join(" ", tokens); + return new OrderingSwap( + item.Id, + $"swapped adjacent {attributeName} entries \"{item.MemberA}\" and \"{item.MemberB}\" on " + + $"Stratum#{item.OwnerOrdinal} (\"{item.OwnerLabel}\")", + copy + ); + } + + private static OrderingSwap? SwapSlots(XDocument copy, OrderingItem item) + { + XElement[] templates = copy.Descendants("AffixTemplate").ToArray(); + if (item.OwnerOrdinal < 0 || item.OwnerOrdinal >= templates.Length) + return null; + XElement owner = templates[item.OwnerOrdinal]; + List slots = owner.Elements("Slot").ToList(); + if (item.PairIndex < 0 || item.PairIndex + 1 >= slots.Count) + return null; + + XElement first = slots[item.PairIndex]; + XElement second = slots[item.PairIndex + 1]; + if (SlotLabel(first, item.PairIndex) != item.MemberA || SlotLabel(second, item.PairIndex + 1) != item.MemberB) + return null; + + // Swap the two elements' positions in place via a placeholder, rather than detaching every + // Slot and rebuilding the list, so no other slot's position is disturbed. + var placeholder = new XElement("Placeholder"); + first.ReplaceWith(placeholder); + second.ReplaceWith(first); + placeholder.ReplaceWith(second); + + return new OrderingSwap( + item.Id, + $"swapped adjacent Slot elements \"{item.MemberA}\" and \"{item.MemberB}\" on " + + $"AffixTemplate#{item.OwnerOrdinal} (\"{item.OwnerLabel}\")", + copy + ); + } + + private static XElement? FindPhonologicalOrMetathesisRule(XDocument grammar, string id) => + grammar + .Descendants() + .FirstOrDefault(e => + (e.Name.LocalName == "PhonologicalRule" || e.Name.LocalName == "MetathesisRule") + && (string?)e.Attribute("id") == id + ); + + /// + /// A resolved segment set, or a failure to resolve one -- false means + /// "cannot look", which callers must never treat as an empty (and therefore trivially disjoint) + /// set. + /// + private readonly record struct SegmentResolution(bool IsResolved, IReadOnlySet Segments, string Reason) + { + public static SegmentResolution Ok(IEnumerable segments) => + new(true, segments.ToHashSet(StringComparer.Ordinal), ""); + + public static SegmentResolution No(string reason) => new(false, ImmutableHashSet.Empty, reason); + } + + private static SegmentResolution Union(SegmentResolution a, SegmentResolution b) + { + if (!a.IsResolved) + return a; + if (!b.IsResolved) + return b; + return SegmentResolution.Ok(a.Segments.Concat(b.Segments)); + } + + // A rule's live output is the union across every PhonologicalSubrule's PhoneticOutput: any one of + // them may fire, so all are possible outputs. isActive="no" subrules are included too -- + // over-approximating a rule's output can only turn a real Disjoint into a false Undetermined, + // never the reverse, which is the safe direction for a check whose only forbidden mistake is a + // false Disjoint. + private static SegmentResolution ResolveRuleOutputSegments( + XElement rule, + XDocument grammar, + Dictionary cache + ) + { + List subrules = + rule.Element("PhonologicalSubrules")?.Elements("PhonologicalSubrule").ToList() ?? new List(); + if (subrules.Count == 0) + return SegmentResolution.No("no PhonologicalSubrule children found"); + + SegmentResolution acc = SegmentResolution.Ok(Array.Empty()); + foreach (XElement subrule in subrules) + { + XElement? sequence = subrule.Element("PhoneticOutput")?.Element("PhoneticSequence"); + acc = Union(acc, ResolveSequenceSegments(sequence, grammar, cache)); + if (!acc.IsResolved) + return acc; + } + return acc; + } + + // A rule's PhoneticInput is shared across every one of its subrules (the DTD gives PhonologicalRule + // exactly one PhoneticInput), so this is a single resolution, not a union. + private static SegmentResolution ResolveRuleInputSegments( + XElement rule, + XDocument grammar, + Dictionary cache + ) => ResolveSequenceSegments(rule.Element("PhoneticInput")?.Element("PhoneticSequence"), grammar, cache); + + // What an earlier rule can change: what it produces AND what it consumes/alters. Consuming or + // altering a segment can destroy an environment a later rule needs (bleeding), so input belongs in + // EFFECT exactly as much as output does. + private static SegmentResolution ResolveRuleEffectSegments( + XElement rule, + XDocument grammar, + Dictionary cache + ) + { + SegmentResolution output = ResolveRuleOutputSegments(rule, grammar, cache); + return Union(output, ResolveRuleInputSegments(rule, grammar, cache)); + } + + // What a later rule can be affected by: what it matches AND every segment its Environment templates + // are conditioned on. A rule that only fires in some environment is sensitive to whatever can create + // or destroy that environment, not only to its own PhoneticInput. + private static SegmentResolution ResolveRuleSensitiveSegments( + XElement rule, + XDocument grammar, + Dictionary cache + ) + { + SegmentResolution input = ResolveRuleInputSegments(rule, grammar, cache); + return Union(input, ResolveRuleEnvironmentSegments(rule, grammar, cache)); + } + + // Union across every PhonologicalSubrule's Environment, mirroring ResolveRuleOutputSegments: any one + // subrule's environment can be the one that fires, so all are possible sensitivities. isActive="no" + // subrules are included too, for the same over-approximation reason output does. + private static SegmentResolution ResolveRuleEnvironmentSegments( + XElement rule, + XDocument grammar, + Dictionary cache + ) + { + List subrules = + rule.Element("PhonologicalSubrules")?.Elements("PhonologicalSubrule").ToList() ?? new List(); + if (subrules.Count == 0) + return SegmentResolution.No("no PhonologicalSubrule children found"); + + SegmentResolution acc = SegmentResolution.Ok(Array.Empty()); + foreach (XElement subrule in subrules) + { + acc = Union(acc, ResolveSubruleEnvironmentSegments(subrule, grammar, cache)); + if (!acc.IsResolved) + return acc; + } + return acc; + } + + // A subrule's Environment (LeftEnvironment?, RightEnvironment?) is optional per the DTD; absent + // means this subrule fires unconditionally, i.e. contributes no extra environment segments. + private static SegmentResolution ResolveSubruleEnvironmentSegments( + XElement subrule, + XDocument grammar, + Dictionary cache + ) + { + XElement? environment = subrule.Element("Environment"); + if (environment is null) + return SegmentResolution.Ok(Array.Empty()); + + SegmentResolution left = ResolveEnvironmentSideSegments(environment.Element("LeftEnvironment"), grammar, cache); + if (!left.IsResolved) + return left; + return Union(left, ResolveEnvironmentSideSegments(environment.Element("RightEnvironment"), grammar, cache)); + } + + private static SegmentResolution ResolveEnvironmentSideSegments( + XElement? side, + XDocument grammar, + Dictionary cache + ) => + side is null + ? SegmentResolution.Ok(Array.Empty()) + : ResolveSequenceSegments(side.Element("PhoneticTemplate")?.Element("PhoneticSequence"), grammar, cache); + + private static SegmentResolution ResolveSequenceSegments( + XElement? sequence, + XDocument grammar, + Dictionary cache + ) + { + // PhoneticInput/PhoneticOutput's PhoneticSequence child is itself optional (an epenthesis rule + // matches/produces no pre-existing segment), and that is a fully resolved empty set, not a + // failure to resolve. + if (sequence is null) + return SegmentResolution.Ok(Array.Empty()); + + SegmentResolution acc = SegmentResolution.Ok(Array.Empty()); + foreach (XElement child in sequence.Elements()) + { + acc = Union(acc, ResolveElementSegments(child, grammar, cache)); + if (!acc.IsResolved) + return acc; + } + return acc; + } + + private static SegmentResolution ResolveElementSegments( + XElement element, + XDocument grammar, + Dictionary cache + ) + { + switch (element.Name.LocalName) + { + case "Segment": + { + string? segmentId = (string?)element.Attribute("segment"); + return segmentId is null + ? SegmentResolution.No(" has no segment attribute") + : SegmentResolution.Ok(new[] { segmentId }); + } + case "SimpleContext": + { + // AlphaVariables (if present) further narrows which polarity applies; ignoring it and + // resolving the base natural class is an over-approximation, which is the safe + // direction for this check. + string? naturalClassId = (string?)element.Attribute("naturalClass"); + return naturalClassId is null + ? SegmentResolution.No(" has no naturalClass attribute") + : ResolveNaturalClass(naturalClassId, grammar, cache); + } + case "OptionalSegmentSequence": + { + // Optionality means these segments may or may not appear; including them (rather than + // excluding) is the same safe over-approximation as above. + SegmentResolution acc = SegmentResolution.Ok(Array.Empty()); + foreach (XElement child in element.Elements()) + { + acc = Union(acc, ResolveElementSegments(child, grammar, cache)); + if (!acc.IsResolved) + return acc; + } + return acc; + } + case "BoundaryMarker": + // A morpheme/word boundary marker, never a phonemic segment. + return SegmentResolution.Ok(Array.Empty()); + default: + // In particular (a raw PhoneticShape string) would need a + // CharacterDefinitionTable tokenizer this check does not implement. + return SegmentResolution.No($"<{element.Name.LocalName}> is not a modeled phonetic-sequence construct"); + } + } + + private static SegmentResolution ResolveNaturalClass( + string naturalClassId, + XDocument grammar, + Dictionary cache + ) + { + if (cache.TryGetValue(naturalClassId, out SegmentResolution cached)) + return cached; + + XElement? segmentClass = grammar + .Descendants("SegmentNaturalClass") + .FirstOrDefault(e => (string?)e.Attribute("id") == naturalClassId); + SegmentResolution result; + if (segmentClass is not null) + { + result = ResolveSegmentNaturalClass(segmentClass); + } + else + { + XElement? featureClass = grammar + .Descendants("FeatureNaturalClass") + .FirstOrDefault(e => (string?)e.Attribute("id") == naturalClassId); + result = featureClass is not null + ? ResolveFeatureNaturalClass(featureClass, grammar) + : SegmentResolution.No($"natural class '{naturalClassId}' is not declared in this document"); + } + + cache[naturalClassId] = result; + return result; + } + + private static SegmentResolution ResolveSegmentNaturalClass(XElement segmentClass) + { + var ids = new List(); + foreach (XElement segment in segmentClass.Elements("Segment")) + { + string? segmentId = (string?)segment.Attribute("segment"); + if (segmentId is null) + { + return SegmentResolution.No( + $"SegmentNaturalClass '{(string?)segmentClass.Attribute("id")}' has a with no segment attribute" + ); + } + ids.Add(segmentId); + } + return SegmentResolution.Ok(ids); + } + + // Nested FeatureValue (the ComplexFeature shape) is refused rather than partially matched, and a + // SegmentDefinition that does not declare a value for a constrained feature is Undetermined rather + // than treated as a non-match: assuming a default one way or the other here would be guessing at + // engine semantics this check does not verify. + private static SegmentResolution ResolveFeatureNaturalClass(XElement featureClass, XDocument grammar) + { + string? classId = (string?)featureClass.Attribute("id"); + var constraints = new List<(string Feature, HashSet Symbols)>(); + foreach (XElement featureValue in featureClass.Elements("FeatureValue")) + { + if ((string?)featureValue.Attribute("isActive") == "no") + continue; + if (featureValue.Elements("FeatureValue").Any()) + { + return SegmentResolution.No( + $"FeatureNaturalClass '{classId}' has a nested FeatureValue (complex-feature matching is not modeled)" + ); + } + + string? feature = (string?)featureValue.Attribute("feature"); + string? symbolValues = (string?)featureValue.Attribute("symbolValues"); + if (feature is null || symbolValues is null) + { + return SegmentResolution.No( + $"FeatureNaturalClass '{classId}' has a FeatureValue missing feature or symbolValues" + ); + } + constraints.Add((feature, SplitIdrefs(symbolValues).ToHashSet(StringComparer.Ordinal))); + } + + var members = new List(); + foreach (XElement segmentDef in grammar.Descendants("SegmentDefinition")) + { + if ((string?)segmentDef.Attribute("isActive") == "no") + continue; + string? segmentId = (string?)segmentDef.Attribute("id"); + if (segmentId is null) + continue; + + bool? matches = MatchesEveryConstraint(segmentDef, constraints); + if (matches is null) + { + return SegmentResolution.No( + $"SegmentDefinition '{segmentId}' does not declare every feature FeatureNaturalClass '{classId}' constrains" + ); + } + if (matches.Value) + members.Add(segmentId); + } + return SegmentResolution.Ok(members); + } + + /// + /// Null means at least one constrained feature is not declared (actively) on this segment at all -- + /// undetermined, never a silent non-match. + /// + private static bool? MatchesEveryConstraint( + XElement segmentDef, + List<(string Feature, HashSet Symbols)> constraints + ) + { + foreach ((string feature, HashSet symbols) in constraints) + { + XElement? declared = segmentDef + .Elements("FeatureValue") + .FirstOrDefault(fv => + (string?)fv.Attribute("isActive") != "no" && (string?)fv.Attribute("feature") == feature + ); + if (declared is null) + return null; + + string? declaredSymbols = (string?)declared.Attribute("symbolValues"); + HashSet declaredSet = declaredSymbols is null + ? new HashSet(StringComparer.Ordinal) + : SplitIdrefs(declaredSymbols).ToHashSet(StringComparer.Ordinal); + if (!declaredSet.Overlaps(symbols)) + return false; + } + return true; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OrderingProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OrderingProofs.cs new file mode 100644 index 000000000..3ea77252e --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OrderingProofs.cs @@ -0,0 +1,54 @@ +#nullable enable +using System; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind from +/// rather than from hand-written prose. A +/// disjoint-domains claim is about the GRAMMAR -- the earlier rule's effect (output plus its own input) +/// cannot reach anything the later rule is sensitive to (its input plus its Environment templates) -- +/// never about which words a fixture happens to contain, so both directions here call the same +/// recomputation the design doc names as authoritative. +/// +public static class OrderingProofs +{ + public const string Kind = "disjoint-domains"; + + /// + /// Builds a proof for from + /// 's own reasoning, or null when the check does + /// not return -- and + /// can never license this proof kind. + /// + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + DisjointDomainsCheck check = OrderingGenerator.CheckDisjointDomains(grammar, item); + return check.Relation == DomainRelation.Disjoint ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies against : true only when + /// 's freshly generated adjacent pairs still contain an item with + /// 's id AND recomputes + /// for it. A stale id (the swap no longer matches the document) + /// and a recomputed / + /// both fail closed to false rather than passing on nothing but the claim itself. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return OrderingGenerator.CheckDisjointDomains(grammar, item).Relation == DomainRelation.Disjoint; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OwnedSymbolKey.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OwnedSymbolKey.cs new file mode 100644 index 000000000..55d92d548 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/OwnedSymbolKey.cs @@ -0,0 +1,643 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// A stable identity for a definition owned by one admitted repository project. +internal sealed record OwnedSymbolKey +{ + private OwnedSymbolKey(string value) + { + if (string.IsNullOrWhiteSpace(value)) + throw new ArgumentException("An owned symbol key is required.", nameof(value)); + Value = value; + } + + internal string Value { get; } + + internal static OwnedSymbolKey Create(string projectId, ISymbol symbol) + { + ArgumentException.ThrowIfNullOrWhiteSpace(projectId); + ArgumentNullException.ThrowIfNull(symbol); + if (symbol.ContainingAssembly is not IAssemblySymbol assembly) + throw new CompilerInputException("external-symbol", "The symbol has no containing assembly."); + + if (symbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction or MethodKind.AnonymousFunction }) + { + throw new CompilerInputException( + "owned-symbol-context-required", + "Local functions and lambdas require compilation context." + ); + } + ISymbol canonical = symbol is INamedTypeSymbol ? symbol : symbol.OriginalDefinition; + return Create(projectId, assembly.Identity, CanonicalSymbolId(canonical)); + } + + internal static OwnedSymbolKey Create(string projectId, AssemblyIdentity assembly, string canonicalSymbolId) => + new($"owned:{projectId}/{AssemblyIdentity(assembly)}/{canonicalSymbolId}"); + + internal static string CanonicalId(ISymbol symbol) => CanonicalSymbolId(symbol); + + internal static string CanonicalIdForParameter(IParameterSymbol parameter) => ParameterType(parameter); + + private static string AssemblyIdentity(AssemblyIdentity identity) + { + string culture = string.IsNullOrEmpty(identity.CultureName) ? "neutral" : identity.CultureName; + string token = identity.PublicKeyToken.IsDefaultOrEmpty + ? "null" + : Convert.ToHexString(identity.PublicKeyToken.ToArray()).ToLowerInvariant(); + return $"{identity.Name},Version={identity.Version},Culture={culture},PublicKeyToken={token}"; + } + + private static string CanonicalSymbolId(ISymbol symbol) + { + return symbol switch + { + INamespaceSymbol ns => NamespaceId(ns), + INamedTypeSymbol type => TypeId(type), + IMethodSymbol method => MethodId(method), + IPropertySymbol property => PropertyId(property), + IFieldSymbol field => $"{TypeId(field.ContainingType!)}.{field.Name}", + IEventSymbol @event => $"{TypeId(@event.ContainingType!)}.{@event.Name}", + _ => throw new CompilerInputException( + "unsupported-symbol-shape", + $"Symbol kind '{symbol.Kind}' is not supported by the owned-symbol catalog." + ), + }; + } + + private static string NamespaceId(INamespaceSymbol ns) + { + return ns.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + .Replace("global::", string.Empty, StringComparison.Ordinal); + } + + private static string TypeId(INamedTypeSymbol type) + { + INamedTypeSymbol definition = type.OriginalDefinition; + string name = definition.Name + (definition.Arity == 0 ? string.Empty : $"`{definition.Arity}"); + string id = + type.ContainingType is not null ? $"{TypeId(type.ContainingType)}.{name}" + : definition.ContainingNamespace is { IsGlobalNamespace: false } ns ? $"{NamespaceId(ns)}.{name}" + : name; + + if (SymbolEqualityComparer.Default.Equals(type, definition) || type.TypeArguments.Length == 0) + return id; + return $"{id}<{string.Join(",", type.TypeArguments.Select(TypeDisplay))}>"; + } + + private static string MethodId(IMethodSymbol method) + { + IMethodSymbol definition = method.OriginalDefinition; + if ( + definition.AssociatedSymbol is IPropertySymbol property + && definition.MethodKind is MethodKind.PropertyGet or MethodKind.PropertySet + ) + { + return $"{PropertyId(property)}/{(definition.MethodKind == MethodKind.PropertyGet ? "get" : "set")}"; + } + if ( + definition.AssociatedSymbol is IEventSymbol @event + && definition.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove + ) + { + return $"{TypeId(@event.ContainingType!)}.{@event.Name}/{(definition.MethodKind == MethodKind.EventAdd ? "add" : "remove")}"; + } + string prefix = definition.ContainingType is null ? string.Empty : TypeId(definition.ContainingType) + "."; + string name = definition.MethodKind switch + { + MethodKind.Constructor => ".ctor", + MethodKind.StaticConstructor => ".cctor", + MethodKind.Destructor => ".dtor", + MethodKind.UserDefinedOperator => "operator-" + definition.MetadataName, + MethodKind.Conversion => "conversion-" + definition.MetadataName, + _ => definition.Name, + }; + if (definition.Arity > 0) + name += "`" + definition.Arity; + + string result = $"{prefix}{name}({string.Join(",", definition.Parameters.Select(ParameterType))})"; + // Both implicit and explicit conversions have the same metadata name and + // parameter list. Their target type is therefore part of their identity. + return definition.MethodKind == MethodKind.Conversion + ? result + "->" + TypeDisplay(definition.ReturnType) + : result; + } + + private static string PropertyId(IPropertySymbol property) + { + string prefix = property.ContainingType is null ? string.Empty : TypeId(property.ContainingType) + "."; + return property.IsIndexer + ? $"{prefix}this({string.Join(",", property.Parameters.Select(ParameterType))})" + : prefix + property.Name; + } + + private static string ParameterType(IParameterSymbol parameter) + { + string modifier = parameter.IsParams + ? "params " + : parameter.RefKind switch + { + RefKind.Ref => "ref ", + RefKind.Out => "out ", + RefKind.In => "in ", + RefKind.RefReadOnlyParameter => "ref readonly ", + _ => string.Empty, + }; + return modifier + TypeDisplay(parameter.Type); + } + + private static string TypeDisplay(ITypeSymbol type) + { + if (type is ITypeParameterSymbol typeParameter) + return (typeParameter.TypeParameterKind == TypeParameterKind.Method ? "!!" : "!") + typeParameter.Ordinal; + if (type is IArrayTypeSymbol array) + return TypeDisplay(array.ElementType) + (array.Rank == 1 ? "[]" : $"[{new string(',', array.Rank - 1)}]"); + if (type is IPointerTypeSymbol pointer) + return TypeDisplay(pointer.PointedAtType) + "*"; + if (type is INamedTypeSymbol named) + return TypeId(named); + if (type is IDynamicTypeSymbol) + return "dynamic"; + + string? special = type.SpecialType switch + { + SpecialType.System_Boolean => "System.Boolean", + SpecialType.System_Byte => "System.Byte", + SpecialType.System_Char => "System.Char", + SpecialType.System_Decimal => "System.Decimal", + SpecialType.System_Double => "System.Double", + SpecialType.System_Int16 => "System.Int16", + SpecialType.System_Int32 => "System.Int32", + SpecialType.System_Int64 => "System.Int64", + SpecialType.System_Object => "System.Object", + SpecialType.System_SByte => "System.SByte", + SpecialType.System_Single => "System.Single", + SpecialType.System_String => "System.String", + SpecialType.System_UInt16 => "System.UInt16", + SpecialType.System_UInt32 => "System.UInt32", + SpecialType.System_UInt64 => "System.UInt64", + _ => null, + }; + return special + ?? type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + .Replace("global::", string.Empty, StringComparison.Ordinal); + } +} + +/// Bridges profile-local Roslyn symbols to original owned definitions. +internal sealed class OwnedSymbolBridge +{ + private static readonly IReadOnlyDictionary ProjectByAssemblyName = new Dictionary( + StringComparer.Ordinal + ) + { + ["SIL.Machine"] = "machine", + ["SIL.Machine.Morphology.HermitCrab"] = "hc", + ["hc"] = "hc-tool", + ["hc-conformance"] = "hc-conformance", + }; + + private readonly IReadOnlyDictionary _profiles; + private readonly IReadOnlyDictionary _assemblyProfiles = new Dictionary< + IAssemblySymbol, + string + >(ReferenceEqualityComparer.Instance); + + private OwnedSymbolBridge( + IReadOnlyDictionary profiles, + IReadOnlyDictionary assemblyProfiles + ) + { + _profiles = profiles; + _assemblyProfiles = assemblyProfiles; + } + + internal static OwnedSymbolBridge Create(RoslynCompilationGraph graph) + { + ArgumentNullException.ThrowIfNull(graph); + var profiles = new Dictionary(StringComparer.Ordinal); + var assemblyProfiles = new Dictionary(ReferenceEqualityComparer.Instance); + + foreach ( + RoslynCompilationNode node in graph + .Nodes.Values.OrderBy(item => item.Key.ProfileId, StringComparer.Ordinal) + .ThenBy(item => item.Key.ProjectId, StringComparer.Ordinal) + ) + { + if (!profiles.TryGetValue(node.Key.ProfileId, out ProfileIndex? profile)) + { + profile = new ProfileIndex(); + profiles.Add(node.Key.ProfileId, profile); + } + + RegisterAssembly(node.Compilation.Assembly, node.Key.ProfileId, assemblyProfiles); + foreach ( + IAssemblySymbol assembly in node.Compilation.SourceModule.ReferencedAssemblySymbols.Where(assembly => + ProjectByAssemblyName.ContainsKey(assembly.Identity.Name) + ) + ) + { + RegisterAssembly(assembly, node.Key.ProfileId, assemblyProfiles); + } + + string? expectedProject = ProjectByAssemblyName.GetValueOrDefault(node.Compilation.Assembly.Identity.Name); + if ( + expectedProject is null + || !string.Equals(expectedProject, node.Key.ProjectId, StringComparison.Ordinal) + ) + { + throw new CompilerInputException( + "unknown-owned-assembly", + $"Project '{node.Key.ProjectId}' has unexpected assembly '{node.Compilation.Assembly.Identity.Name}'." + ); + } + + foreach (ISymbol symbol in Definitions(node.Compilation.Assembly.GlobalNamespace)) + { + OwnedSymbolKey key = OwnedSymbolKey.Create(node.Key.ProjectId, symbol); + if (!profile.Definitions.TryAdd(key.Value, symbol)) + { + throw new CompilerInputException( + "ambiguous-owned-key", + $"Duplicate owned symbol key '{key.Value}'." + ); + } + profile.SymbolKeys.Add(symbol, key); + } + RegisterLocalExecutables(node, profile); + } + + return new OwnedSymbolBridge(profiles, assemblyProfiles); + } + + internal OwnedSymbolKey KeyFor(string profileId, ISymbol symbol) + { + ProfileIndex profile = Profile(profileId); + ArgumentNullException.ThrowIfNull(symbol); + if (symbol.ContainingAssembly is not IAssemblySymbol assembly) + throw new CompilerInputException("external-symbol", "The symbol has no containing assembly."); + string? project = ProjectByAssemblyName.GetValueOrDefault(assembly.Identity.Name); + if (project is null) + { + throw new CompilerInputException( + "external-symbol", + $"Assembly '{assembly.Identity.Name}' is not an admitted owned project." + ); + } + if (!_assemblyProfiles.TryGetValue(assembly, out string? actualProfile)) + { + throw new CompilerInputException( + "unknown-symbol-profile", + "The symbol does not belong to a captured compilation profile." + ); + } + if (!string.Equals(profileId, actualProfile, StringComparison.Ordinal)) + { + throw new CompilerInputException( + "cross-profile-symbol", + $"The symbol belongs to profile '{actualProfile}', not '{profileId}'." + ); + } + + if (profile.SymbolKeys.TryGetValue(symbol, out OwnedSymbolKey? contextualKey)) + return contextualKey; + if ( + symbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction or MethodKind.AnonymousFunction } contextual + && profile.ContextualKeys.TryGetValue(ContextLookupKey(contextual), out contextualKey) + ) + { + return contextualKey; + } + OwnedSymbolKey key = OwnedSymbolKey.Create(project, symbol); + if (!profile.Definitions.ContainsKey(key.Value)) + { + if ( + symbol is INamedTypeSymbol type + && !SymbolEqualityComparer.Default.Equals(type, type.OriginalDefinition) + ) + { + INamedTypeSymbol ownedConstruction = ConstructOwnedType(profile, project, type); + lock (profile.Definitions) + { + if (!profile.Definitions.TryGetValue(key.Value, out ISymbol? existing)) + { + profile.Definitions.Add(key.Value, ownedConstruction); + profile.SymbolKeys[ownedConstruction] = key; + } + else if (!SymbolEqualityComparer.Default.Equals(existing, ownedConstruction)) + { + throw new CompilerInputException( + "ambiguous-owned-key", + $"Duplicate owned symbol key '{key.Value}'." + ); + } + } + profile.SymbolKeys[symbol] = key; + return key; + } + throw new CompilerInputException("missing-owned-key", $"No owned definition exists for '{key.Value}'."); + } + return key; + } + + internal ISymbol Resolve(string profileId, OwnedSymbolKey key) + { + ProfileIndex profile = Profile(profileId); + ArgumentNullException.ThrowIfNull(key); + ParsedKey parsed = Parse(key.Value); + string assemblySimpleName = parsed.AssemblyIdentity.Split(',')[0]; + if ( + !ProjectByAssemblyName.TryGetValue(assemblySimpleName, out string? expectedProject) + || !string.Equals(expectedProject, parsed.ProjectId, StringComparison.Ordinal) + ) + { + throw new CompilerInputException( + "external-symbol", + $"Owned key '{key.Value}' names an unadmitted assembly." + ); + } + if (!profile.Definitions.TryGetValue(key.Value, out ISymbol? symbol)) + { + throw new CompilerInputException( + "missing-owned-key", + $"Owned key '{key.Value}' is not present in profile '{profileId}'." + ); + } + return symbol; + } + + private static INamedTypeSymbol ConstructOwnedType(ProfileIndex profile, string projectId, INamedTypeSymbol type) + { + OwnedSymbolKey openKey = OwnedSymbolKey.Create(projectId, type.OriginalDefinition); + if ( + !profile.Definitions.TryGetValue(openKey.Value, out ISymbol? openSymbol) + || openSymbol is not INamedTypeSymbol openType + ) + { + throw new CompilerInputException( + "missing-owned-key", + $"No owned generic definition exists for '{openKey.Value}'." + ); + } + + if ( + type.ContainingType is not null + && !SymbolEqualityComparer.Default.Equals(type.ContainingType, type.ContainingType.OriginalDefinition) + ) + { + INamedTypeSymbol ownedContaining = ConstructOwnedType(profile, projectId, type.ContainingType); + INamedTypeSymbol[] matches = ownedContaining.GetTypeMembers(type.Name, type.Arity).ToArray(); + if (matches.Length != 1) + { + throw new CompilerInputException( + "ambiguous-owned-key", + $"Constructed containing type has {matches.Length} nested matches for '{type.MetadataName}'." + ); + } + openType = matches[0]; + } + + return type.IsUnboundGenericType + ? openType.ConstructUnboundGenericType() + : openType.Construct(type.TypeArguments.ToArray()); + } + + private ProfileIndex Profile(string profileId) + { + ArgumentException.ThrowIfNullOrWhiteSpace(profileId); + if (!_profiles.TryGetValue(profileId, out ProfileIndex? profile)) + throw new CompilerInputException("unknown-profile", $"Unknown compilation profile '{profileId}'."); + return profile; + } + + private static IEnumerable Definitions(INamespaceSymbol ns) + { + if (!ns.IsGlobalNamespace) + yield return ns; + foreach (INamespaceSymbol child in ns.GetNamespaceMembers().OrderBy(item => item.Name, StringComparer.Ordinal)) + { + foreach (ISymbol symbol in Definitions(child)) + yield return symbol; + } + foreach ( + INamedTypeSymbol type in ns.GetTypeMembers().OrderBy(item => item.MetadataName, StringComparer.Ordinal) + ) + { + foreach (ISymbol symbol in Definitions(type)) + yield return symbol; + } + } + + private static IEnumerable Definitions(INamedTypeSymbol type) + { + yield return type; + foreach ( + INamedTypeSymbol nested in type.GetTypeMembers().OrderBy(item => item.MetadataName, StringComparer.Ordinal) + ) + { + foreach (ISymbol symbol in Definitions(nested)) + yield return symbol; + } + foreach ( + ISymbol member in type.GetMembers() + .OrderBy(item => item.MetadataName, StringComparer.Ordinal) + .ThenBy(item => item.Kind) + ) + { + if (member is INamedTypeSymbol) + continue; + yield return member; + } + } + + private static void RegisterAssembly( + IAssemblySymbol assembly, + string profileId, + IDictionary assemblyProfiles + ) + { + if ( + assemblyProfiles.TryGetValue(assembly, out string? existing) + && !string.Equals(existing, profileId, StringComparison.Ordinal) + ) + { + throw new CompilerInputException( + "ambiguous-symbol-profile", + $"Assembly '{assembly.Identity.Name}' appears in multiple profiles." + ); + } + assemblyProfiles[assembly] = profileId; + } + + private static void RegisterLocalExecutables(RoslynCompilationNode node, ProfileIndex profile) + { + var locals = new List(); + var lambdas = new List(); + foreach (SyntaxTree tree in node.Compilation.SyntaxTrees.OrderBy(tree => tree.FilePath, StringComparer.Ordinal)) + { + SemanticModel model = node.Compilation.GetSemanticModel(tree); + foreach ( + LocalFunctionStatementSyntax local in tree.GetRoot() + .DescendantNodes() + .OfType() + ) + { + if (model.GetDeclaredSymbol(local) is IMethodSymbol symbol) + locals.Add(symbol); + } + foreach ( + AnonymousFunctionExpressionSyntax lambda in tree.GetRoot() + .DescendantNodes() + .OfType() + ) + { + if (model.GetOperation(lambda) is IAnonymousFunctionOperation operation) + lambdas.Add(operation.Symbol); + } + } + + var localIds = new Dictionary(SymbolEqualityComparer.Default); + IMethodSymbol[] uniqueLocals = locals + .Cast() + .Distinct(SymbolEqualityComparer.Default) + .Cast() + .ToArray(); + IMethodSymbol[] uniqueLambdas = lambdas + .Cast() + .Distinct(SymbolEqualityComparer.Default) + .Cast() + .ToArray(); + foreach ( + IGrouping level in uniqueLocals.GroupBy(LocalNestingDepth).OrderBy(group => group.Key) + ) + { + foreach ( + IGrouping collision in level.GroupBy( + method => LocalBaseId(method, localIds), + StringComparer.Ordinal + ) + ) + { + IMethodSymbol[] ordered = collision + .OrderBy(SourcePath, StringComparer.Ordinal) + .ThenBy(SourceStart) + .ToArray(); + for (int index = 0; index < ordered.Length; index++) + { + string suffix = ordered.Length > 1 ? $"#{index}" : string.Empty; + localIds.Add(ordered[index], collision.Key + suffix); + } + } + } + + foreach (IMethodSymbol local in uniqueLocals) + RegisterContextual(node, profile, local, localIds[local]); + foreach (IMethodSymbol lambda in uniqueLambdas) + RegisterContextual(node, profile, lambda, ContextualId(lambda, localIds)); + } + + private static void RegisterContextual( + RoslynCompilationNode node, + ProfileIndex profile, + IMethodSymbol symbol, + string canonicalId + ) + { + OwnedSymbolKey key = OwnedSymbolKey.Create(node.Key.ProjectId, node.Compilation.Assembly.Identity, canonicalId); + if (!profile.Definitions.TryAdd(key.Value, symbol)) + throw new CompilerInputException("ambiguous-owned-key", $"Duplicate owned symbol key '{key.Value}'."); + profile.SymbolKeys.Add(symbol, key); + if (!profile.ContextualKeys.TryAdd(ContextLookupKey(symbol), key)) + { + throw new CompilerInputException( + "ambiguous-owned-key", + $"Duplicate contextual symbol location for '{key.Value}'." + ); + } + } + + private static string LocalBaseId(IMethodSymbol method, IReadOnlyDictionary localIds) => + $"{ContextualId(method.ContainingSymbol!, localIds)}/local/{CallableSignature(method)}"; + + private static string ContextualId(ISymbol symbol, IReadOnlyDictionary localIds) + { + if ( + symbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction } local + && localIds.TryGetValue(local, out string? localId) + ) + { + return localId; + } + if (symbol is IMethodSymbol { MethodKind: MethodKind.AnonymousFunction } lambda) + { + return $"{ContextualId(lambda.ContainingSymbol!, localIds)}/lambda@{CanonicalIdCodec.Encode(SourcePath(lambda))}:{SourceStart(lambda)}"; + } + return OwnedSymbolKey.CanonicalId(symbol.OriginalDefinition); + } + + private static string CallableSignature(IMethodSymbol method) + { + string name = method.Name + (method.Arity == 0 ? string.Empty : $"`{method.Arity}"); + string parameters = string.Join(",", method.Parameters.Select(OwnedSymbolKey.CanonicalIdForParameter)); + return $"{name}({parameters})"; + } + + private static int LocalNestingDepth(IMethodSymbol method) + { + int depth = 0; + for ( + ISymbol? current = method.ContainingSymbol; + current is IMethodSymbol containing && containing.MethodKind == MethodKind.LocalFunction; + current = current.ContainingSymbol + ) + { + depth++; + } + return depth; + } + + private static string SourcePath(IMethodSymbol method) => + method + .Locations.Where(location => location.IsInSource) + .Select(location => location.SourceTree?.FilePath ?? string.Empty) + .OrderBy(path => path, StringComparer.Ordinal) + .FirstOrDefault() + ?? string.Empty; + + private static int SourceStart(IMethodSymbol method) => + method + .Locations.Where(location => location.IsInSource) + .Select(location => location.SourceSpan.Start) + .DefaultIfEmpty(-1) + .Min(); + + private static string ContextLookupKey(IMethodSymbol method) => + $"{method.ContainingAssembly.Identity}\0{method.MethodKind}\0{SourcePath(method)}\0{SourceStart(method)}"; + + private sealed class ProfileIndex + { + internal Dictionary Definitions { get; } = new(StringComparer.Ordinal); + internal Dictionary SymbolKeys { get; } = new(ReferenceEqualityComparer.Instance); + internal Dictionary ContextualKeys { get; } = new(StringComparer.Ordinal); + } + + private readonly record struct ParsedKey(string ProjectId, string AssemblyIdentity, string SymbolId); + + private static ParsedKey Parse(string value) + { + if (!value.StartsWith("owned:", StringComparison.Ordinal)) + throw new CompilerInputException("invalid-owned-key", $"Invalid owned symbol key '{value}'."); + string body = value["owned:".Length..]; + int first = body.IndexOf('/'); + int second = first < 0 ? -1 : body.IndexOf('/', first + 1); + if (first <= 0 || second <= first + 1 || second == body.Length - 1) + throw new CompilerInputException("invalid-owned-key", $"Invalid owned symbol key '{value}'."); + return new ParsedKey(body[..first], body[(first + 1)..second], body[(second + 1)..]); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/PhaseTraceRecorder.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/PhaseTraceRecorder.cs new file mode 100644 index 000000000..6ae3f3904 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/PhaseTraceRecorder.cs @@ -0,0 +1,191 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// The three parse phases a catalog feature declares an effect in. +public enum ParsePhase +{ + /// Unapplication: proposing analyses by undoing rules. + AnalysisCandidate, + + /// Application: confirming a candidate by regenerating its surface. + SynthesisConfirmation, + + /// The verdict on a fully built word. + FinalParse, +} + +/// Records engine trace events bucketed by the phase that emitted them. +/// The engine's trace interface already separates unapplication from application from the +/// final verdict, which is what makes a phase-level claim checkable rather than asserted: a feature +/// is said to act in a phase only when neutralizing it changes that phase's events. +public sealed class PhaseTraceRecorder : ITraceManager +{ + private readonly Dictionary> _events = new() + { + [ParsePhase.AnalysisCandidate] = new List(), + [ParsePhase.SynthesisConfirmation] = new List(), + [ParsePhase.FinalParse] = new List(), + }; + + public bool IsTracing { get; set; } = true; + + /// The recorded events of one phase, in the order the engine emitted them. + public IReadOnlyList Events(ParsePhase phase) => _events[phase]; + + /// An order-insensitive digest of a phase, for comparing two runs. + /// Order is deliberately dropped: the engine parallelizes synthesis, so event order is + /// not stable between runs of the same grammar and would report differences that are not + /// semantic ones. + public string Digest(ParsePhase phase) => + string.Join( + "\n", + _events[phase] + .GroupBy(item => item, StringComparer.Ordinal) + .OrderBy(group => group.Key, StringComparer.Ordinal) + .Select(group => $"{group.Count().ToString(CultureInfo.InvariantCulture)}x {group.Key}") + ); + + private void Record(ParsePhase phase, string kind, params string?[] parts) => + _events[phase] + .Add( + parts.Length == 0 ? kind : kind + "(" + string.Join(",", parts.Select(part => part ?? "")) + ")" + ); + + private static string RuleName(IHCRule? rule) => rule?.Name ?? ""; + + private static string Index(int value) => value.ToString(CultureInfo.InvariantCulture); + + public object GenerateWords(Language lang) => new object(); + + // Analysis: every unapplication hook. + public void AnalyzeWord(Language lang, Word input) => Record(ParsePhase.AnalysisCandidate, "AnalyzeWord"); + + public void BeginUnapplyStratum(Stratum stratum, Word input) => + Record(ParsePhase.AnalysisCandidate, "BeginUnapplyStratum", stratum?.Name); + + public void EndUnapplyStratum(Stratum stratum, Word output) => + Record(ParsePhase.AnalysisCandidate, "EndUnapplyStratum", stratum?.Name); + + public void PhonologicalRuleUnapplied(IPhonologicalRule rule, int subruleIndex, Word input, Word output) => + Record(ParsePhase.AnalysisCandidate, "PhonologicalRuleUnapplied", RuleName(rule), Index(subruleIndex)); + + public void PhonologicalRuleNotUnapplied(IPhonologicalRule rule, int subruleIndex, Word input) => + Record(ParsePhase.AnalysisCandidate, "PhonologicalRuleNotUnapplied", RuleName(rule), Index(subruleIndex)); + + public void BeginUnapplyTemplate(AffixTemplate template, Word input) => + Record(ParsePhase.AnalysisCandidate, "BeginUnapplyTemplate", template?.Name); + + public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied) => + Record(ParsePhase.AnalysisCandidate, "EndUnapplyTemplate", template?.Name, unapplied.ToString()); + + public void MorphologicalRuleUnapplied(IMorphologicalRule rule, int subruleIndex, Word input, Word output) => + Record(ParsePhase.AnalysisCandidate, "MorphologicalRuleUnapplied", RuleName(rule), Index(subruleIndex)); + + public void MorphologicalRuleNotUnapplied(IMorphologicalRule rule, int subruleIndex, Word input) => + Record(ParsePhase.AnalysisCandidate, "MorphologicalRuleNotUnapplied", RuleName(rule), Index(subruleIndex)); + + public void CompoundingRuleNotUnapplied( + IMorphologicalRule rule, + int subruleIndex, + Word input, + FailureReason reason, + object failureObj + ) => + Record( + ParsePhase.AnalysisCandidate, + "CompoundingRuleNotUnapplied", + RuleName(rule), + Index(subruleIndex), + reason.ToString() + ); + + // The hinge, and the engine puts it on the synthesis side: Morpher.Synthesize calls it per + // analysis to find the entries a rebuild can start from. + public void LexicalLookup(Stratum stratum, Word input) => + Record(ParsePhase.SynthesisConfirmation, "LexicalLookup", stratum?.Name); + + // Synthesis: every application hook. + public void SynthesizeWord(Language lang, Word input) => Record(ParsePhase.SynthesisConfirmation, "SynthesizeWord"); + + public void BeginApplyStratum(Stratum stratum, Word input) => + Record(ParsePhase.SynthesisConfirmation, "BeginApplyStratum", stratum?.Name); + + public void NonFinalTemplateAppliedLast(Stratum stratum, Word word) => + Record(ParsePhase.SynthesisConfirmation, "NonFinalTemplateAppliedLast", stratum?.Name); + + public void ApplicableTemplatesNotApplied(Stratum stratum, Word word) => + Record(ParsePhase.SynthesisConfirmation, "ApplicableTemplatesNotApplied", stratum?.Name); + + public void EndApplyStratum(Stratum stratum, Word output) => + Record(ParsePhase.SynthesisConfirmation, "EndApplyStratum", stratum?.Name); + + public void PhonologicalRuleApplied(IPhonologicalRule rule, int subruleIndex, Word input, Word output) => + Record(ParsePhase.SynthesisConfirmation, "PhonologicalRuleApplied", RuleName(rule), Index(subruleIndex)); + + public void PhonologicalRuleNotApplied( + IPhonologicalRule rule, + int subruleIndex, + Word input, + FailureReason reason, + object failureObj + ) => + Record( + ParsePhase.SynthesisConfirmation, + "PhonologicalRuleNotApplied", + RuleName(rule), + Index(subruleIndex), + reason.ToString() + ); + + public void BeginApplyTemplate(AffixTemplate template, Word input) => + Record(ParsePhase.SynthesisConfirmation, "BeginApplyTemplate", template?.Name); + + public void EndApplyTemplate(AffixTemplate template, Word output, bool applied) => + Record(ParsePhase.SynthesisConfirmation, "EndApplyTemplate", template?.Name, applied.ToString()); + + public void MorphologicalRuleApplied(IMorphologicalRule rule, int subruleIndex, Word input, Word output) => + Record(ParsePhase.SynthesisConfirmation, "MorphologicalRuleApplied", RuleName(rule), Index(subruleIndex)); + + public void MorphologicalRuleNotApplied( + IMorphologicalRule rule, + int subruleIndex, + Word input, + FailureReason reason, + object failureObj + ) => + Record( + ParsePhase.SynthesisConfirmation, + "MorphologicalRuleNotApplied", + RuleName(rule), + Index(subruleIndex), + reason.ToString() + ); + + public void CompoundingRuleNotApplied( + IMorphologicalRule rule, + int subruleIndex, + Word input, + FailureReason reason, + object failureObj + ) => + Record( + ParsePhase.SynthesisConfirmation, + "CompoundingRuleNotApplied", + RuleName(rule), + Index(subruleIndex), + reason.ToString() + ); + + // Final parse: the verdict on a completed word. + public void Blocked(IHCRule rule, Word output) => Record(ParsePhase.FinalParse, "Blocked", RuleName(rule)); + + public void Successful(Language lang, Word word) => Record(ParsePhase.FinalParse, "Successful"); + + public void Failed(Language lang, Word word, FailureReason reason, Allomorph allomorph, object failureObj) => + Record(ParsePhase.FinalParse, "Failed", reason.ToString()); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/PosDisjointProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/PosDisjointProofs.cs new file mode 100644 index 000000000..2331f9192 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/PosDisjointProofs.cs @@ -0,0 +1,349 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind : two rules whose part-of-speech +/// gates are mutually exclusive, so no root can ever satisfy both. Two shapes are modeled: +/// +/// - A MorphologicalRule/MorphologicalRule pair, on requiredPartsOfSpeech directly -- +/// the DTD's own IDREF cardinality (LexicalEntry@partOfSpeech is a single IDREF) means one root +/// carries exactly one part of speech. +/// - A PhonologicalRule/PhonologicalRule pair, on the union of each rule's +/// PhonologicalSubrule@requiredPartsOfSpeech values -- a rule's active subrules are alternatives, +/// so the rule's own POS gate is whichever of them can fire. +/// +/// This is the dangerous kind: POS-disjointness only rules out interaction when nothing in the grammar +/// can convert one part of speech into the other before the second rule is reached. This check is +/// therefore conservative by construction -- see this file's bridging step and remarks below for exactly +/// what it can and cannot see. +/// +/// NOT MODELED, all failing closed to : RealizationalRule +/// (no requiredPartsOfSpeech attribute at all -- it applies regardless of POS), +/// CompoundingRule (a headPartsOfSpeech/nonHeadPartsOfSpeech pair, a different shape +/// entirely), and MetathesisRule (no requiredPartsOfSpeech at all). A rule with no active +/// subrule declaring a restriction -- including a rule with zero active subrules -- is UNRESTRICTED and +/// can never be proven disjoint from anything; that inversion (treating "no restriction" as "disjoint from +/// everything") is the one this check must never make. +/// +/// BRIDGING, checked but incomplete: any active MorphologicalRule or CompoundingRule +/// anywhere in the document (not only the owning Stratum, which is the safe direction -- more +/// Undetermined, never a missed bridge within scope) whose outputPartOfSpeech reaches either +/// compared rule's required set is treated as a possible bridge unless it is a MorphologicalRule +/// with a nonempty required set wholly contained in the same disjoint side as its output. Such a +/// rule preserves its own side and cannot bridge; a rule that can accept the opposite side, has an +/// unrestricted or otherwise unclassified input gate, or is a CompoundingRule remains a blocker. +/// This is a single hop: it does not check whether that bridging rule's OWN requiredPartsOfSpeech +/// is itself reachable from any root, so a bridge that is itself unreachable still blocks the proof -- +/// safe (it can only under-prove, never over-prove) but not exhaustive. It also cannot see a bridge built +/// from RequiredHeadFeatures/RequiredFootFeatures or any output the loader derives without +/// setting outputPartOfSpeech textually, since no other conversion channel is inspected. +/// +public static class PosDisjointProofs +{ + public const string Kind = "pos-disjoint"; + + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + PosDisjointCheck check = Check(grammar, item); + return check.Relation == PosRelation.Disjoint ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies : true only when 's freshly + /// generated adjacent pairs still contain an item with 's id AND the check + /// recomputes for it. A stale id, a recomputed overlap, and a + /// recomputed bridge all fail closed to false. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return Check(grammar, item).Relation == PosRelation.Disjoint; + } + + private enum PosRelation + { + Disjoint, + Overlaps, + Undetermined, + } + + private sealed record PosDisjointCheck(string ItemId, PosRelation Relation, string Reason); + + private static PosDisjointCheck Check(XDocument grammar, OrderingItem item) => + item.Kind switch + { + OrderingListKind.StratumMorphologicalRules => CheckMorphologicalPair(grammar, item), + OrderingListKind.StratumPhonologicalRules => CheckPhonologicalPair(grammar, item), + _ => new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"{item.Kind} pairs are not modeled -- only Stratum morphologicalRules/phonologicalRules pairs " + + "resolve to a requiredPartsOfSpeech comparison" + ), + }; + + private static PosDisjointCheck CheckMorphologicalPair(XDocument grammar, OrderingItem item) + { + XElement? ruleA = FindElementById(grammar, item.MemberA); + XElement? ruleB = FindElementById(grammar, item.MemberB); + if (ruleA is null || ruleB is null) + { + string missing = ruleA is null ? item.MemberA : item.MemberB; + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"'{missing}' was not found as an element with a matching id attribute" + ); + } + if (ruleA.Name.LocalName != "MorphologicalRule" || ruleB.Name.LocalName != "MorphologicalRule") + { + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"<{ruleA.Name.LocalName}>/<{ruleB.Name.LocalName}> is not modeled -- only a MorphologicalRule/MorphologicalRule " + + "pair has a plain requiredPartsOfSpeech to compare (RealizationalRule has none; CompoundingRule uses a " + + "different head/nonhead shape)" + ); + } + + HashSet? reqA = RequiredPartsOfSpeech(ruleA); + HashSet? reqB = RequiredPartsOfSpeech(ruleB); + if (reqA is null || reqA.Count == 0 || reqB is null || reqB.Count == 0) + { + return new PosDisjointCheck( + item.Id, + PosRelation.Overlaps, + $"'{(reqA is null || reqA.Count == 0 ? item.MemberA : item.MemberB)}' declares no requiredPartsOfSpeech, " + + "so it applies regardless of part of speech" + ); + } + + string[] shared = reqA.Intersect(reqB, StringComparer.Ordinal) + .OrderBy(s => s, StringComparer.Ordinal) + .ToArray(); + if (shared.Length > 0) + { + return new PosDisjointCheck( + item.Id, + PosRelation.Overlaps, + $"requiredPartsOfSpeech share {{{string.Join(",", shared)}}}" + ); + } + + HashSet union = reqA.Union(reqB, StringComparer.Ordinal).ToHashSet(StringComparer.Ordinal); + XElement? bridge = FindBridgingRule(grammar, union, reqA, reqB); + if (bridge is not null) + { + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"possible bridge: <{bridge.Name.LocalName}> '{(string?)bridge.Attribute("id")}' outputs a part of speech " + + $"in {{{string.Join(",", union.OrderBy(s => s, StringComparer.Ordinal))}}}" + ); + } + + return new PosDisjointCheck( + item.Id, + PosRelation.Disjoint, + $"'{item.MemberA}' requires {{{string.Join(",", reqA.OrderBy(s => s, StringComparer.Ordinal))}}}, " + + $"'{item.MemberB}' requires {{{string.Join(",", reqB.OrderBy(s => s, StringComparer.Ordinal))}}}, disjoint, " + + "and no modeled active MorphologicalRule/CompoundingRule can bridge the compared part-of-speech sets " + + "(same-side MorphologicalRule preservation is excluded)" + ); + } + + // A PhonologicalRule's own POS gate is not on the rule element -- it is the union of whichever active + // PhonologicalSubrule can fire, since the subrules are alternatives. A subrule with no + // requiredPartsOfSpeech fires regardless of POS, which makes the WHOLE rule unrestricted; that is why + // this returns Unrestricted rather than an empty set the caller could mistake for "requires nothing". + private enum SubrulePosKind + { + NoActiveSubrules, + Unrestricted, + Restricted, + } + + private sealed record SubrulePosResolution(SubrulePosKind Kind, HashSet PartsOfSpeech); + + private static SubrulePosResolution SubruleRequiredPartsOfSpeech(XElement rule) + { + List subrules = ( + rule.Element("PhonologicalSubrules")?.Elements("PhonologicalSubrule") ?? Enumerable.Empty() + ) + .Where(IsActiveElement) + .ToList(); + if (subrules.Count == 0) + { + return new SubrulePosResolution( + SubrulePosKind.NoActiveSubrules, + new HashSet(StringComparer.Ordinal) + ); + } + + var union = new HashSet(StringComparer.Ordinal); + foreach (XElement subrule in subrules) + { + HashSet? pos = RequiredPartsOfSpeech(subrule); + if (pos is null || pos.Count == 0) + { + return new SubrulePosResolution( + SubrulePosKind.Unrestricted, + new HashSet(StringComparer.Ordinal) + ); + } + union.UnionWith(pos); + } + return new SubrulePosResolution(SubrulePosKind.Restricted, union); + } + + private static PosDisjointCheck CheckPhonologicalPair(XDocument grammar, OrderingItem item) + { + XElement? ruleA = FindElementById(grammar, item.MemberA); + XElement? ruleB = FindElementById(grammar, item.MemberB); + if (ruleA is null || ruleB is null) + { + string missing = ruleA is null ? item.MemberA : item.MemberB; + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"'{missing}' was not found as an element with a matching id attribute" + ); + } + if (ruleA.Name.LocalName != "PhonologicalRule" || ruleB.Name.LocalName != "PhonologicalRule") + { + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"<{ruleA.Name.LocalName}>/<{ruleB.Name.LocalName}> is not modeled -- only a PhonologicalRule/PhonologicalRule " + + "pair has PhonologicalSubrule requiredPartsOfSpeech to compare (MetathesisRule has none)" + ); + } + + SubrulePosResolution resA = SubruleRequiredPartsOfSpeech(ruleA); + SubrulePosResolution resB = SubruleRequiredPartsOfSpeech(ruleB); + if (resA.Kind == SubrulePosKind.NoActiveSubrules || resB.Kind == SubrulePosKind.NoActiveSubrules) + { + string missing = resA.Kind == SubrulePosKind.NoActiveSubrules ? item.MemberA : item.MemberB; + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"'{missing}' has no active PhonologicalSubrule children" + ); + } + if (resA.Kind == SubrulePosKind.Unrestricted || resB.Kind == SubrulePosKind.Unrestricted) + { + string unrestricted = resA.Kind == SubrulePosKind.Unrestricted ? item.MemberA : item.MemberB; + return new PosDisjointCheck( + item.Id, + PosRelation.Overlaps, + $"'{unrestricted}' has an active PhonologicalSubrule with no requiredPartsOfSpeech, so it applies regardless of part of speech" + ); + } + + string[] shared = resA + .PartsOfSpeech.Intersect(resB.PartsOfSpeech, StringComparer.Ordinal) + .OrderBy(s => s, StringComparer.Ordinal) + .ToArray(); + if (shared.Length > 0) + { + return new PosDisjointCheck( + item.Id, + PosRelation.Overlaps, + $"requiredPartsOfSpeech share {{{string.Join(",", shared)}}}" + ); + } + + HashSet union = resA + .PartsOfSpeech.Union(resB.PartsOfSpeech, StringComparer.Ordinal) + .ToHashSet(StringComparer.Ordinal); + XElement? bridge = FindBridgingRule(grammar, union, resA.PartsOfSpeech, resB.PartsOfSpeech); + if (bridge is not null) + { + return new PosDisjointCheck( + item.Id, + PosRelation.Undetermined, + $"possible bridge: <{bridge.Name.LocalName}> '{(string?)bridge.Attribute("id")}' outputs a part of speech " + + $"in {{{string.Join(",", union.OrderBy(s => s, StringComparer.Ordinal))}}}" + ); + } + + return new PosDisjointCheck( + item.Id, + PosRelation.Disjoint, + $"'{item.MemberA}' PhonologicalSubrules require {{{string.Join(",", resA.PartsOfSpeech.OrderBy(s => s, StringComparer.Ordinal))}}}, " + + $"'{item.MemberB}' PhonologicalSubrules require {{{string.Join(",", resB.PartsOfSpeech.OrderBy(s => s, StringComparer.Ordinal))}}}, " + + "disjoint, and no modeled active MorphologicalRule/CompoundingRule can bridge the compared part-of-speech sets " + + "(same-side MorphologicalRule preservation is excluded)" + ); + } + + private static HashSet? RequiredPartsOfSpeech(XElement rule) + { + string? value = (string?)rule.Attribute("requiredPartsOfSpeech"); + return string.IsNullOrEmpty(value) + ? null + : value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries).ToHashSet(StringComparer.Ordinal); + } + + // Single-hop over-approximation: every active MorphologicalRule/CompoundingRule in the whole document + // (not just the owning Stratum) whose outputPartOfSpeech lands in the union is a candidate bridge, + // regardless of whether that rule's own inputs are themselves reachable. A MorphologicalRule is + // exempt only when its nonempty required POS set is wholly contained in the same side as its output; + // CompoundingRule remains conservative because its input shape is different. See this file's header. + private static XElement? FindBridgingRule( + XDocument grammar, + HashSet union, + HashSet requiredA, + HashSet requiredB + ) => + grammar + .Descendants() + .Where(e => e.Name.LocalName is "MorphologicalRule" or "CompoundingRule") + .Where(IsActiveElement) + .FirstOrDefault(e => + { + string? outPos = (string?)e.Attribute("outputPartOfSpeech"); + if (string.IsNullOrEmpty(outPos) || !union.Contains(outPos)) + return false; + + return !IsSameSideMorphologicalPreservation(e, outPos, requiredA, requiredB); + }); + + private static bool IsSameSideMorphologicalPreservation( + XElement candidate, + string outputPartOfSpeech, + HashSet requiredA, + HashSet requiredB + ) + { + if (candidate.Name.LocalName != "MorphologicalRule") + return false; + + HashSet? required = RequiredPartsOfSpeech(candidate); + if (required is null || required.Count == 0) + return false; + + bool outputOnSideA = requiredA.Contains(outputPartOfSpeech); + bool outputOnSideB = requiredB.Contains(outputPartOfSpeech); + return (outputOnSideA && required.IsSubsetOf(requiredA)) || (outputOnSideB && required.IsSubsetOf(requiredB)); + } + + private static bool IsActiveElement(XElement element) => (string?)element.Attribute("isActive") != "no"; + + private static XElement? FindElementById(XDocument grammar, string id) => + grammar.Descendants().FirstOrDefault(e => (string?)e.Attribute("id") == id); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RaiseSiteScanner.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RaiseSiteScanner.cs new file mode 100644 index 000000000..3c2f322c5 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RaiseSiteScanner.cs @@ -0,0 +1,90 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Finds every source location in the core engine (src/SIL.Machine.Morphology.HermitCrab, never +/// this Conformance project or the Tool project, which only ever READ a +/// back off a trace) that passes a non- member as a value -- the +/// raise_sites column reports per gate. +/// +/// Purely textual: a literal FailureReason.Member occurrence, skipping a `//`-commented line and +/// a `==`/`!=` comparison (the only two shapes that appear in this engine and are NOT a raise -- see +/// e.g. ParseCommand.cs's and SynthesisRewriteRule.cs's own comparisons against +/// ). Deliberately mechanical rather than a hand-curated list, so the +/// checked-in ledger cannot silently drift from the source it claims to describe. +/// +public static class RaiseSiteScanner +{ + private static readonly Regex Reference = new(@"FailureReason\.(\w+)", RegexOptions.Compiled); + + public static IReadOnlyDictionary> Scan(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string engineRoot = Path.Combine(repositoryRoot, "src", "SIL.Machine.Morphology.HermitCrab"); + var sites = new Dictionary>(StringComparer.Ordinal); + + foreach (string path in Directory.EnumerateFiles(engineRoot, "*.cs", SearchOption.AllDirectories)) + { + if ( + path.Contains( + $"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", + StringComparison.Ordinal + ) + || path.Contains( + $"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", + StringComparison.Ordinal + ) + ) + { + continue; + } + + string fileName = Path.GetFileName(path); + string[] lines = File.ReadAllLines(path); + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + if (line.TrimStart().StartsWith("//", StringComparison.Ordinal)) + continue; + + foreach (Match match in Reference.Matches(line)) + { + string member = match.Groups[1].Value; + if (member == "None") + continue; + + string before = line[..match.Index].TrimEnd(); + if ( + before.EndsWith("==", StringComparison.Ordinal) + || before.EndsWith("!=", StringComparison.Ordinal) + ) + { + continue; + } + + if (!sites.TryGetValue(member, out List<(string File, int Line)>? list)) + sites[member] = list = new List<(string, int)>(); + list.Add((fileName, i + 1)); + } + } + } + + return sites.ToDictionary( + kv => kv.Key, + kv => + (IReadOnlyList) + kv + .Value.OrderBy(s => s.File, StringComparer.Ordinal) + .ThenBy(s => s.Line) + .Select(s => $"{s.File}:{s.Line}") + .ToArray(), + StringComparer.Ordinal + ); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RepositoryCompilationGraphLoader.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RepositoryCompilationGraphLoader.cs new file mode 100644 index 000000000..b21a6e9a1 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RepositoryCompilationGraphLoader.cs @@ -0,0 +1,1253 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record CompilationGraphHashEnvironment( + RepositoryCompilationGraph Graph, + IReadOnlyDictionary Captures, + IReadOnlyDictionary CompilerInputs, + string RepositoryRoot, + string PrivateRoot, + string CaptureTarget +); + +internal sealed class RepositoryCompilationGraphLoader +{ + internal static readonly TimeSpan QueryTimeout = TimeSpan.FromSeconds(120); + internal const int MaximumStandardOutputBytes = 64 * 1024 * 1024; + + private const string CaptureProperties = + "PanGlossCompilerInputProtocol,MSBuildAllProjects,AssemblyName,TargetFramework,LangVersion,Nullable," + + "DefineConstants,AllowUnsafeBlocks,CheckForOverflowUnderflow,OutputType,NETCoreSdkVersion,MSBuildVersion,CscToolPath,RoslynAssembliesPath," + + "GeneratedAssemblyInfoFile,TargetFrameworkMonikerAssemblyAttributesPath"; + private const string CaptureItems = + "CscCommandLineArgs,Compile,ProjectReference,ReferencePathWithRefAssemblies,Analyzer,AdditionalFiles,EditorConfigFiles,Using"; + + private readonly IMsBuildProcessRunner _runner; + private readonly Func _privateDirectoryFactory; + private readonly Func? _hashInputBuilder; + + internal RepositoryCompilationGraphLoader( + IMsBuildProcessRunner runner, + Func? privateDirectoryFactory = null, + Func? hashInputBuilder = null + ) + { + _runner = runner ?? throw new ArgumentNullException(nameof(runner)); + _hashInputBuilder = hashInputBuilder; + _privateDirectoryFactory = + privateDirectoryFactory + ?? (() => Path.Combine(Path.GetTempPath(), "hc-semantic-msbuild", Guid.NewGuid().ToString("N"))); + } + + public async ValueTask LoadAsync( + RepositoryRoot root, + CancellationToken cancellationToken + ) + { + ArgumentNullException.ThrowIfNull(root); + ValidateRepositoryRoot(root.FullPath); + RepositoryCompilationGraph graph = RepositoryCompilationGraph.CreateFixed(); + string captureTarget = ResolveRepositoryFile(root.FullPath, "eng/HcSemanticCompilerInputs.targets"); + string privateRoot = Path.GetFullPath(_privateDirectoryFactory()); + if (Directory.Exists(privateRoot) || File.Exists(privateRoot)) + throw new InvalidDataException("The private MSBuild query directory must not already exist."); + Directory.CreateDirectory(privateRoot); + + try + { + var baseDefines = new Dictionary(StringComparer.Ordinal); + foreach (RepositoryProjectDefinition project in graph.Projects) + { + ProjectPaths paths = ValidateProjectInputs(root.FullPath, project); + ProcessCapture capture = await RunCheckedAsync( + CreateBasePropertyQuery(root.FullPath, project, paths), + cancellationToken + ) + .ConfigureAwait(false); + baseDefines.Add(project.Id, ParseBaseDefines(capture.StandardOutput, project.TargetFramework)); + } + + var captures = new Dictionary(); + var compilerInputs = new Dictionary(); + foreach (RepositoryGraphNode node in graph.Nodes) + { + RepositoryProjectDefinition project = graph.Projects.Single(item => item.Id == node.ProjectId); + ProjectPaths paths = ValidateProjectInputs(root.FullPath, project); + string nodeIntermediate = Path.Combine( + privateRoot, + SafeSegment(node.ProjectId), + SafeSegment(node.Profile.Id) + ); + Directory.CreateDirectory(nodeIntermediate); + ValidateNoReparsePoints(privateRoot, nodeIntermediate); + string defines = CanonicalDefineUnion(baseDefines[node.ProjectId], node.Profile.AdditionalSymbols); + ProcessCapture capture = await RunCheckedAsync( + CreateCaptureQuery(root.FullPath, project, paths, captureTarget, nodeIntermediate, defines), + cancellationToken + ) + .ConfigureAwait(false); + CapturedCompilerInputs parsed = MsBuildCaptureProtocol.Parse(capture.StandardOutput); + string capturedTargetFramework = parsed.Properties["TargetFramework"]; + if (!string.Equals(capturedTargetFramework, node.TargetFramework, StringComparison.Ordinal)) + { + throw new InvalidDataException( + $"MSBuild returned target framework '{capturedTargetFramework}' for '{node.Key}', expected '{node.TargetFramework}'." + ); + } + ValidatePrivateGeneratedFile( + privateRoot, + nodeIntermediate, + parsed.Properties["GeneratedAssemblyInfoFile"] + ); + ValidatePrivateGeneratedFile( + privateRoot, + nodeIntermediate, + parsed.Properties["TargetFrameworkMonikerAssemblyAttributesPath"] + ); + captures.Add(node.Key, parsed); + string projectDirectory = + Path.GetDirectoryName(paths.ProjectFile) + ?? throw new InvalidDataException("Project path has no directory."); + CompilerInputModel normalized = CSharpCommandLineInputParser.Parse( + parsed, + root.FullPath, + projectDirectory, + nodeIntermediate, + node.Profile.AdditionalSymbols, + new CompilerToolchainIdentity(parsed.Properties["RoslynAssembliesPath"]) + ); + compilerInputs.Add(node.Key, normalized); + } + + CompilationGraphHashEnvironment environment = new( + graph, + captures, + compilerInputs, + root.FullPath, + privateRoot, + captureTarget + ); + CompilationGraphHashInputs hashInputs = _hashInputBuilder is null + ? BuildHashInputs(environment) + : _hashInputBuilder(environment) + ?? throw new InvalidDataException("The hash-input builder returned null."); + RepositoryCompilationGraph capturedGraph = graph.WithCaptures(captures).WithCompilerInputs(compilerInputs); + return capturedGraph.WithHashInputs(hashInputs).WithHashes(CompilationGraphHashing.Compute(hashInputs)); + } + finally + { + DeletePrivateDirectory(privateRoot); + } + } + + private async ValueTask RunCheckedAsync( + ProcessStartInfo startInfo, + CancellationToken cancellationToken + ) + { + ProcessCapture capture = await _runner + .RunAsync(startInfo, QueryTimeout, MaximumStandardOutputBytes, cancellationToken) + .ConfigureAwait(false); + if (capture.ExitCode != 0) + { + string output = Encoding.UTF8.GetString(capture.StandardOutput); + throw new InvalidDataException( + $"MSBuild exited with code {capture.ExitCode}. stderr: {capture.StandardError.Trim()} stdout: {output.Trim()}" + ); + } + if (!string.IsNullOrWhiteSpace(capture.StandardError)) + throw new InvalidDataException($"MSBuild wrote to standard error: {capture.StandardError.Trim()}"); + if (capture.StandardOutput.Length > MaximumStandardOutputBytes) + throw new InvalidDataException("MSBuild standard output exceeded the configured limit."); + return capture; + } + + private static ProcessStartInfo CreateBasePropertyQuery( + string repositoryRoot, + RepositoryProjectDefinition project, + ProjectPaths paths + ) + { + ProcessStartInfo start = CreateStartInfo(repositoryRoot, paths.ProjectFile); + AddCommonEvaluationArguments(start, project, paths); + start.ArgumentList.Add("-getProperty:DefineConstants,TargetFramework"); + return start; + } + + private static ProcessStartInfo CreateCaptureQuery( + string repositoryRoot, + RepositoryProjectDefinition project, + ProjectPaths paths, + string captureTarget, + string intermediateDirectory, + string defineConstants + ) + { + ProcessStartInfo start = CreateStartInfo(repositoryRoot, paths.ProjectFile); + AddCommonEvaluationArguments(start, project, paths); + start.ArgumentList.Add("/t:_PanGlossCaptureCompilerInputs"); + start.ArgumentList.Add("/p:SkipCompilerExecution=true"); + start.ArgumentList.Add("/p:ProvideCommandLineArgs=true"); + start.ArgumentList.Add($"/p:CustomAfterMicrosoftCommonTargets={captureTarget}"); + start.ArgumentList.Add( + $"/p:IntermediateOutputPath={Path.TrimEndingDirectorySeparator(intermediateDirectory)}{Path.DirectorySeparatorChar}" + ); + start.ArgumentList.Add($"/p:DefineConstants={defineConstants.Replace(";", "%3B", StringComparison.Ordinal)}"); + start.ArgumentList.Add($"-getProperty:{CaptureProperties}"); + start.ArgumentList.Add($"-getItem:{CaptureItems}"); + return start; + } + + private static ProcessStartInfo CreateStartInfo(string repositoryRoot, string projectFile) + { + var start = new ProcessStartInfo + { + FileName = "dotnet", + WorkingDirectory = repositoryRoot, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }; + start.ArgumentList.Add("msbuild"); + start.ArgumentList.Add(projectFile); + start.ArgumentList.Add("--noAutoResponse"); + start.ArgumentList.Add("/nologo"); + start.ArgumentList.Add("/nr:false"); + start.ArgumentList.Add("/v:quiet"); + return start; + } + + private static void AddCommonEvaluationArguments( + ProcessStartInfo start, + RepositoryProjectDefinition project, + ProjectPaths paths + ) + { + start.ArgumentList.Add("/p:Configuration=Release"); + start.ArgumentList.Add($"/p:TargetFramework={project.TargetFramework}"); + start.ArgumentList.Add("/p:BuildProjectReferences=false"); + start.ArgumentList.Add("/p:RestoreIgnoreFailedSources=false"); + start.ArgumentList.Add( + $"/p:MSBuildProjectExtensionsPath={Path.TrimEndingDirectorySeparator(paths.ObjDirectory)}{Path.DirectorySeparatorChar}" + ); + start.ArgumentList.Add($"/p:ProjectAssetsFile={paths.AssetsFile}"); + } + + private static string[] ParseBaseDefines(byte[] json, string expectedTargetFramework) + { + try + { + using JsonDocument document = JsonDocument.Parse(json); + JsonElement properties = document.RootElement.GetProperty("Properties"); + string? value = properties.GetProperty("DefineConstants").GetString(); + string? targetFramework = properties.GetProperty("TargetFramework").GetString(); + if (value is null) + throw new InvalidDataException("MSBuild returned a null DefineConstants property."); + if (!string.Equals(targetFramework, expectedTargetFramework, StringComparison.Ordinal)) + { + throw new InvalidDataException( + $"MSBuild base evaluation returned target framework '{targetFramework}', expected '{expectedTargetFramework}'." + ); + } + return value.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + } + catch (Exception exception) + when (exception is JsonException or KeyNotFoundException or InvalidOperationException) + { + throw new InvalidDataException("MSBuild base-property output is invalid.", exception); + } + } + + private static string CanonicalDefineUnion( + IReadOnlyCollection baseDefines, + IReadOnlyCollection additionalDefines + ) => + string.Join( + ";", + baseDefines + .Concat(additionalDefines) + .Where(value => !string.IsNullOrWhiteSpace(value)) + .Distinct(StringComparer.Ordinal) + .OrderBy(value => value, StringComparer.Ordinal) + ); + + private static CompilationGraphHashInputs BuildHashInputs(CompilationGraphHashEnvironment environment) + { + RepositoryCompilationGraph graph = environment.Graph; + IReadOnlyDictionary captures = environment.Captures; + IReadOnlyDictionary compilerInputs = environment.CompilerInputs; + string repositoryRoot = environment.RepositoryRoot; + string privateRoot = environment.PrivateRoot; + string captureTarget = environment.CaptureTarget; + ProjectPaths[] projectPaths = graph + .Projects.Select(project => ValidateProjectInputs(repositoryRoot, project)) + .ToArray(); + LogicalPathRoots roots = InferLogicalRoots(repositoryRoot, privateRoot, captures.Values, projectPaths); + GraphHashFile targetFile = ReadHashFile(captureTarget, roots, GraphHashFileKind.Text); + + var projects = graph + .Projects.Select(project => new ProjectHashInput( + project.Id, + LogicalPathTokens.FromAbsolute(Path.Combine(repositoryRoot, project.RelativePath), roots), + project.TargetFramework + )) + .ToArray(); + var profiles = graph + .Profiles.Select(profile => new ProfileHashInput(profile.Id, profile.AdditionalSymbols)) + .ToArray(); + var nodes = new List(graph.Nodes.Count); + foreach (RepositoryGraphNode node in graph.Nodes) + { + CapturedCompilerInputs capture = captures[node.Key]; + CompilerInputModel input = compilerInputs[node.Key]; + RepositoryProjectDefinition project = graph.Projects.Single(item => item.Id == node.ProjectId); + ProjectPaths paths = projectPaths.Single(item => + string.Equals( + item.ProjectFile, + Path.GetFullPath(project.RelativePath, repositoryRoot), + OperatingSystem.IsWindows() ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal + ) + ); + nodes.Add( + BuildNodeHashInput( + graph, + node, + capture, + input, + compilerInputs, + paths, + roots, + repositoryRoot, + privateRoot + ) + ); + } + + OptionalGraphHashFile lockFile = ReadLockFile(projectPaths, roots); + ToolchainHashInput toolchain = BuildToolchainHashInput(captures.Values, roots); + return new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + projects, + profiles, + nodes, + graph.ProjectEdges, + toolchain, + targetFile, + lockFile + ); + } + + private static NodeHashInput BuildNodeHashInput( + RepositoryCompilationGraph graph, + RepositoryGraphNode node, + CapturedCompilerInputs capture, + CompilerInputModel input, + IReadOnlyDictionary compilerInputs, + ProjectPaths paths, + LogicalPathRoots roots, + string repositoryRoot, + string privateRoot + ) + { + var settings = capture.Properties.ToDictionary( + pair => pair.Key, + pair => NormalizeStableValue(pair.Key, pair.Value, roots), + StringComparer.Ordinal + ); + settings["ProfileSymbols"] = string.Join( + ";", + node.Profile.AdditionalSymbols.OrderBy(symbol => symbol, StringComparer.Ordinal) + ); + + var arguments = capture + .Items["CscCommandLineArgs"] + .Select((item, ordinal) => new OrderedHashValue(ordinal, NormalizeArgument(item.Identity, roots))) + .ToArray(); + var sources = input + .Sources.Select( + (source, ordinal) => + new OrderedGraphHashFile( + ordinal, + new GraphHashFile( + LogicalPathTokens.FromAbsolute(source.Path, roots), + source.Content, + GraphHashFileKind.Text + ) + ) + ) + .ToArray(); + + var references = BuildReferenceInputs(graph, node, compilerInputs, capture, roots, repositoryRoot); + var projectReferences = BuildProjectReferences(graph, node, capture, repositoryRoot); + var analyzers = BuildAnalyzerInputs(input, roots, repositoryRoot, node.TargetFramework); + var additionalFiles = BuildAuxiliaryFiles( + input.AdditionalFiles, + capture.Items["AdditionalFiles"], + roots, + repositoryRoot, + GraphHashFileKind.Text + ); + var editorConfigFiles = BuildAuxiliaryFiles( + input.AnalyzerConfigs, + capture.Items["EditorConfigFiles"], + roots, + repositoryRoot, + GraphHashFileKind.Text, + admitAncestorEditorConfig: true + ); + if (editorConfigFiles.Count == 0) + { + string generatedConfig = Path.Combine( + privateRoot, + SafeSegment(node.ProjectId), + SafeSegment(node.Profile.Id), + ".editorconfig" + ); + string repositoryConfig = Path.Combine(repositoryRoot, ".editorconfig"); + if (!File.Exists(repositoryConfig)) + throw new FileNotFoundException("Fallback analyzer configuration is missing.", repositoryConfig); + editorConfigFiles.Add( + new GraphHashFile( + LogicalPathTokens.FromAbsolute(generatedConfig, roots), + ImmutableArray.CreateRange(File.ReadAllBytes(repositoryConfig)), + GraphHashFileKind.Text + ) + ); + } + + ProjectPaths projectPath = paths; + var assets = new List { ReadHashFile(projectPath.AssetsFile, roots, GraphHashFileKind.Json) }; + string projectName = Path.GetFileNameWithoutExtension(projectPath.ProjectFile); + assets.Add( + ReadHashFile( + Path.Combine(projectPath.ObjDirectory, $"{projectName}.csproj.nuget.g.props"), + roots, + GraphHashFileKind.Text + ) + ); + assets.Add( + ReadHashFile( + Path.Combine(projectPath.ObjDirectory, $"{projectName}.csproj.nuget.g.targets"), + roots, + GraphHashFileKind.Text + ) + ); + + var imports = new List(); + foreach (string import in SplitMsBuildPaths(capture.Properties["MSBuildAllProjects"])) + { + string path = ResolveCapturePath(import, roots, Path.GetDirectoryName(projectPath.ProjectFile)!); + imports.Add(ReadHashFile(path, roots, GraphHashFileKind.Text)); + } + if (imports.Count == 0) + throw new InvalidDataException($"MSBuildAllProjects for '{node.Key}' did not contain a file import."); + + return new NodeHashInput( + node.Key, + settings, + arguments, + sources, + references, + projectReferences, + analyzers, + additionalFiles, + editorConfigFiles, + Array.Empty(), + assets, + imports + ); + } + + private static List BuildReferenceInputs( + RepositoryCompilationGraph graph, + RepositoryGraphNode node, + IReadOnlyDictionary compilerInputs, + CapturedCompilerInputs capture, + LogicalPathRoots roots, + string repositoryRoot + ) + { + var result = new List(); + IReadOnlyList captured = capture.Items["ReferencePathWithRefAssemblies"]; + var owned = TransitiveOwnedProjects(graph, node.ProjectId).ToHashSet(StringComparer.Ordinal); + var everyOwnedAssemblyName = graph.Projects.ToDictionary( + project => project.Id, + project => + ProjectAssemblyName( + project.Id, + compilerInputs[ + graph + .Nodes.First(item => item.ProjectId == project.Id && item.Profile.Id == node.Profile.Id) + .Key + ] + ), + StringComparer.Ordinal + ); + var admittedOwnedAssemblyNames = everyOwnedAssemblyName + .Where(pair => owned.Contains(pair.Key)) + .ToDictionary(pair => pair.Value, pair => pair.Key, StringComparer.OrdinalIgnoreCase); + foreach (CapturedCompilerItem item in captured) + { + string identity = item.Identity; + IReadOnlyDictionary metadata = item.Metadata; + string capturedPath = metadata.TryGetValue("FullPath", out string? fullPath) ? fullPath : identity; + string path = ResolveCapturePath(capturedPath, roots, repositoryRoot); + string fileName = Path.GetFileNameWithoutExtension(path); + if (admittedOwnedAssemblyNames.ContainsKey(fileName)) + continue; + if ( + everyOwnedAssemblyName.Values.Any(name => + string.Equals(name, fileName, StringComparison.OrdinalIgnoreCase) + ) + ) + { + throw new InvalidDataException( + $"Owned binary reference '{capturedPath}' was not matched to an admitted project edge." + ); + } + string assemblyIdentity = + metadata.TryGetValue("FusionName", out string? fusionName) && !string.IsNullOrWhiteSpace(fusionName) + ? fusionName + : metadata.TryGetValue("Name", out string? name) && !string.IsNullOrWhiteSpace(name) ? name + : identity is not null && !Path.IsPathFullyQualified(identity) ? identity + : Path.GetFileNameWithoutExtension(path); + string logical = LogicalPathTokens.FromAbsolute(path, roots); + var aliases = metadata.TryGetValue("Aliases", out string? aliasesText) + ? aliasesText.Split( + new[] { ';', ',' }, + StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries + ) + : Array.Empty(); + bool embedInterop = + metadata.TryGetValue("EmbedInteropTypes", out string? embed) + && bool.TryParse(embed, out bool parsedEmbed) + && parsedEmbed; + result.Add( + new ReferenceHashInput( + assemblyIdentity, + new GraphHashFile( + logical, + ImmutableArray.CreateRange(File.ReadAllBytes(path)), + GraphHashFileKind.Binary + ), + aliases, + embedInterop + ) + ); + } + return result; + } + + private static IEnumerable TransitiveOwnedProjects(RepositoryCompilationGraph graph, string projectId) + { + var outgoing = graph + .ProjectEdges.GroupBy(edge => edge.FromProjectId) + .ToDictionary(group => group.Key, group => group.Select(edge => edge.ToProjectId), StringComparer.Ordinal); + var visited = new HashSet(StringComparer.Ordinal); + var pending = new Stack( + outgoing.TryGetValue(projectId, out IEnumerable? direct) ? direct : Array.Empty() + ); + while (pending.Count != 0) + { + string project = pending.Pop(); + if (!visited.Add(project)) + continue; + yield return project; + if (outgoing.TryGetValue(project, out IEnumerable? dependencies)) + { + foreach (string dependency in dependencies) + pending.Push(dependency); + } + } + } + + private static string ProjectAssemblyName(string projectId, CompilerInputModel input) + { + if (input.Arguments.CompilationName is { Length: > 0 } commandLineName) + return commandLineName; + if (input.Arguments.OutputFileName is { Length: > 0 } outputFile) + return Path.GetFileNameWithoutExtension(outputFile); + return projectId switch + { + "machine" => "SIL.Machine", + "hc" => "SIL.Machine.Morphology.HermitCrab", + "hc-tool" => "SIL.Machine.Morphology.HermitCrab.Tool", + "hc-conformance" => "hc-conformance", + _ => projectId, + }; + } + + private static List BuildProjectReferences( + RepositoryCompilationGraph graph, + RepositoryGraphNode node, + CapturedCompilerInputs capture, + string repositoryRoot + ) + { + var result = new List(); + foreach (CapturedCompilerItem item in capture.Items["ProjectReference"]) + { + string path = item.Metadata.TryGetValue("FullPath", out string? fullPath) ? fullPath : item.Identity; + string? projectId = graph + .Projects.Where(project => + string.Equals( + Path.GetFullPath(path, repositoryRoot), + Path.GetFullPath(project.RelativePath, repositoryRoot), + OperatingSystem.IsWindows() ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal + ) + ) + .Select(project => project.Id) + .SingleOrDefault(); + if (projectId is null) + throw new InvalidDataException($"Project reference '{path}' is outside the fixed project table."); + result.Add(new ProjectReferenceHashInput(projectId, item.Metadata)); + } + if (result.Count == 0) + { + RepositoryProjectDefinition project = graph.Projects.Single(item => item.Id == node.ProjectId); + result.AddRange( + project.DirectOwnedReferences.Select(reference => new ProjectReferenceHashInput(reference)) + ); + } + return result; + } + + private static List BuildAnalyzerInputs( + CompilerInputModel input, + LogicalPathRoots roots, + string repositoryRoot, + string targetFramework + ) + { + var inspections = input.Analyzers.ToList(); + if (inspections.Count == 0 && targetFramework == "net10.0") + { + string? generatorDirectory = FindSdkGeneratorDirectory(roots.SdkRoot); + if (generatorDirectory is not null) + { + foreach (string name in KnownSdkGeneratorNames) + { + string path = Path.Combine(generatorDirectory, name); + if (File.Exists(path)) + inspections.Add(AnalyzerMetadataInspector.Inspect(path, new[] { generatorDirectory })); + } + } + } + var result = new List(); + foreach (AnalyzerMetadataInspection inspection in inspections) + { + string path = ResolveCapturePath(inspection.Path, roots, repositoryRoot); + result.Add( + new AnalyzerHashInput( + inspection.AssemblyIdentity, + new GraphHashFile( + LogicalPathTokens.FromAbsolute(path, roots), + ImmutableArray.CreateRange(File.ReadAllBytes(path)), + GraphHashFileKind.Binary + ) + ) + ); + } + return result; + } + + private static List BuildAuxiliaryFiles( + IReadOnlyList inputs, + IReadOnlyList captured, + LogicalPathRoots roots, + string repositoryRoot, + GraphHashFileKind kind, + bool admitAncestorEditorConfig = false + ) + { + var result = new List(); + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach ( + (string path, ImmutableArray content) in inputs + .Select(item => (item.Path, item.Content)) + .Concat( + captured.Select(item => + { + string path = item.Metadata.TryGetValue("FullPath", out string? fullPath) + ? fullPath + : item.Identity; + path = ResolveCapturePath(path, roots, repositoryRoot); + return (path, ImmutableArray.CreateRange(File.ReadAllBytes(path))); + }) + ) + ) + { + // Only EditorConfigFiles admits an ancestor .editorconfig; every other auxiliary kind still fails closed. + string logical = admitAncestorEditorConfig + ? LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig(path, roots) + : LogicalPathTokens.FromAbsolute(path, roots); + if (seen.Add(logical)) + result.Add(new GraphHashFile(logical, content, kind)); + } + return result; + } + + private static readonly string[] KnownSdkGeneratorNames = + { + "Microsoft.Interop.ComInterfaceGenerator.dll", + "Microsoft.Interop.JavaScript.JSImportGenerator.dll", + "Microsoft.Interop.LibraryImportGenerator.dll", + "System.Text.Json.SourceGeneration.dll", + "System.Text.RegularExpressions.Generator.dll", + }; + + private static ToolchainHashInput BuildToolchainHashInput( + IEnumerable captures, + LogicalPathRoots roots + ) + { + CapturedCompilerInputs first = captures.First(); + string roslynPath = first.Properties["RoslynAssembliesPath"]; + string actualRoslynPath = Path.IsPathFullyQualified(roslynPath) + ? Path.GetFullPath(roslynPath) + : Path.GetDirectoryName(typeof(CSharpCommandLineInputParser).Assembly.Location)! + ?? throw new InvalidDataException("The loaded Roslyn assembly has no directory."); + string roslynLogical = LogicalPathTokens.IsLogicalPath(roslynPath) + ? NormalizeLogicalPath(roslynPath) + : LogicalPathTokens.FromAbsolute(actualRoslynPath, roots); + var files = new List(); + foreach (string name in new[] { "Microsoft.CodeAnalysis.dll", "Microsoft.CodeAnalysis.CSharp.dll" }) + { + string path = Path.Combine(actualRoslynPath, name); + if (!File.Exists(path)) + continue; + files.Add(ReadHashFile(path, roots, GraphHashFileKind.Binary)); + } + if (files.Count == 0) + { + throw new FileNotFoundException( + "The captured Roslyn toolchain contains no compiler assemblies.", + actualRoslynPath + ); + } + + string compilerPath = first.Properties["CscToolPath"]; + string compilerIdentity = string.IsNullOrWhiteSpace(compilerPath) + ? "csc:dotnet" + : "csc:" + NormalizeStableValue("CscToolPath", compilerPath, roots); + string loaderAssembly = typeof(RepositoryCompilationGraphLoader).Assembly.Location; + string loaderIdentity = + typeof(RepositoryCompilationGraphLoader).Assembly.GetName().FullName + ?? typeof(RepositoryCompilationGraphLoader).FullName!; + if (File.Exists(loaderAssembly)) + { + loaderIdentity += "|mvid:" + typeof(RepositoryCompilationGraphLoader).Module.ModuleVersionId.ToString("D"); + files.Add(ReadHashFile(loaderAssembly, roots, GraphHashFileKind.Binary)); + } + return new ToolchainHashInput( + first.Properties["NETCoreSdkVersion"], + first.Properties["MSBuildVersion"], + "roslyn:" + roslynLogical, + compilerIdentity, + loaderIdentity, + files + ); + } + + private static OptionalGraphHashFile ReadLockFile(IReadOnlyList paths, LogicalPathRoots roots) + { + foreach (ProjectPaths project in paths) + { + string lockPath = Path.Combine(project.ObjDirectory, "packages.lock.json"); + if (File.Exists(lockPath)) + return new OptionalGraphHashFile(true, ReadHashFile(lockPath, roots, GraphHashFileKind.Json)); + } + return new OptionalGraphHashFile(false, null); + } + + private static LogicalPathRoots InferLogicalRoots( + string repositoryRoot, + string privateRoot, + IEnumerable captures, + IReadOnlyList projectPaths + ) + { + var sdkCandidates = new List(); + foreach (CapturedCompilerInputs capture in captures) + { + string roslyn = capture.Properties["RoslynAssembliesPath"]; + if (Path.IsPathFullyQualified(roslyn)) + sdkCandidates.Add(roslyn); + foreach (CapturedCompilerItem reference in capture.Items["ReferencePathWithRefAssemblies"]) + { + string path = reference.Metadata.TryGetValue("FullPath", out string? fullPath) + ? fullPath + : reference.Identity; + if (Path.IsPathFullyQualified(path)) + sdkCandidates.Add(path); + } + } + string parserPath = typeof(CSharpCommandLineInputParser).Assembly.Location; + if (Path.IsPathFullyQualified(parserPath)) + sdkCandidates.Add(parserPath); + string? sdkRoot = sdkCandidates.Select(FindDotnetRoot).FirstOrDefault(path => path is not null); + if (sdkRoot is null) + throw new InvalidDataException("Unable to infer a unique SDK root from captured compiler inputs."); + + var nugetRoots = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (ProjectPaths project in projectPaths) + { + using JsonDocument assets = JsonDocument.Parse(File.ReadAllBytes(project.AssetsFile)); + if ( + assets.RootElement.TryGetProperty("packageFolders", out JsonElement folders) + && folders.ValueKind == JsonValueKind.Object + ) + { + foreach (JsonProperty folder in folders.EnumerateObject()) + { + if (Path.IsPathFullyQualified(folder.Name)) + { + string root = Path.TrimEndingDirectorySeparator(Path.GetFullPath(folder.Name)); + ValidateNoReparsePoints(root, root); + nugetRoots.Add(root); + } + } + } + } + foreach (CapturedCompilerInputs capture in captures) + { + foreach (CapturedCompilerItem reference in capture.Items["ReferencePathWithRefAssemblies"]) + { + string path = reference.Metadata.TryGetValue("FullPath", out string? fullPath) + ? fullPath + : reference.Identity; + if (!Path.IsPathFullyQualified(path)) + continue; + string? root = FindPackageRoot(path); + if (root is null) + continue; + ValidateNoReparsePoints(root, Path.GetFullPath(path)); + nugetRoots.Add(root); + } + } + if (nugetRoots.Count == 0) + throw new InvalidDataException("Unable to infer a NuGet package root from restored assets or references."); + string[] distinctNuGetRoots = nugetRoots + .Select(root => LogicalPathTokens.NormalizeAbsolute(Path.GetFullPath(root))) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(root => root, StringComparer.OrdinalIgnoreCase) + .ToArray(); + return new LogicalPathRoots(repositoryRoot, sdkRoot, distinctNuGetRoots, privateRoot); + } + + private static string? FindPackageRoot(string path) + { + string fullPath = Path.GetFullPath(path); + string[] segments = LogicalPathTokens + .NormalizeAbsolute(fullPath) + .Split('/', StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < segments.Length; i++) + { + if ( + !string.Equals(segments[i], "packages", StringComparison.OrdinalIgnoreCase) + && !string.Equals(segments[i], "NuGetFallbackFolder", StringComparison.OrdinalIgnoreCase) + ) + { + continue; + } + string root = fullPath.StartsWith("/", StringComparison.Ordinal) + ? "/" + string.Join('/', segments.Take(i + 1)) + : string.Join('/', segments.Take(i + 1)); + if (root.Length == 2 && root[1] == ':') + root += "/"; + root = LogicalPathTokens.NormalizeAbsolute(root); + string relative = fullPath.Length == root.Length ? string.Empty : fullPath[(root.Length + 1)..]; + string[] package = relative.Replace('\\', '/').Split('/', StringSplitOptions.RemoveEmptyEntries); + if ( + package.Length >= 2 + && IsPackageSegment(package[0]) + && IsPackageSegment(package[1]) + && Directory.Exists(root) + ) + { + return root; + } + } + return null; + } + + private static bool IsPackageSegment(string value) => + !string.IsNullOrWhiteSpace(value) + && value is not "." and not ".." + && value.IndexOfAny(new[] { '/', '\\', ':', '*', '?', '"', '<', '>', '|' }) < 0; + + private static string? FindDotnetRoot(string path) + { + if (string.IsNullOrWhiteSpace(path) || !LogicalPathTokens.IsAbsolute(path)) + return null; + string fullPath; + try + { + fullPath = Path.GetFullPath(path); + } + catch (Exception exception) when (exception is ArgumentException or IOException or NotSupportedException) + { + return null; + } + if (!File.Exists(fullPath) && !Directory.Exists(fullPath)) + return null; + string normalized = LogicalPathTokens.NormalizeAbsolute(fullPath); + string[] segments = normalized.Split('/', StringSplitOptions.RemoveEmptyEntries); + int sdkIndex = Array.FindIndex( + segments, + segment => string.Equals(segment, "sdk", StringComparison.OrdinalIgnoreCase) + ); + if (sdkIndex < 0) + return null; + string root = normalized.StartsWith("/", StringComparison.Ordinal) + ? "/" + string.Join('/', segments.Take(sdkIndex)) + : string.Join('/', segments.Take(sdkIndex)); + if (root.Length == 2 && root[1] == ':') + root += "/"; + string normalizedRoot = LogicalPathTokens.NormalizeAbsolute(root); + try + { + ValidateNoReparsePoints(normalizedRoot, fullPath); + } + catch (Exception exception) + when (exception is IOException or UnauthorizedAccessException or InvalidDataException) + { + return null; + } + return normalizedRoot; + } + + private static string? FindSdkGeneratorDirectory(string sdkRoot) + { + string packs = Path.Combine(sdkRoot, "packs", "Microsoft.NETCore.App.Ref"); + if (!Directory.Exists(packs)) + return null; + return Directory + .EnumerateDirectories(packs) + .OrderByDescending(path => Path.GetFileName(path), StringComparer.Ordinal) + .Select(path => Path.Combine(path, "analyzers", "dotnet", "cs")) + .FirstOrDefault(Directory.Exists); + } + + private static GraphHashFile ReadHashFile(string path, LogicalPathRoots roots, GraphHashFileKind kind) + { + string fullPath = Path.GetFullPath(path); + if (!File.Exists(fullPath)) + throw new FileNotFoundException("Required hash input file is missing.", fullPath); + string admittedRoot = FindAdmittedRoot(fullPath, roots); + ValidateNoReparsePoints(admittedRoot, fullPath); + return new GraphHashFile( + LogicalPathTokens.FromAbsolute(fullPath, roots), + ImmutableArray.CreateRange(File.ReadAllBytes(fullPath)), + kind + ); + } + + private static string FindAdmittedRoot(string fullPath, LogicalPathRoots roots) + { + string normalizedPath = LogicalPathTokens.NormalizeAbsolute(fullPath); + var candidates = new List<(string Root, bool IsNuGet, string? PackageIdentity)>(); + AddCandidate(roots.RepositoryRoot, false); + AddCandidate(roots.SdkRoot, false); + AddCandidate(roots.GeneratedRoot, false); + foreach (string root in roots.NuGetRoots) + AddCandidate(root, true); + if (candidates.Count == 0) + throw new InvalidDataException($"Hash input '{fullPath}' is outside all admitted roots."); + if (candidates.Count == 1) + return candidates[0].Root; + if ( + !candidates.All(candidate => candidate.IsNuGet) + || candidates + .Select(candidate => candidate.PackageIdentity) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Count() != 1 + ) + { + throw new InvalidDataException($"Hash input '{fullPath}' has ambiguous admitted roots."); + } + return candidates.OrderBy(candidate => candidate.Root, StringComparer.OrdinalIgnoreCase).First().Root; + + void AddCandidate(string root, bool isNuGet) + { + if (!LogicalPathTokens.IsUnder(normalizedPath, root)) + return; + string? identity = null; + if (isNuGet) + { + string relative = + normalizedPath.Length == root.Length ? string.Empty : normalizedPath[(root.Length + 1)..]; + string[] segments = relative.Split('/', StringSplitOptions.RemoveEmptyEntries); + if (segments.Length < 2) + { + throw new InvalidDataException( + $"NuGet hash input '{fullPath}' is not decomposable into package ID and version." + ); + } + identity = segments[0] + "/" + segments[1]; + } + candidates.Add((root, isNuGet, identity)); + } + } + + private static string ResolveCapturePath(string path, LogicalPathRoots roots, string baseDirectory) + { + if (path.StartsWith("tmp:/", StringComparison.Ordinal)) + return Path.Combine(roots.GeneratedRoot, path[5..].Replace('/', Path.DirectorySeparatorChar)); + if (LogicalPathTokens.IsLogicalPath(path)) + { + string[] prefix = { "repo:/", "sdk:/", "nuget:/", "generated:/" }; + string token = prefix.Single(path.StartsWith); + string root = token switch + { + "repo:/" => roots.RepositoryRoot, + "sdk:/" => roots.SdkRoot, + "nuget:/" => ResolveNuGetLogicalRoot(path[token.Length..], roots), + _ => roots.GeneratedRoot, + }; + return Path.Combine(root, path[token.Length..].Replace('/', Path.DirectorySeparatorChar)); + } + if (Path.IsPathFullyQualified(path)) + return Path.GetFullPath(path); + return Path.GetFullPath(path, baseDirectory); + } + + private static string ResolveNuGetLogicalRoot(string relative, LogicalPathRoots roots) + { + string[] segments = relative.Split('/', StringSplitOptions.RemoveEmptyEntries); + if (segments.Length < 2) + { + throw new InvalidDataException( + $"NuGet logical path '{relative}' is not decomposable into package ID and version." + ); + } + foreach (string root in roots.NuGetRoots) + { + string candidate = Path.Combine(root, segments[0], segments[1]); + if (Directory.Exists(candidate)) + return root; + } + return roots.NuGetRoot; + } + + private static string NormalizeStableValue(string name, string value, LogicalPathRoots roots) + { + if (string.IsNullOrEmpty(value)) + return value; + if (name == "MSBuildAllProjects") + return string.Join(";", SplitMsBuildPaths(value).Select(path => NormalizeStablePath(path, roots))); + return NormalizeStablePath(value, roots); + } + + private static string NormalizeArgument(string value, LogicalPathRoots roots) + { + // On Unix every csc switch is syntactically an absolute path, so switch shape has to be + // decided before any path handling: /noconfig carries no value, /doc:/tmp/x.xml carries one. + if (IsCompilerSwitchPrefix(value)) + { + int switchSeparator = value.IndexOf(':'); + return switchSeparator > 0 + ? value[..(switchSeparator + 1)] + NormalizeSwitchValue(value[(switchSeparator + 1)..], roots) + : value; + } + + if (Path.IsPathFullyQualified(value)) + { + return LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig(Path.GetFullPath(value), roots); + } + + int separator = value.IndexOf(':'); + return separator > 0 ? value[..(separator + 1)] + NormalizeSwitchValue(value[(separator + 1)..], roots) : value; + } + + /// Normalises the value half of a token, which may be a path or an opaque setting. + /// Everything after the first colon, possibly an =-joined pair. + private static string NormalizeSwitchValue(string tail, LogicalPathRoots roots) + { + string[] parts = tail.Split('=', 2); + if (!Path.IsPathFullyQualified(parts[^1])) + { + return tail; + } + + parts[^1] = LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig(Path.GetFullPath(parts[^1]), roots); + return string.Join('=', parts); + } + + /// Whether a token is a compiler switch rather than a path. + /// A single token from CscCommandLineArgs. + /// A leading slash is ambiguous on Unix, where it also begins an absolute path. What + /// separates them is what follows the switch name: nothing for a bare switch, a colon for one + /// carrying a value, and a further separator for a real path. + private static bool IsCompilerSwitchPrefix(string value) + { + if (value.Length < 2 || (value[0] != '/' && value[0] != '-')) + { + return false; + } + + int special = value.IndexOfAny(new[] { '/', '\\', ':' }, 1); + return special < 0 || value[special] == ':'; + } + + private static string NormalizeStablePath(string value, LogicalPathRoots roots) + { + if (value.StartsWith("tmp:/", StringComparison.Ordinal)) + return "generated:/" + value[5..]; + if (LogicalPathTokens.IsLogicalPath(value)) + return NormalizeLogicalPath(value); + if (Path.IsPathFullyQualified(value)) + return LogicalPathTokens.FromAbsolute(Path.GetFullPath(value), roots); + return value; + } + + private static string NormalizeLogicalPath(string value) => value.Replace('\\', '/'); + + private static IEnumerable SplitMsBuildPaths(string value) => + value.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + private static ProjectPaths ValidateProjectInputs(string repositoryRoot, RepositoryProjectDefinition project) + { + string projectFile = ResolveRepositoryFile(repositoryRoot, project.RelativePath); + string projectDirectory = + Path.GetDirectoryName(projectFile) ?? throw new InvalidDataException("Project path has no directory."); + string objDirectory = ResolveRepositoryDirectory( + repositoryRoot, + Path.Combine(Path.GetRelativePath(repositoryRoot, projectDirectory), "obj") + ); + string assetsFile = ResolveRepositoryFile( + repositoryRoot, + Path.Combine(Path.GetRelativePath(repositoryRoot, objDirectory), "project.assets.json") + ); + string projectName = Path.GetFileNameWithoutExtension(projectFile); + ResolveRepositoryFile( + repositoryRoot, + Path.Combine(Path.GetRelativePath(repositoryRoot, objDirectory), $"{projectName}.csproj.nuget.g.props") + ); + ResolveRepositoryFile( + repositoryRoot, + Path.Combine(Path.GetRelativePath(repositoryRoot, objDirectory), $"{projectName}.csproj.nuget.g.targets") + ); + ValidateAssetsTarget(assetsFile, project.TargetFramework); + return new ProjectPaths(projectFile, objDirectory, assetsFile); + } + + private static void ValidateAssetsTarget(string assetsFile, string targetFramework) + { + try + { + using JsonDocument document = JsonDocument.Parse(File.ReadAllBytes(assetsFile)); + JsonElement frameworks = document.RootElement.GetProperty("project").GetProperty("frameworks"); + if (!frameworks.TryGetProperty(targetFramework, out _)) + throw new InvalidDataException($"Assets file does not contain target framework '{targetFramework}'."); + } + catch (JsonException exception) + { + throw new InvalidDataException($"Assets file '{assetsFile}' is invalid JSON.", exception); + } + } + + private static string ResolveRepositoryFile(string repositoryRoot, string relativePath) + { + string path = ResolveContainedPath(repositoryRoot, relativePath); + if (!File.Exists(path)) + throw new FileNotFoundException("Required repository file is missing.", path); + ValidateNoReparsePoints(repositoryRoot, path); + return path; + } + + private static string ResolveRepositoryDirectory(string repositoryRoot, string relativePath) + { + string path = ResolveContainedPath(repositoryRoot, relativePath); + if (!Directory.Exists(path)) + throw new DirectoryNotFoundException($"Required repository directory '{path}' is missing."); + ValidateNoReparsePoints(repositoryRoot, path); + return path; + } + + private static string ResolveContainedPath(string repositoryRoot, string relativePath) + { + if (Path.IsPathFullyQualified(relativePath)) + throw new InvalidDataException("Repository paths must be relative."); + string fullPath = Path.GetFullPath(relativePath, repositoryRoot); + string prefix = Path.TrimEndingDirectorySeparator(repositoryRoot) + Path.DirectorySeparatorChar; + StringComparison comparison = OperatingSystem.IsWindows() + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + if (!fullPath.StartsWith(prefix, comparison)) + throw new InvalidDataException($"Repository path '{relativePath}' escapes the root."); + return fullPath; + } + + private static void ValidateRepositoryRoot(string repositoryRoot) + { + if (!Directory.Exists(repositoryRoot)) + throw new DirectoryNotFoundException($"Repository root '{repositoryRoot}' is missing."); + FileAttributes attributes = File.GetAttributes(repositoryRoot); + if ((attributes & FileAttributes.ReparsePoint) != 0) + throw new InvalidDataException("Repository root cannot be a reparse point."); + } + + private static void ValidateNoReparsePoints(string root, string path) + { + string relative = Path.GetRelativePath(root, path); + if (relative.StartsWith("..", StringComparison.Ordinal) || Path.IsPathFullyQualified(relative)) + throw new InvalidDataException("Path escapes its validated root."); + string current = root; + foreach ( + string segment in relative.Split( + new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, + StringSplitOptions.RemoveEmptyEntries + ) + ) + { + current = Path.Combine(current, segment); + if ((File.GetAttributes(current) & FileAttributes.ReparsePoint) != 0) + throw new InvalidDataException($"Reparse point '{current}' is not admitted."); + } + } + + internal static void ValidatePrivateGeneratedFile(string privateRoot, string intermediateDirectory, string path) + { + string fullPath = Path.GetFullPath(path); + string relative = Path.GetRelativePath(intermediateDirectory, fullPath); + if (relative.StartsWith("..", StringComparison.Ordinal) || Path.IsPathFullyQualified(relative)) + throw new InvalidDataException("Generated compiler source escapes its private intermediate directory."); + if (!File.Exists(fullPath)) + throw new FileNotFoundException("Generated compiler source is missing.", fullPath); + ValidateNoReparsePoints(privateRoot, fullPath); + } + + private static string SafeSegment(string value) + { + if (value.Length == 0 || value.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) + throw new InvalidDataException($"Invalid graph path segment '{value}'."); + return value; + } + + private static void DeletePrivateDirectory(string privateRoot) + { + if (!Directory.Exists(privateRoot)) + return; + string leaf = Path.GetFileName(Path.TrimEndingDirectorySeparator(privateRoot)); + if (leaf.Length != 32 || !Guid.TryParseExact(leaf, "N", out _)) + throw new InvalidDataException("Refusing to delete an unverified MSBuild query directory."); + ValidateNoReparsePoints(Path.GetDirectoryName(privateRoot)!, privateRoot); + Directory.Delete(privateRoot, recursive: true); + } + + private sealed record ProjectPaths(string ProjectFile, string ObjDirectory, string AssetsFile); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RoslynCompilationGraph.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RoslynCompilationGraph.cs new file mode 100644 index 000000000..dbb8b19c9 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RoslynCompilationGraph.cs @@ -0,0 +1,428 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal sealed record RoslynCompilationNode( + RepositoryGraphNodeKey Key, + CSharpCompilation Compilation, + CompilationDiagnostics Diagnostics, + int ProbedSdkGeneratorCount +); + +internal sealed class RoslynCompilationGraph +{ + private static readonly IReadOnlyDictionary OwnedAssemblyNames = new Dictionary( + StringComparer.OrdinalIgnoreCase + ) + { + ["machine"] = "SIL.Machine", + ["hc"] = "SIL.Machine.Morphology.HermitCrab", + ["hc-tool"] = "SIL.Machine.Morphology.HermitCrab.Tool", + ["hc-conformance"] = "hc-conformance", + }; + + private RoslynCompilationGraph(IReadOnlyDictionary nodes) + { + Nodes = nodes; + } + + internal IReadOnlyDictionary Nodes { get; } + + internal RoslynCompilationNode this[RepositoryGraphNodeKey key] => Nodes[key]; + + internal static RoslynCompilationGraph Build(RepositoryCompilationGraph graph) + { + ArgumentNullException.ThrowIfNull(graph); + if (graph.CompilerInputs.Count != graph.Nodes.Count) + throw new InvalidDataException("Compiler inputs must cover every compilation graph node."); + + var built = new Dictionary(); + var externalReferences = new Dictionary(StringComparer.Ordinal); + foreach (RepositoryProjectDefinition project in graph.Projects) + { + foreach (RepositoryGraphNode node in graph.Nodes.Where(item => item.ProjectId == project.Id)) + { + CompilerInputModel input = graph.CompilerInputs[node.Key]; + var trees = input + .Sources.Select(source => + { + using var stream = new MemoryStream(source.Content.ToArray(), writable: false); + SourceText text = SourceText.From(stream, encoding: null); + return CSharpSyntaxTree.ParseText( + text, + input.Arguments.ParseOptions as CSharpParseOptions, + source.Path + ); + }) + .ToImmutableArray(); + var diagnostics = CompilationDiagnostics.From( + node.Key.ToString(), + trees.SelectMany(tree => tree.GetDiagnostics()) + ); + diagnostics.ThrowIfFatal(); + + IEnumerable references = CreateReferences( + graph, + node, + input, + built, + externalReferences + ); + CSharpCompilation compilation = CSharpCompilation.Create( + ProjectAssemblyName(project.Id, input), + trees, + references, + input.Arguments.CompilationOptions as CSharpCompilationOptions + ?? new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + CompilationDiagnostics compilerDiagnostics = CompilationDiagnostics.From( + node.Key.ToString(), + compilation.GetDiagnostics() + ); + compilerDiagnostics.ThrowIfFatal(); + int probedSdkGeneratorCount = RunPendingGeneratorProbe(input, compilation); + built.Add( + node.Key, + new RoslynCompilationNode(node.Key, compilation, compilerDiagnostics, probedSdkGeneratorCount) + ); + } + } + + return new RoslynCompilationGraph(built); + } + + private static IEnumerable CreateReferences( + RepositoryCompilationGraph graph, + RepositoryGraphNode node, + CompilerInputModel input, + IReadOnlyDictionary built, + IDictionary externalReferences + ) + { + var directOwned = graph + .ProjectEdges.Where(edge => edge.FromProjectId == node.ProjectId) + .Select(edge => edge.ToProjectId) + .ToHashSet(StringComparer.Ordinal); + var owned = TransitiveOwnedProjects(graph, node.ProjectId); + var ownedAssemblyNames = owned.ToDictionary( + project => project, + project => + ProjectAssemblyName( + project, + graph.CompilerInputs[ + graph.Nodes.First(item => item.ProjectId == project && item.Profile.Id == node.Profile.Id).Key + ] + ), + StringComparer.Ordinal + ); + var everyOwnedAssemblyName = graph.Projects.ToDictionary( + project => project.Id, + project => + ProjectAssemblyName( + project.Id, + graph.CompilerInputs[ + graph + .Nodes.First(item => item.ProjectId == project.Id && item.Profile.Id == node.Profile.Id) + .Key + ] + ), + StringComparer.Ordinal + ); + var consumed = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (CommandLineReference reference in input.Arguments.MetadataReferences) + { + string? path = reference.Reference; + string fileName = path is null ? string.Empty : Path.GetFileNameWithoutExtension(path); + string? ownedProject = owned.FirstOrDefault(project => + ownedAssemblyNames.TryGetValue(project, out string? name) + && string.Equals(name, fileName, StringComparison.OrdinalIgnoreCase) + ); + if (ownedProject is not null) + { + RepositoryGraphNodeKey upstreamKey = new( + ownedProject, + graph.Nodes.First(item => item.ProjectId == ownedProject).TargetFramework, + node.Profile.Id + ); + if (!built.TryGetValue(upstreamKey, out RoslynCompilationNode? upstream)) + { + throw new InvalidDataException( + $"Owned project '{ownedProject}' has not been compiled before '{node.ProjectId}'." + ); + } + consumed.Add(ownedProject); + yield return upstream.Compilation.ToMetadataReference( + reference.Properties.Aliases, + reference.Properties.EmbedInteropTypes + ); + continue; + } + + if ( + everyOwnedAssemblyName.Values.Any(name => + string.Equals(name, fileName, StringComparison.OrdinalIgnoreCase) + ) + ) + { + throw new CompilerInputException( + "owned-binary-reference", + $"Owned reference '{path}' was not matched to an admitted direct project edge." + ); + } + + if (path is null || string.IsNullOrWhiteSpace(path)) + throw new CompilerInputException("reference-parser-diagnostic", "A metadata reference has no path."); + if (!File.Exists(path)) + { + throw new CompilerInputException( + "reference-parser-diagnostic", + $"Metadata reference '{path}' does not exist." + ); + } + string externalKey = + $"{Path.GetFullPath(path)}\0{reference.Properties.Kind}\0{reference.Properties.EmbedInteropTypes}\0{string.Join("\0", reference.Properties.Aliases)}"; + if (!externalReferences.TryGetValue(externalKey, out PortableExecutableReference? externalReference)) + { + externalReference = LoadExternalReference(path, reference.Properties); + externalReferences.Add(externalKey, externalReference); + } + yield return externalReference; + } + + foreach (string project in directOwned.Where(project => !consumed.Contains(project))) + { + throw new CompilerInputException( + "missing-owned-project-reference", + $"Compiler inputs for '{node.ProjectId}' omit direct owned reference '{project}'." + ); + } + } + + internal static PortableExecutableReference LoadExternalReference( + string path, + MetadataReferenceProperties properties + ) + { + try + { + using (FileStream stream = File.OpenRead(path)) + using (var peReader = new PEReader(stream)) + { + if (!peReader.HasMetadata) + throw new BadImageFormatException("The reference has no CLI metadata."); + _ = peReader.GetMetadataReader(); + } + PortableExecutableReference reference = MetadataReference.CreateFromFile(path, properties); + return reference; + } + catch (Exception exception) + when (exception + is IOException + or UnauthorizedAccessException + or BadImageFormatException + or ArgumentException + ) + { + throw new CompilerInputException( + "reference-parser-diagnostic", + $"Metadata reference '{path}' could not be loaded.", + exception + ); + } + } + + private static HashSet TransitiveOwnedProjects(RepositoryCompilationGraph graph, string projectId) + { + var result = new HashSet(StringComparer.Ordinal); + var pending = new Stack(); + pending.Push(projectId); + while (pending.Count != 0) + { + string current = pending.Pop(); + foreach ( + string dependency in graph + .ProjectEdges.Where(edge => edge.FromProjectId == current) + .Select(edge => edge.ToProjectId) + ) + { + if (result.Add(dependency)) + pending.Push(dependency); + } + } + return result; + } + + private static int RunPendingGeneratorProbe(CompilerInputModel input, CSharpCompilation compilation) + { + AnalyzerMetadataInspection[] pending = input + .Analyzers.Where(analyzer => + analyzer.Disposition == AnalyzerDisposition.SdkOwnedSourceGeneratorPendingProbe + ) + .ToArray(); + if (pending.Length == 0) + return 0; + + try + { + var generators = ImmutableArray.CreateBuilder(); + foreach (AnalyzerMetadataInspection analyzer in pending) + { + var reference = new AnalyzerFileReference(analyzer.Path, new GraphAnalyzerAssemblyLoader()); + ImmutableArray loaded = reference.GetGenerators(LanguageNames.CSharp); + if (loaded.Length == 0) + { + throw new CompilerInputException( + "source-generator-probe", + $"Admitted SDK generator assembly '{analyzer.Path}' exposed no C# generators." + ); + } + generators.AddRange(loaded); + } + GeneratorDriver driver = CSharpGeneratorDriver.Create( + generators.ToImmutable(), + additionalTexts: input + .AdditionalFiles.Select(file => (AdditionalText)new CapturedAdditionalText(file)) + .ToImmutableArray(), + parseOptions: input.Arguments.ParseOptions as CSharpParseOptions, + optionsProvider: new CapturedAnalyzerConfigOptionsProvider(input.AnalyzerConfigs) + ); + driver = driver.RunGeneratorsAndUpdateCompilation( + compilation, + out Compilation updatedCompilation, + out ImmutableArray diagnostics + ); + if (updatedCompilation is not CSharpCompilation updated) + { + throw new CompilerInputException( + "source-generator-probe", + "The source-generator probe returned a non-C# compilation." + ); + } + GeneratorDriverRunResult runResult = driver.GetRunResult(); + bool generatorFailure = + runResult.Diagnostics.Length != 0 + || runResult.Results.Any(result => + result.Exception is not null + || result.Diagnostics.Length != 0 + || result.GeneratedSources.Length != 0 + ); + if ( + updated.SyntaxTrees.Length != compilation.SyntaxTrees.Length + || diagnostics.Length != 0 + || generatorFailure + ) + { + throw new CompilerInputException( + "source-generator-probe", + "An admitted SDK source generator produced output or diagnostics." + ); + } + return generators.Count; + } + catch (CompilerInputException) + { + throw; + } + catch (Exception exception) + { + throw new CompilerInputException( + "source-generator-probe", + "An admitted SDK source generator failed during the zero-output probe.", + exception + ); + } + } + + private static string ProjectAssemblyName(string projectId, CompilerInputModel input) + { + if (input.Arguments.CompilationName is { Length: > 0 } commandLineName) + return commandLineName; + return input.Arguments.OutputFileName is { Length: > 0 } outputFile + ? Path.GetFileNameWithoutExtension(outputFile) + : OwnedAssemblyNames.TryGetValue(projectId, out string? name) ? name + : projectId; + } + + private sealed class GraphAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader + { + public void AddDependencyLocation(string fullPath) { } + + public Assembly LoadFromPath(string fullPath) => Assembly.LoadFrom(fullPath); + } + + private sealed class CapturedAdditionalText(CompilerAuxiliaryInput input) : AdditionalText + { + public override string Path { get; } = input.Path; + + public override SourceText? GetText(System.Threading.CancellationToken cancellationToken = default) + { + using var stream = new MemoryStream(input.Content.ToArray(), writable: false); + return SourceText.From(stream, encoding: null); + } + } + + private sealed class CapturedAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider + { + private readonly AnalyzerConfigSet _configs; + private readonly AnalyzerConfigOptions _global; + + internal CapturedAnalyzerConfigOptionsProvider(IReadOnlyList inputs) + { + AnalyzerConfig[] configs = inputs.Select(Parse).ToArray(); + _configs = AnalyzerConfigSet.Create(configs, out ImmutableArray diagnostics); + ThrowIfConfigDiagnostics(diagnostics); + AnalyzerConfigOptionsResult global = _configs.GlobalConfigOptions; + ThrowIfConfigDiagnostics(global.Diagnostics); + _global = new CapturedAnalyzerConfigOptions(global.AnalyzerOptions); + } + + public override AnalyzerConfigOptions GlobalOptions => _global; + + public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) => GetOptions(tree.FilePath); + + public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) => GetOptions(textFile.Path); + + private AnalyzerConfigOptions GetOptions(string path) + { + AnalyzerConfigOptionsResult result = _configs.GetOptionsForSourcePath(path); + ThrowIfConfigDiagnostics(result.Diagnostics); + return new CapturedAnalyzerConfigOptions(result.AnalyzerOptions); + } + + private static AnalyzerConfig Parse(CompilerAuxiliaryInput input) + { + using var stream = new MemoryStream(input.Content.ToArray(), writable: false); + return AnalyzerConfig.Parse(SourceText.From(stream, encoding: null), input.Path); + } + + private static void ThrowIfConfigDiagnostics(ImmutableArray diagnostics) + { + if (diagnostics.Length == 0) + return; + throw new CompilerInputException( + "analyzer-config-diagnostic", + string.Join("; ", diagnostics.Select(diagnostic => diagnostic.ToString())) + ); + } + } + + private sealed class CapturedAnalyzerConfigOptions(IReadOnlyDictionary values) + : AnalyzerConfigOptions + { + public override IEnumerable Keys => values.Keys; + + public override bool TryGetValue(string key, out string value) => values.TryGetValue(key, out value!); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RuleInteractionLedger.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RuleInteractionLedger.cs new file mode 100644 index 000000000..384db94e8 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/RuleInteractionLedger.cs @@ -0,0 +1,167 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// The checked-in denominator for rule-interaction coverage: one row per +/// across every fixture, with the +/// resolved for +/// it. Unlike or , this ledger is not evidence +/// of anything having been exercised -- it is purely the enumerated denominator, checked in so a change to +/// the enumeration or to a fixture's grammar is visible as a diff rather than only as a recomputed number. +/// +public static class RuleInteractionLedger +{ + public const string RelativePath = "conformance/rule-interaction-pairs.tsv"; + + private const int ColumnCount = 9; + + public sealed record Row( + string Fixture, + string StratumA, + string StratumB, + StratumPairKind PairKind, + StratumUnitKind UnitAKind, + string UnitA, + StratumUnitKind UnitBKind, + string UnitB, + DomainRelation Relation + ); + + /// Runs and classifies every pair + /// for one fixture's grammar. + public static IReadOnlyList Compute(XDocument grammar, string fixtureId) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + + return OrderingGenerator + .EnumerateStratumPairs(grammar, fixtureId) + .Select(pair => new Row( + pair.FixtureId, + pair.StratumALabel, + pair.StratumBLabel, + pair.Kind, + pair.UnitA.Kind, + pair.UnitA.Label, + pair.UnitB.Kind, + pair.UnitB.Label, + OrderingGenerator.CheckStratumPairDisjointDomains(grammar, pair).Relation + )) + .ToArray(); + } + + public static void Write(string repositoryRoot, IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + ArgumentNullException.ThrowIfNull(rows); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + File.WriteAllText(path, ToText(rows)); + } + + /// + /// Renders the ledger deterministically (fixture, then Stratum ordinals, then unit labels) so two runs + /// over an unchanged corpus byte-for-byte agree -- RuleInteractionPairsCheckedInLedgerIsUpToDate + /// depends on this for its drift check. + /// + public static string ToText(IReadOnlyList rows) + { + ArgumentNullException.ThrowIfNull(rows); + var writer = new StringWriter(); + writer.WriteLine( + "# GENERATED by hc-conformance --write-rule-interaction-pairs. One line per pipeline-permitted" + ); + writer.WriteLine("# ordered pair of rule-bearing units within a Stratum (or between two adjacent Strata) --"); + writer.WriteLine( + "# OrderingGenerator.EnumerateStratumPairs's denominator for rule-interaction coverage, classified" + ); + writer.WriteLine( + "# by CheckStratumPairDisjointDomains. Self-pairs are included (see the method doc for why); an" + ); + writer.WriteLine( + "# AffixTemplate is one unit, never exploded into its Slot rules -- those are already pinned by" + ); + writer.WriteLine( + "# OrderingGenerator's adjacent-pair AffixTemplateSlots list. pair_kind is same-stage, cross-stage," + ); + writer.WriteLine( + "# or cross-stratum. domain_relation is only ever Disjoint/Overlaps for a PhonologicalRule pair;" + ); + writer.WriteLine("# every other unit-kind combination is Undetermined by construction."); + writer.WriteLine( + "fixture\tstratum_a\tstratum_b\tpair_kind\tunit_a_kind\tunit_a\tunit_b_kind\tunit_b\tdomain_relation" + ); + foreach ( + Row row in rows.OrderBy(r => r.Fixture, StringComparer.Ordinal) + .ThenBy(r => r.StratumA, StringComparer.Ordinal) + .ThenBy(r => r.PairKind) + .ThenBy(r => r.UnitAKind) + .ThenBy(r => r.UnitA, StringComparer.Ordinal) + .ThenBy(r => r.UnitBKind) + .ThenBy(r => r.UnitB, StringComparer.Ordinal) + ) + { + writer.WriteLine( + string.Join( + '\t', + row.Fixture, + row.StratumA, + row.StratumB, + row.PairKind, + row.UnitAKind, + row.UnitA, + row.UnitBKind, + row.UnitB, + row.Relation + ) + ); + } + return writer.ToString(); + } + + /// Reads the checked-in ledger, or an empty list if it has never been written. + public static IReadOnlyList Read(string repositoryRoot) + { + ArgumentNullException.ThrowIfNull(repositoryRoot); + string path = Path.Combine(repositoryRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + if (!File.Exists(path)) + return Array.Empty(); + + var rows = new List(); + foreach (string raw in File.ReadAllLines(path)) + { + string line = raw.Trim(); + if ( + line.Length == 0 + || line.StartsWith("#", StringComparison.Ordinal) + || line.StartsWith("fixture\t", StringComparison.Ordinal) + ) + { + continue; + } + + string[] fields = line.Split('\t'); + if (fields.Length != ColumnCount) + throw new FormatException($"{RelativePath}: '{line}' must be {ColumnCount} tab-separated fields"); + if (!Enum.TryParse(fields[3], out StratumPairKind pairKind)) + throw new FormatException($"{RelativePath}: unknown pair kind '{fields[3]}'"); + if (!Enum.TryParse(fields[4], out StratumUnitKind unitAKind)) + throw new FormatException($"{RelativePath}: unknown unit kind '{fields[4]}'"); + if (!Enum.TryParse(fields[6], out StratumUnitKind unitBKind)) + throw new FormatException($"{RelativePath}: unknown unit kind '{fields[6]}'"); + if (!Enum.TryParse(fields[8], out DomainRelation relation)) + throw new FormatException($"{RelativePath}: unknown domain relation '{fields[8]}'"); + + rows.Add( + new Row(fields[0], fields[1], fields[2], pairKind, unitAKind, fields[5], unitBKind, fields[7], relation) + ); + } + + return rows; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ScopeValidation.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ScopeValidation.cs new file mode 100644 index 000000000..ddf00dd30 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/ScopeValidation.cs @@ -0,0 +1,34 @@ +#nullable enable +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +internal static class ScopeValidation +{ + public static bool HasPattern(string scope) + { + if (scope.Contains('*') || scope.Contains('?')) + return true; + + bool inArrayRank = false; + foreach (char character in scope) + { + if (character == '[') + { + if (inArrayRank) + return true; + inArrayRank = true; + } + else if (character == ']') + { + if (!inArrayRank) + return true; + inArrayRank = false; + } + else if (inArrayRank && character != ',') + { + return true; + } + } + + return inArrayRank; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCatalog.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCatalog.cs new file mode 100644 index 000000000..341d530a4 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCatalog.cs @@ -0,0 +1,239 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using YamlDotNet.Core; +using YamlDotNet.RepresentationModel; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// How a catalog feature participates in semantic coverage. Only features +/// require fixture evidence; every other disposition must carry a reason and a citation. +/// +public enum FeatureDisposition +{ + /// Observable parsing semantics; requires phase effects and fixture evidence. + Semantic, + + /// Load-time structure with no effect on a parse result. + Loader, + + /// Schema bookkeeping such as an attribute's declared type or default. + Metadata, + + /// Deliberately out of scope. + Ignored, + + /// Declared by the schema but rejected or unreachable in practice. + Invalid, + + /// Blocked by a known C# defect; cannot be covered until that is fixed. + BlockedCSharpDefect, + + /// + /// Mapped by the bootstrap generator and not yet classified by a human. Keeps the exact-once + /// mapping total while stating plainly that the semantic judgement has not been made, instead of + /// fabricating phase effects to satisfy the audit. + /// + Unclassified, +} + +public sealed record PhaseEffect(string Behavior, IReadOnlyList Reads, IReadOnlyList Writes); + +public sealed record SemanticFeature( + string Id, + FeatureDisposition Disposition, + PhaseEffect? AnalysisCandidateEffect, + PhaseEffect? SynthesisConfirmationEffect, + PhaseEffect? FinalParseEffect, + IReadOnlyList Carriers, + string? Reason, + IReadOnlyList Citations +); + +public sealed record SurfaceMapping(string SurfaceId, string FeatureId); + +public sealed record SemanticCatalog( + string Profile, + IReadOnlyList AuditedSourceScopes, + IReadOnlyList Features, + IReadOnlyList SurfaceMappings +); + +public sealed class SemanticCatalogException(string path, string detail) : FormatException($"{path}: {detail}"); + +public static class SemanticCatalogLoader +{ + public const string ExpectedProfile = "sil.machine.hc-semantic-catalog/v1"; + + private static readonly HashSet RootKeys = new(StringComparer.Ordinal) + { + "profile", + "auditedSourceScopes", + "features", + "surfaceMappings", + }; + private static readonly HashSet FeatureKeys = new(StringComparer.Ordinal) + { + "id", + "disposition", + "analysisCandidateEffect", + "synthesisConfirmationEffect", + "finalParseEffect", + "carriers", + "reason", + "citations", + }; + private static readonly HashSet EffectKeys = new(StringComparer.Ordinal) { "behavior", "reads", "writes" }; + private static readonly HashSet MappingKeys = new(StringComparer.Ordinal) { "surface", "feature" }; + + private static readonly Dictionary Dispositions = new(StringComparer.Ordinal) + { + ["semantic"] = FeatureDisposition.Semantic, + ["loader"] = FeatureDisposition.Loader, + ["metadata"] = FeatureDisposition.Metadata, + ["ignored"] = FeatureDisposition.Ignored, + ["invalid"] = FeatureDisposition.Invalid, + ["blocked-csharp-defect"] = FeatureDisposition.BlockedCSharpDefect, + ["unclassified"] = FeatureDisposition.Unclassified, + }; + + public static SemanticCatalog Load(string path) => Parse(File.ReadAllText(path), path); + + public static SemanticCatalog Parse(string text, string path) + { + ArgumentNullException.ThrowIfNull(text); + YamlMappingNode root; + try + { + var stream = new YamlStream(); + using var reader = new StringReader(text); + stream.Load(reader); + if (stream.Documents.Count != 1) + throw new SemanticCatalogException(path, "expected exactly one YAML document"); + root = + stream.Documents[0].RootNode as YamlMappingNode + ?? throw new SemanticCatalogException(path, "top-level YAML node must be a mapping"); + } + catch (YamlException ex) + { + throw new SemanticCatalogException(path, $"YAML syntax error at {ex.Start}: {ex.Message}"); + } + + RejectUnknownKeys(root, RootKeys, path, "catalog"); + string profile = RequireScalar(root, "profile", path); + if (profile != ExpectedProfile) + { + throw new SemanticCatalogException( + path, + $"unsupported catalog profile '{profile}'; expected '{ExpectedProfile}'" + ); + } + + var features = new List(); + var featureIds = new HashSet(StringComparer.Ordinal); + foreach (YamlMappingNode node in Sequence(root, "features", path)) + { + SemanticFeature feature = ParseFeature(node, path); + if (!featureIds.Add(feature.Id)) + throw new SemanticCatalogException(path, $"duplicate feature id '{feature.Id}'"); + features.Add(feature); + } + + var mappings = new List(); + foreach (YamlMappingNode node in Sequence(root, "surfaceMappings", path)) + { + RejectUnknownKeys(node, MappingKeys, path, "surfaceMappings entry"); + mappings.Add( + new SurfaceMapping(RequireScalar(node, "surface", path), RequireScalar(node, "feature", path)) + ); + } + + return new SemanticCatalog( + profile, + Strings(root, "auditedSourceScopes", path), + new ReadOnlyCollection(features.OrderBy(item => item.Id, StringComparer.Ordinal).ToList()), + new ReadOnlyCollection( + mappings.OrderBy(item => item.SurfaceId, StringComparer.Ordinal).ToList() + ) + ); + } + + private static SemanticFeature ParseFeature(YamlMappingNode node, string path) + { + RejectUnknownKeys(node, FeatureKeys, path, "features entry"); + string id = RequireScalar(node, "id", path); + string disposition = RequireScalar(node, "disposition", path); + if (!Dispositions.TryGetValue(disposition, out FeatureDisposition parsed)) + throw new SemanticCatalogException(path, $"feature '{id}' has unknown disposition '{disposition}'"); + + return new SemanticFeature( + id, + parsed, + ParseEffect(node, "analysisCandidateEffect", path, id), + ParseEffect(node, "synthesisConfirmationEffect", path, id), + ParseEffect(node, "finalParseEffect", path, id), + Strings(node, "carriers", path), + node.Children.TryGetValue(new YamlScalarNode("reason"), out YamlNode? reason) ? Scalar(reason, path) : null, + Strings(node, "citations", path) + ); + } + + private static PhaseEffect? ParseEffect(YamlMappingNode node, string key, string path, string featureId) + { + if (!node.Children.TryGetValue(new YamlScalarNode(key), out YamlNode? value)) + return null; + if (value is not YamlMappingNode mapping) + throw new SemanticCatalogException(path, $"feature '{featureId}' key '{key}' must be a mapping"); + RejectUnknownKeys(mapping, EffectKeys, path, $"{key} of feature '{featureId}'"); + return new PhaseEffect( + RequireScalar(mapping, "behavior", path), + Strings(mapping, "reads", path), + Strings(mapping, "writes", path) + ); + } + + private static IEnumerable Sequence(YamlMappingNode root, string key, string path) + { + if (!root.Children.TryGetValue(new YamlScalarNode(key), out YamlNode? value)) + return Array.Empty(); + if (value is not YamlSequenceNode sequence) + throw new SemanticCatalogException(path, $"'{key}' must be a sequence"); + return sequence.Select(item => + item as YamlMappingNode + ?? throw new SemanticCatalogException(path, $"every '{key}' entry must be a mapping") + ); + } + + private static IReadOnlyList Strings(YamlMappingNode node, string key, string path) + { + if (!node.Children.TryGetValue(new YamlScalarNode(key), out YamlNode? value)) + return Array.Empty(); + if (value is not YamlSequenceNode sequence) + throw new SemanticCatalogException(path, $"'{key}' must be a sequence"); + return new ReadOnlyCollection(sequence.Select(item => Scalar(item, path)).ToList()); + } + + private static string RequireScalar(YamlMappingNode node, string key, string path) => + node.Children.TryGetValue(new YamlScalarNode(key), out YamlNode? value) + ? Scalar(value, path) + : throw new SemanticCatalogException(path, $"missing required key '{key}'"); + + private static string Scalar(YamlNode node, string path) => + node is YamlScalarNode { Value: not null } scalar + ? scalar.Value + : throw new SemanticCatalogException(path, "expected a scalar value"); + + private static void RejectUnknownKeys(YamlMappingNode node, HashSet allowed, string path, string what) + { + foreach (YamlNode key in node.Children.Keys) + { + string name = Scalar(key, path); + if (!allowed.Contains(name)) + throw new SemanticCatalogException(path, $"unknown key '{name}' in {what}"); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCoverageAudit.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCoverageAudit.cs new file mode 100644 index 000000000..b69c0298a --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCoverageAudit.cs @@ -0,0 +1,216 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +public sealed record AuditDiagnostic( + string Code, + string SubjectId, + string Message, + string Configurations = "", + string Location = "" +); + +public sealed record AuditResult(bool IsComplete, IReadOnlyList Diagnostics); + +/// +/// Joins a generated to a curated and +/// reports every way the join is incomplete. Many surfaces may share one feature, but each surface +/// must be named by exactly one mapping row, so a newly generated surface stays red until a human +/// classifies it. +/// +public static class SemanticCoverageAudit +{ + public const string UnmappedSurface = "unmapped-surface"; + public const string DuplicateSurfaceMapping = "duplicate-surface-mapping"; + public const string StaleSurfaceMapping = "stale-surface-mapping"; + public const string UnknownFeature = "unknown-feature"; + public const string PatternMapping = "pattern-mapping"; + public const string UnusedFeature = "unused-feature"; + public const string MissingPhaseEffect = "missing-phase-effect"; + public const string RetirementWithoutReason = "retirement-without-reason"; + public const string UnclassifiedMapping = "unclassified-mapping"; + + private static readonly char[] PatternCharacters = { '*', '?', '[', ']' }; + + public static AuditResult Run(SemanticInventory inventory, SemanticCatalog catalog) + { + ArgumentNullException.ThrowIfNull(inventory); + ArgumentNullException.ThrowIfNull(catalog); + + var diagnostics = new List(); + foreach (InventoryDiagnostic diagnostic in inventory.Diagnostics) + { + diagnostics.Add( + new AuditDiagnostic( + diagnostic.Code, + diagnostic.SubjectId, + diagnostic.Message, + diagnostic.Configurations, + diagnostic.Location + ) + ); + } + var featuresById = new Dictionary(StringComparer.Ordinal); + foreach (SemanticFeature feature in catalog.Features) + featuresById[feature.Id] = feature; + + foreach (SemanticFeature feature in catalog.Features) + { + if (feature.Disposition == FeatureDisposition.Semantic) + { + foreach ((string name, PhaseEffect? effect) in Effects(feature)) + { + if (effect is null) + { + diagnostics.Add( + new AuditDiagnostic( + MissingPhaseEffect, + feature.Id, + $"semantic feature '{feature.Id}' declares no {name}" + ) + ); + } + } + } + else if (string.IsNullOrWhiteSpace(feature.Reason) || feature.Citations.Count == 0) + { + diagnostics.Add( + new AuditDiagnostic( + RetirementWithoutReason, + feature.Id, + $"feature '{feature.Id}' is {Name(feature.Disposition)} and needs a reason and at least one citation" + ) + ); + } + } + + var mappedSurfaces = new HashSet(StringComparer.Ordinal); + var usedFeatures = new HashSet(StringComparer.Ordinal); + var inventoryIds = new HashSet( + inventory.Surfaces.Select(surface => surface.Id), + StringComparer.Ordinal + ); + foreach (SurfaceMapping mapping in catalog.SurfaceMappings) + { + if (mapping.SurfaceId.IndexOfAny(PatternCharacters) >= 0) + { + diagnostics.Add( + new AuditDiagnostic( + PatternMapping, + mapping.SurfaceId, + $"mapping '{mapping.SurfaceId}' must name one exact surface; patterns are not allowed" + ) + ); + continue; + } + + if (!mappedSurfaces.Add(mapping.SurfaceId)) + { + diagnostics.Add( + new AuditDiagnostic( + DuplicateSurfaceMapping, + mapping.SurfaceId, + $"surface '{mapping.SurfaceId}' is mapped more than once" + ) + ); + } + + if (!featuresById.ContainsKey(mapping.FeatureId)) + { + diagnostics.Add( + new AuditDiagnostic( + UnknownFeature, + mapping.SurfaceId, + $"surface '{mapping.SurfaceId}' maps to undeclared feature '{mapping.FeatureId}'" + ) + ); + } + else + { + usedFeatures.Add(mapping.FeatureId); + if (featuresById[mapping.FeatureId].Disposition == FeatureDisposition.Unclassified) + { + diagnostics.Add( + new AuditDiagnostic( + UnclassifiedMapping, + mapping.SurfaceId, + $"surface '{mapping.SurfaceId}' maps to unclassified feature '{mapping.FeatureId}'" + ) + ); + } + } + + if (!inventoryIds.Contains(mapping.SurfaceId)) + { + diagnostics.Add( + new AuditDiagnostic( + StaleSurfaceMapping, + mapping.SurfaceId, + $"mapping names '{mapping.SurfaceId}', which the generated inventory no longer contains" + ) + ); + } + } + + foreach (InventorySurface surface in inventory.Surfaces) + { + if (!mappedSurfaces.Contains(surface.Id)) + { + diagnostics.Add( + new AuditDiagnostic( + UnmappedSurface, + surface.Id, + $"generated surface '{surface.Id}' ({surface.Kind}) has no catalog mapping" + ) + ); + } + } + + foreach (SemanticFeature feature in catalog.Features) + { + if (!usedFeatures.Contains(feature.Id)) + { + diagnostics.Add( + new AuditDiagnostic( + UnusedFeature, + feature.Id, + $"feature '{feature.Id}' is declared but no surface maps to it" + ) + ); + } + } + + IReadOnlyList ordered = new ReadOnlyCollection( + diagnostics + .OrderBy(item => item.Code, StringComparer.Ordinal) + .ThenBy(item => item.SubjectId, StringComparer.Ordinal) + .ThenBy(item => item.Location, StringComparer.Ordinal) + .ThenBy(item => item.Configurations, StringComparer.Ordinal) + .ThenBy(item => item.Message, StringComparer.Ordinal) + .ToList() + ); + return new AuditResult(ordered.Count == 0, ordered); + } + + private static IEnumerable<(string Name, PhaseEffect? Effect)> Effects(SemanticFeature feature) + { + yield return ("analysisCandidateEffect", feature.AnalysisCandidateEffect); + yield return ("synthesisConfirmationEffect", feature.SynthesisConfirmationEffect); + yield return ("finalParseEffect", feature.FinalParseEffect); + } + + private static string Name(FeatureDisposition disposition) => + disposition switch + { + FeatureDisposition.Loader => "loader", + FeatureDisposition.Metadata => "metadata", + FeatureDisposition.Ignored => "ignored", + FeatureDisposition.Invalid => "invalid", + FeatureDisposition.BlockedCSharpDefect => "blocked-csharp-defect", + _ => "semantic", + }; +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCoverageInventory.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCoverageInventory.cs new file mode 100644 index 000000000..ddfea3b8b --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/SemanticCoverageInventory.cs @@ -0,0 +1,80 @@ +#nullable enable +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +public static class SemanticCoverageInventory +{ + public static SemanticInventory Generate(SemanticCoverageSourceSet sources) + { + ArgumentNullException.ThrowIfNull(sources); + ArgumentException.ThrowIfNullOrEmpty(sources.DtdPath); + ArgumentNullException.ThrowIfNull(sources.DtdText); + ArgumentNullException.ThrowIfNull(sources.CSharpSources); + if (sources.CSharpSources.Count == 0) + { + SemanticInventory dtdOnly = DtdInventoryReader.Read(sources.DtdPath, sources.DtdText); + return string.IsNullOrEmpty(sources.ToolchainFingerprint) + ? dtdOnly + : dtdOnly with + { + SourceHash = CompositeHash(dtdOnly.SourceHash, "", sources.ToolchainFingerprint), + }; + } + + var duplicatePaths = sources + .CSharpSources.GroupBy(source => NormalizePath(source.RelativePath), StringComparer.Ordinal) + .Where(group => group.Count() > 1) + .Select(group => group.Key) + .OrderBy(path => path, StringComparer.Ordinal) + .ToArray(); + if (duplicatePaths.Length != 0) + { + throw new ArgumentException( + $"Duplicate C# source paths: {string.Join(", ", duplicatePaths)}", + nameof(sources) + ); + } + + SemanticInventory csharp = CSharpInventoryReader.Read( + sources.CSharpSources, + sources.CompleteProjects ?? Array.Empty() + ); + return Compose(sources.DtdPath, sources.DtdText, csharp, sources.ToolchainFingerprint); + } + + internal static SemanticInventory Compose( + string dtdPath, + string dtdText, + SemanticInventory csharp, + string toolchainFingerprint + ) + { + SemanticInventory dtd = DtdInventoryReader.Read(dtdPath, dtdText); + return new SemanticInventory( + dtd.Profile, + CompositeHash(dtd.SourceHash, csharp.SourceHash, toolchainFingerprint), + InventorySurfaceFactory.Sort(dtd.Surfaces.Concat(csharp.Surfaces)), + dtd.Diagnostics.Concat(csharp.Diagnostics) + .OrderBy(diagnostic => diagnostic.Code, StringComparer.Ordinal) + .ThenBy(diagnostic => diagnostic.SubjectId, StringComparer.Ordinal) + .ThenBy(diagnostic => diagnostic.Location, StringComparer.Ordinal) + .ThenBy(diagnostic => diagnostic.Message, StringComparer.Ordinal) + .ToArray() + ); + } + + private static string NormalizePath(string path) => path.Replace('\\', '/'); + + private static string CompositeHash(string dtdHash, string csharpHash, string toolchainFingerprint = "") + { + string material = $"dtd\n{dtdHash}\ncsharp\n{csharpHash}\n"; + if (!string.IsNullOrEmpty(toolchainFingerprint)) + material += $"toolchain\n{toolchainFingerprint}\n"; + byte[] input = Encoding.UTF8.GetBytes(material); + return Convert.ToHexString(SHA256.HashData(input)).ToLowerInvariant(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/TemplateMaskedProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/TemplateMaskedProofs.cs new file mode 100644 index 000000000..3026789ec --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/TemplateMaskedProofs.cs @@ -0,0 +1,160 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind : an AffixTemplate Slot pair +/// whose owning Stratum is morphologicalRuleOrder="unordered" AND every rule referenced by every +/// Slot of that template (not only the pair being swapped) is also a member of the Stratum's own +/// morphologicalRules list. SynthesisStratumRule.Apply unions +/// ApplyMorphologicalRules(input).Concat(ApplyTemplates(input)) into one HashSet under +/// structural Word equality, and an unordered morphologicalRules list compiles to a +/// CombinationRuleCascade that tries every rule at every step regardless of list position. When +/// both hold, the cascade already produces every word the template can produce, so the union is invariant +/// under any permutation of the template's slots and an adjacent swap is unobservable by construction. The +/// check is recomputed from the owning Stratum's and AffixTemplate's current attributes, never stored: +/// flipping the Stratum to linear, or dropping one of the template's rules from the cascade list, +/// invalidates every proof built from it. +/// +public static class TemplateMaskedProofs +{ + public const string Kind = "template-masked"; + + /// Builds a proof for , or null when a + /// precondition fails. + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + TemplateMaskedCheck check = Check(grammar, item); + return check.IsMasked ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies : true only when 's freshly + /// generated adjacent pairs still contain an item with 's id AND the check + /// recomputes masked for it. A stale id, a stratum flipped to linear, and a Slot rule dropped + /// from the cascade all fail closed to false. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return Check(grammar, item).IsMasked; + } + + private sealed record TemplateMaskedCheck(string ItemId, bool IsMasked, string Reason); + + private static TemplateMaskedCheck Check(XDocument grammar, OrderingItem item) + { + if (item.Kind != OrderingListKind.AffixTemplateSlots) + { + return new TemplateMaskedCheck( + item.Id, + false, + $"{item.Kind} pairs are not owned by an AffixTemplate's Slot list" + ); + } + + XElement[] templates = grammar.Descendants("AffixTemplate").ToArray(); + if (item.OwnerOrdinal < 0 || item.OwnerOrdinal >= templates.Length) + { + return new TemplateMaskedCheck( + item.Id, + false, + "owning AffixTemplate ordinal is out of range for the current document" + ); + } + + XElement template = templates[item.OwnerOrdinal]; + XElement? stratum = template.Ancestors("Stratum").FirstOrDefault(); + if (stratum is null) + { + return new TemplateMaskedCheck( + item.Id, + false, + $"AffixTemplate#{item.OwnerOrdinal} (\"{item.OwnerLabel}\") has no owning Stratum in the current document" + ); + } + + // An absent morphologicalRuleOrder is the DTD default "linear" -- never treated as unordered. + string order = (string?)stratum.Attribute("morphologicalRuleOrder") ?? "linear"; + if (order != "unordered") + { + return new TemplateMaskedCheck( + item.Id, + false, + $"owning Stratum's morphologicalRuleOrder=\"{order}\", not unordered: a linear cascade does not " + + "already reproduce the template's slots regardless of position" + ); + } + + var cascadeRules = SplitIdrefs((string?)stratum.Attribute("morphologicalRules")) + .ToHashSet(StringComparer.Ordinal); + + // Every Slot of the WHOLE template, not merely the two being swapped -- the template applies its + // slots in sequence, so a rule reachable only through a slot outside the pair still makes this + // derivation path genuinely distinct from the cascade. + List slots = template.Elements("Slot").ToList(); + var missing = new List(); + for (int i = 0; i < slots.Count; i++) + { + string? rulesAttribute = (string?)slots[i].Attribute("morphologicalRules"); + if (rulesAttribute is null) + { + return new TemplateMaskedCheck( + item.Id, + false, + $"Slot \"{SlotLabel(slots[i], i)}\" of AffixTemplate#{item.OwnerOrdinal} (\"{item.OwnerLabel}\") declares no " + + "morphologicalRules -- cannot verify it is reproduced by the cascade" + ); + } + + foreach (string ruleId in SplitIdrefs(rulesAttribute)) + { + if (!cascadeRules.Contains(ruleId)) + missing.Add($"{ruleId} (Slot \"{SlotLabel(slots[i], i)}\")"); + } + } + + if (missing.Count > 0) + { + return new TemplateMaskedCheck( + item.Id, + false, + $"not every rule referenced by AffixTemplate#{item.OwnerOrdinal} (\"{item.OwnerLabel}\")'s Slots is a member of " + + $"the owning Stratum's morphologicalRules list -- missing {{{string.Join(",", missing)}}}: this template is " + + "a genuinely distinct derivation path, so its slot order can matter" + ); + } + + return new TemplateMaskedCheck( + item.Id, + true, + $"owning Stratum morphologicalRuleOrder=\"unordered\" and every rule referenced by every Slot of " + + $"AffixTemplate#{item.OwnerOrdinal} (\"{item.OwnerLabel}\") is a member of its morphologicalRules list: the " + + "compiled cascade already reproduces everything the template's slots can produce, so slot order is invariant" + ); + } + + private static string SlotLabel(XElement slot, int index) + { + string? name = (string?)slot.Element("Name"); + return string.IsNullOrEmpty(name) ? $"Slot#{index}" : name; + } + + private static IEnumerable SplitIdrefs(string? value) => + string.IsNullOrEmpty(value) + ? Enumerable.Empty() + : value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/TraceEvidence.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/TraceEvidence.cs new file mode 100644 index 000000000..48aefd950 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/TraceEvidence.cs @@ -0,0 +1,260 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// How strongly a fixture shows that it exercised a surface, rather than merely declaring it. +/// +public enum EvidenceStrength +{ + /// + /// Declared in a grammar and nothing more. The construct may never influence any parse, so this + /// is evidence context, never semantic credit. + /// + Presence, + + /// + /// The declaration is deliberately deactivated, so it can never appear in a fired-rule list, and + /// or is a rule capped at zero applications, so it can never appear in a fired-rule list. A word + /// that fails BECAUSE it did not apply is the observation, and that word must name it. + /// + NegativeControl, + + /// + /// The declaration is on the load path of a fixture that produces at least one verified parse, + /// but no per-construct trace attributes the parse to it. + /// + Structural, + + /// + /// A verified parse names the owning rule among the rules that fired, so the construct + /// demonstrably took part in producing a result. + /// + Trace, +} + +public sealed record SurfaceEvidence(string SurfaceId, EvidenceStrength Strength, string FixtureId, string Detail); + +/// +/// Grades grammar-observable coverage by the evidence behind it. A rule-bearing construct is only +/// credited when some word's verified rules: list names the rule that owns it; the conformance +/// runner checks those lists against a real engine run, so they are trace data rather than a claim. +/// +/// Known over-crediting, not yet fixed: attribution is per rule, so every attribute on a firing rule +/// is credited even when its value changed nothing. Deactivated declarations no longer inherit credit +/// from a neighbouring failing word: a word must name the declaration in its `neutralizes:` list. The +/// structural grade remains per fixture, and is reported separately from trace for that reason. +/// +public static class TraceEvidence +{ + /// Elements whose id can appear in a parse's fired-rule list. + private static readonly HashSet RuleElements = new(StringComparer.Ordinal) + { + "MorphologicalRule", + "RealizationalRule", + "CompoundingRule", + "PhonologicalRule", + "MetathesisRule", + }; + + /// + /// Elements whose declarations can never reach , because their + /// ids do not appear in a fired-rule list. AffixTemplate and Slot carry no id in the DTD at all, + /// and the co-occurrence rules are blocking mechanisms the trace attributor does not resolve. + /// + public static readonly IReadOnlySet TraceUnreachableElements = new HashSet(StringComparer.Ordinal) + { + "AffixTemplate", + "Slot", + "AllomorphCoOccurrenceRule", + "MorphemeCoOccurrenceRule", + }; + + /// + /// Grades every observable surface in one fixture. is the union of + /// every verified parse's fired rules plus any blocked-by attribution, since a rule that blocked + /// an analysis also ran. + /// + public static IReadOnlyList Grade( + string fixtureId, + XDocument grammar, + SemanticInventory inventory, + IReadOnlyCollection firedRuleIds, + bool hasVerifiedParse, + IReadOnlyCollection neutralizedIds + ) + { + ArgumentNullException.ThrowIfNull(neutralizedIds); + var neutralized = new HashSet(neutralizedIds, StringComparer.Ordinal); + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(inventory); + ArgumentNullException.ThrowIfNull(firedRuleIds); + var declared = new HashSet(inventory.Surfaces.Select(surface => surface.Id), StringComparer.Ordinal); + var fired = new HashSet(firedRuleIds, StringComparer.Ordinal); + var best = new Dictionary(StringComparer.Ordinal); + + foreach (XElement element in grammar.Descendants()) + { + (EvidenceStrength strength, string detail) = GradeElement(element, fired, hasVerifiedParse, neutralized); + foreach (string surfaceId in ObservableIds(element, declared)) + { + if (best.TryGetValue(surfaceId, out SurfaceEvidence? existing) && existing.Strength >= strength) + continue; + best[surfaceId] = new SurfaceEvidence(surfaceId, strength, fixtureId, detail); + } + } + + return best.Values.OrderBy(item => item.SurfaceId, StringComparer.Ordinal).ToArray(); + } + + private static IEnumerable ObservableIds(XElement element, HashSet declared) + { + string encodedElement = CanonicalIdCodec.Encode(element.Name.LocalName); + string elementId = GrammarFeatureUsage.ElementPrefix + encodedElement; + if (declared.Contains(elementId)) + yield return elementId; + foreach (XAttribute attribute in element.Attributes()) + { + string enumId = + $"{GrammarFeatureUsage.EnumPrefix}{encodedElement}/{CanonicalIdCodec.Encode(attribute.Name.LocalName)}" + + $"/{CanonicalIdCodec.Encode(attribute.Value)}"; + if (declared.Contains(enumId)) + yield return enumId; + } + } + + /// + /// A construct inside a rule is credited only when that rule fired. Everything else can reach at + /// most structural strength, because nothing in a fixture attributes a parse to it. + /// + private static (EvidenceStrength Strength, string Detail) GradeElement( + XElement element, + HashSet fired, + bool hasVerifiedParse, + HashSet neutralized + ) + { + // A deactivated declaration is never loaded, so it can never reach a fired-rule list; the + // observation is a word that fails BECAUSE it is absent. That word must NAME the declaration: + // a fixture-wide flag would let a decoy nothing targets inherit credit from its neighbours. + if (DeactivatedAncestor(element) is string deactivated) + { + // Some deactivatable elements (Stratum) carry no id, so a word may name any id inside the + // deactivated subtree instead; either way it has targeted that subtree. + string? named = NeutralizedName(element, neutralized); + return named is not null + ? ( + EvidenceStrength.NegativeControl, + $"deactivated at '{deactivated}'; a verified failing word neutralizes '{named}'" + ) + : (EvidenceStrength.Presence, $"deactivated at '{deactivated}', which no word names in neutralizes:"); + } + + string? owningRule = OwningRuleId(element); + if (owningRule is not null) + { + if (fired.Contains(owningRule)) + return (EvidenceStrength.Trace, $"rule '{owningRule}' fired in a verified parse"); + + // A rule can be DESIGNED never to fire: multipleApplication="0" caps it at zero + // applications. Its evidence is the same shape as a deactivated decoy's, a word that fails + // because the rule did not apply, so it is credited the same way and only when named. + return neutralized.Contains(owningRule) + ? ( + EvidenceStrength.NegativeControl, + $"rule '{owningRule}' never fires and a verified failing word neutralizes it" + ) + : (EvidenceStrength.Presence, $"declared under rule '{owningRule}', which no verified parse fired"); + } + + if (!hasVerifiedParse) + return (EvidenceStrength.Presence, "fixture produces no verified parse"); + string? unreachable = UnreachableAncestor(element); + return unreachable is not null + ? (EvidenceStrength.Structural, $"trace-unreachable: '{unreachable}' ids never appear in a fired-rule list") + : (EvidenceStrength.Structural, "on the load path of a fixture with a verified parse"); + } + + /// + /// The first identifier a word names, searching this element and its ancestors up to and including + /// the deactivated one, then the ids declared beneath that deactivated element. + /// + private static string? NeutralizedName(XElement element, HashSet neutralized) + { + XElement? deactivated = null; + for (XElement? current = element; current is not null; current = current.Parent) + { + if (Identifier(current) is string own && neutralized.Contains(own)) + return own; + if (neutralized.Contains(current.Name.LocalName)) + return current.Name.LocalName; + if ((string?)current.Attribute("isActive") == "no") + { + deactivated = current; + break; + } + } + + if (deactivated is null) + return null; + return deactivated + .Descendants() + .Select(Identifier) + .FirstOrDefault(id => id is not null && neutralized.Contains(id)); + } + + /// + /// How a word names a declaration: its id, else its Name child's text (Slot, AffixTemplate and + /// Stratum carry no id), else the element name. + /// + private static string? Identifier(XElement element) => + (string?)element.Attribute("id") + ?? element.Elements("Name").FirstOrDefault()?.Value.Trim() + ?? element.Name.LocalName; + + /// The nearest self-or-ancestor element whose kind trace attribution cannot reach. + public static string? UnreachableAncestor(XElement element) + { + ArgumentNullException.ThrowIfNull(element); + for (XElement? current = element; current is not null; current = current.Parent) + { + if (TraceUnreachableElements.Contains(current.Name.LocalName)) + return current.Name.LocalName; + } + + return null; + } + + /// The nearest self-or-ancestor element carrying isActive="no". + public static string? DeactivatedAncestor(XElement element) + { + ArgumentNullException.ThrowIfNull(element); + for (XElement? current = element; current is not null; current = current.Parent) + { + if ((string?)current.Attribute("isActive") == "no") + return (string?)current.Attribute("id") ?? current.Name.LocalName; + } + + return null; + } + + /// The id of the nearest rule-or-self ancestor whose id can appear in a fired-rule list. + public static string? OwningRuleId(XElement element) + { + ArgumentNullException.ThrowIfNull(element); + for (XElement? current = element; current is not null; current = current.Parent) + { + if (!RuleElements.Contains(current.Name.LocalName)) + continue; + string? id = (string?)current.Attribute("id"); + if (!string.IsNullOrEmpty(id)) + return id; + } + + return null; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/UnorderedInvariantProofs.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/UnorderedInvariantProofs.cs new file mode 100644 index 000000000..bdc6336ce --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/UnorderedInvariantProofs.cs @@ -0,0 +1,88 @@ +#nullable enable +using System; +using System.Linq; +using System.Xml.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// +/// Builds and re-verifies a of kind : a Stratum whose +/// morphologicalRuleOrder is unordered compiles to CombinationRuleCascade / +/// ParallelCombinationRuleCascade (SynthesisStratumRule.cs, AnalysisStratumRule.cs), +/// which tries every rule at every recursive step regardless of list position and collects into a +/// HashSet under structural Word equality. The reachable set is therefore invariant under +/// any permutation of that Stratum's morphologicalRules list, so an adjacent pair drawn from it can +/// never be order-sensitive. The check is recomputed from the owning Stratum's current attribute, never +/// stored, so flipping the stratum back to linear invalidates every proof built from it. +/// +public static class UnorderedInvariantProofs +{ + public const string Kind = "unordered-invariant"; + + /// Builds a proof for , or null when its owning + /// Stratum is not unordered. + public static Proof? TryBuild(XDocument grammar, OrderingItem item) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(item); + UnorderedInvariantCheck check = Check(grammar, item); + return check.IsUnordered ? new Proof(item.Id, Kind, check.Reason) : null; + } + + /// + /// Re-verifies : true only when 's freshly + /// generated adjacent pairs still contain an item with 's id AND that item's + /// current owning Stratum still declares morphologicalRuleOrder="unordered". A stale id and a + /// recomputed linear/absent order both fail closed to false. + /// + public static bool Verify(XDocument grammar, string fixtureId, Proof proof) + { + ArgumentNullException.ThrowIfNull(grammar); + ArgumentNullException.ThrowIfNull(fixtureId); + ArgumentNullException.ThrowIfNull(proof); + OrderingItem? item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .FirstOrDefault(candidate => candidate.Id == proof.ItemId); + if (item is null) + return false; + return Check(grammar, item).IsUnordered; + } + + private sealed record UnorderedInvariantCheck(string ItemId, bool IsUnordered, string Reason); + + private static UnorderedInvariantCheck Check(XDocument grammar, OrderingItem item) + { + if (item.Kind != OrderingListKind.StratumMorphologicalRules) + { + return new UnorderedInvariantCheck( + item.Id, + false, + $"{item.Kind} pairs are not owned by a Stratum's morphologicalRuleOrder" + ); + } + + XElement[] strata = grammar.Descendants("Stratum").ToArray(); + if (item.OwnerOrdinal < 0 || item.OwnerOrdinal >= strata.Length) + { + return new UnorderedInvariantCheck( + item.Id, + false, + "owning Stratum ordinal is out of range for the current document" + ); + } + + string order = (string?)strata[item.OwnerOrdinal].Attribute("morphologicalRuleOrder") ?? "linear"; + return order == "unordered" + ? new UnorderedInvariantCheck( + item.Id, + true, + $"Stratum#{item.OwnerOrdinal} (\"{item.OwnerLabel}\") morphologicalRuleOrder=\"unordered\": " + + "the compiled cascade tries every rule at every step regardless of list position" + ) + : new UnorderedInvariantCheck( + item.Id, + false, + $"Stratum#{item.OwnerOrdinal} (\"{item.OwnerLabel}\") morphologicalRuleOrder=\"{order}\", not unordered" + ); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/WordsSchemaValidation.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/WordsSchemaValidation.cs new file mode 100644 index 000000000..3040d75be --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SemanticCoverage/WordsSchemaValidation.cs @@ -0,0 +1,142 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.Json.Nodes; +using Json.Schema; +using YamlDotNet.RepresentationModel; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +/// Validates an authored words.yaml against the published words schema. +/// The schema, not the loader, is what a consumer outside this repository can read, so the +/// two must agree on every checked-in fixture. Plain YAML only: aliases, anchors, merge keys and +/// custom tags are refused before conversion rather than silently resolved. +public static class WordsSchemaValidation +{ + public const string SchemaRelativePath = "conformance/schema/words.schema.json"; + + // A schema registers itself globally under its $id, so it is loaded once per path rather than + // once per file validated. + private static readonly Dictionary LoadedSchemas = new(StringComparer.OrdinalIgnoreCase); + + /// Validation messages for ; empty when it conforms. + public static IReadOnlyList Validate(string wordsPath, string schemaPath) + { + ArgumentException.ThrowIfNullOrWhiteSpace(wordsPath); + ArgumentException.ThrowIfNullOrWhiteSpace(schemaPath); + + JsonNode? node = ReadAsJson(wordsPath); + if (node is null) + return new[] { "words.yaml is empty" }; + + using var document = System.Text.Json.JsonDocument.Parse(node.ToJsonString()); + EvaluationResults results = Schema(schemaPath) + .Evaluate(document.RootElement, new EvaluationOptions { OutputFormat = OutputFormat.List }); + if (results.IsValid) + return Array.Empty(); + + return (results.Details ?? new List()) + .Where(detail => detail.Errors is { Count: > 0 }) + .SelectMany(detail => detail.Errors!.Select(error => $"{detail.InstanceLocation}: {error.Value}")) + .DefaultIfEmpty("does not conform to " + SchemaRelativePath) + .ToArray(); + } + + private static JsonSchema Schema(string schemaPath) + { + string key = Path.GetFullPath(schemaPath); + lock (LoadedSchemas) + { + if (!LoadedSchemas.TryGetValue(key, out JsonSchema? schema)) + { + schema = JsonSchema.FromFile(key); + LoadedSchemas[key] = schema; + } + + return schema; + } + } + + private static JsonNode? ReadAsJson(string wordsPath) + { + var stream = new YamlStream(); + using (var reader = new StreamReader(wordsPath)) + stream.Load(reader); + if (stream.Documents.Count == 0) + return null; + if (stream.Documents.Count != 1) + throw new InvalidDataException($"{wordsPath}: a words file must contain exactly one YAML document."); + + return Convert(stream.Documents[0].RootNode, wordsPath); + } + + private static JsonNode? Convert(YamlNode node, string path) + { + if (!node.Anchor.IsEmpty) + throw new InvalidDataException($"{path}: YAML anchors are not admitted."); + + switch (node) + { + case YamlMappingNode mapping: + { + var result = new JsonObject(); + foreach (KeyValuePair pair in mapping.Children) + { + if (pair.Key is not YamlScalarNode { Value: { } key }) + throw new InvalidDataException($"{path}: mapping keys must be scalars."); + if (key == "<<") + throw new InvalidDataException($"{path}: YAML merge keys are not admitted."); + result[key] = Convert(pair.Value, path); + } + + return result; + } + + case YamlSequenceNode sequence: + { + var result = new JsonArray(); + foreach (YamlNode child in sequence.Children) + result.Add(Convert(child, path)); + return result; + } + + case YamlScalarNode scalar: + return ConvertScalar(scalar); + + default: + throw new InvalidDataException($"{path}: unsupported YAML node '{node.GetType().Name}'."); + } + } + + /// Applies YAML 1.1 core scalar resolution for the types the schema distinguishes. + private static JsonNode? ConvertScalar(YamlScalarNode scalar) + { + string? value = scalar.Value; + if (value is null) + return null; + if ( + scalar.Style + is YamlDotNet.Core.ScalarStyle.SingleQuoted + or YamlDotNet.Core.ScalarStyle.DoubleQuoted + or YamlDotNet.Core.ScalarStyle.Literal + or YamlDotNet.Core.ScalarStyle.Folded + ) + { + return JsonValue.Create(value); + } + + if (value is "null" or "~" or "") + return null; + if (value is "true" or "True" or "TRUE") + return JsonValue.Create(true); + if (value is "false" or "False" or "FALSE") + return JsonValue.Create(false); + if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long integer)) + return JsonValue.Create(integer); + + return JsonValue.Create(value); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/SignatureTsv.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SignatureTsv.cs new file mode 100644 index 000000000..0ab0088e5 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/SignatureTsv.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// One well-formed 5-column row of the batch TSV format (see conformance/PROTOCOL.md). +public readonly struct TsvRow(int idx, string word, long ms, string status, string signature) +{ + public readonly int Idx = idx; + public readonly string Word = word; + public readonly long Ms = ms; + public readonly string Status = status; + public readonly string Signature = signature; +} + +/// +/// Parsing and comparison for the batch TSV format, per conformance/PROTOCOL.md sections 2-4: +/// only word/status/signature are compared; idx and ms are ignored; any line that isn't a +/// well-formed 5-column row (in particular the "STARTED" 3-column sentinel) is skipped; a +/// signature's ";"-separated entries are compared as a multiset, not a plain string. +/// +public static class SignatureTsv +{ + /// Reads a batch TSV file, silently skipping malformed/sentinel lines. + public static List ReadFile(string path) + { + var rows = new List(); + foreach (string line in File.ReadAllLines(path)) + { + if (TryParseRow(line, out TsvRow row)) + rows.Add(row); + } + return rows; + } + + public static bool TryParseRow(string line, out TsvRow row) + { + row = default; + if (string.IsNullOrEmpty(line)) + return false; + string[] cols = line.Split('\t'); + // A well-formed row has exactly 5 columns (idx, word, ms, status, signature). The + // 3-column "STARTED" sentinel and any other malformed line is not comparison data. + if (cols.Length != 5) + return false; + if (!int.TryParse(cols[0], out int idx)) + return false; + if (!long.TryParse(cols[2], out long ms)) + return false; + // A well-formed row's status is always "ok" or "SKIPPED" (see PROTOCOL.md section 2); any + // other value means the line isn't actually a comparison-worthy result row. + if (cols[3] != "ok" && cols[3] != "SKIPPED") + return false; + row = new TsvRow(idx, cols[1], ms, cols[3], cols[4]); + return true; + } + + /// The ";"-separated signature entries as a multiset (sorted list, for equality/diff display). + public static List SplitSignature(string signature) + { + if (signature == "-") + return new List(); + return signature.Split(';').OrderBy(s => s, StringComparer.Ordinal).ToList(); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/TraceRuleAttributor.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/TraceRuleAttributor.cs new file mode 100644 index 000000000..17330376a --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/TraceRuleAttributor.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using SIL.Machine.Morphology.HermitCrab.MorphologicalRules; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Extracts, for one successful parse () returned by Morpher.ParseWord, +/// the set of grammar rule ids a word's "rules:" field is verified against: self-check runs the +/// oracle with tracing enabled and fails if the traced rule applications don't match the declared +/// list. +/// +/// Two different sources, because no single API gives both: +/// +/// Morphological rules (AffixProcessRule/CompoundingRule) come straight off +/// -- populated once during analysis-direction unapplication +/// and carried forward unchanged through synthesis, so it is exact and per-result, no ambiguity. +/// Phonological rules (RewriteRule/MetathesisRule) have no equivalent per-Word list -- +/// only records their application as nodes +/// (), via . +/// Unlike , that call does NOT update +/// Word.CurrentTrace (see TraceManager.cs), so a phonological-rule trace node is a *sibling* +/// of the branch that produced a given final Word, not an ancestor reachable by walking +/// CurrentTrace upward. This class instead walks the ENTIRE trace tree for the word (the +/// trace out-parameter of ParseWord) and collects every +/// node system-wide. +/// +/// +/// Documented limitation (ambiguous words): when a surface word has more than one successful +/// analysis, this global trace walk cannot attribute a specific phonological rule firing to one +/// analysis branch over another -- it reports the UNION of every phonological rule that fired +/// anywhere while producing any of the word's results. applies this same +/// phonological-rule set to every one of that word's declared parses, so a false PASS is possible +/// in principle for an ambiguous word whose two parses use different phonological rules but the +/// same declared "rules:" set does not distinguish them. This does not affect any G1 fixture (the +/// pilot grammar has zero phonological rules by construction; the one ambiguous pilot word's +/// parses differ only in a morphological rule, which IS attributed exactly per-result). A future +/// language with both ambiguity and phonological rules would need per-branch trace correlation +/// (e.g. threading a distinguishing marker through ITraceManager.PhonologicalRuleApplied) to +/// close this gap -- flagged here rather than silently shipped. +/// +/// RealizationalAffixProcessRule applications are attributed word-level too: +/// Word.MorphologicalRuleUnapplied deliberately excludes them from the _mruleApps +/// list that backs (see Word.cs), so they cannot come from +/// the per-result source above -- but SynthesisRealizationalAffixProcessRule does report +/// successful applications through , which +/// records a node. The same trace walk that +/// collects phonological rules therefore also collects realizational rules (with the same +/// union-across-results ambiguity caveat), keyed off the node's Source type. +/// +public static class TraceRuleAttributor +{ + public static HashSet MorphologicalRuleIds(Word result, GrammarRuleIndex index) + { + var ids = new HashSet(StringComparer.Ordinal); + foreach (IMorphologicalRule rule in result.MorphologicalRules) + { + string id = index.ResolveMorphologicalRuleId(rule); + if (id != null) + ids.Add(id); + } + return ids; + } + + /// The word-level (not per-result) set of phonological and realizational rule ids fired + /// anywhere in the trace tree rooted at -- see the class doc comment for + /// why these two kinds are word-level, not per-result. + public static HashSet WordLevelRuleIds(object trace, GrammarRuleIndex index) + { + var ids = new HashSet(StringComparer.Ordinal); + if (trace is not Trace root) + return ids; + Walk(root); + return ids; + + void Walk(Trace node) + { + // TraceManager records BOTH outcomes of a synthesis-direction rule attempt as + // *RuleSynthesis nodes: *RuleApplied (FailureReason.None, Output set) and + // *RuleNotApplied (FailureReason set, no Output). Only the applied nodes count as + // "this rule fired" -- without this filter, every phonological rule in a stratum shows + // up in every word's traced set merely because its pass ran. + if (node.FailureReason == FailureReason.None) + { + if (node.Type == TraceType.PhonologicalRuleSynthesis && node.Source is IPhonologicalRule prule) + { + string id = index.ResolvePhonologicalRuleId(prule); + if (id != null) + ids.Add(id); + } + else if ( + node.Type == TraceType.MorphologicalRuleSynthesis + && node.Source is RealizationalAffixProcessRule rrule + ) + { + string id = index.ResolveMorphologicalRuleId(rrule); + if (id != null) + ids.Add(id); + } + } + foreach (Trace child in node.Children) + Walk(child); + } + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/WordsYaml.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/WordsYaml.cs new file mode 100644 index 000000000..3f514fab0 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/WordsYaml.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// In-memory model of one words.yaml file. Parsed by , which +/// enforces the strict, fixed key vocabulary -- this class only carries already-validated data, it +/// does not itself validate anything. +/// +public class WordsYaml +{ + public string Language = ""; + public List InspiredBy { get; } = new(); + public List Sources { get; } = new(); + public List Requires { get; } = new(); + + /// Edge-cases only: a wall-clock budget in milliseconds (materialized as manifest.json's + /// budget.wallClockMs). + public long? BudgetMs; + + /// Edge-cases only: this fixture's ground truth is a crash, not a signature (materialized + /// as manifest.json's expectCrash). + public bool ExpectCrash; + + public List Words { get; } = new(); +} + +public class WordEntry +{ + public string Word = ""; + public string Note = ""; + public string Provenance = ""; + public bool ExpectFail; + + /// + /// The oracle SKIPS this word rather than returning a genuine zero-parse "ok": it throws + /// (e.g. the surface contains a segment undeclared in the + /// grammar's CharacterDefinitionTable). Distinct from (well-formed input, + /// zero valid analyses) because the two produce different adapter-contract status columns -- + /// "SKIPPED" vs "ok" -- and BatchCommand/expected.tsv distinguish them (materialized row: "N word 0 SKIPPED -"). + /// Both modes verify it: self-check confirms an was actually + /// thrown; adapter mode materializes status "SKIPPED". Like expect_fail, a skip word has no parses. + /// + public bool ExpectSkip; + + public List BlockedBy { get; } = new(); + + /// + /// Declaration ids (a grammar element's id) whose deactivation this word's failure + /// observes. Without it, a deactivated declaration would inherit credit from any failing word in + /// the same fixture, which is how a decoy nothing targets came to be graded as a control. + /// + public List Neutralizes { get; } = new(); + public List Exercises { get; } = new(); + public List Parses { get; } = new(); + + /// + /// Cell ids from conformance/dataflow-obligations.tsv this word is meant to witness -- checked by + /// DataflowClaimGate, never trusted by it. A claim can carry the literal machine evidence + /// (/) it was reviewed + /// against, inline and human-readable, so DataflowClaimGate can recompute the severance and a + /// reviewer can read the same values without joining four files by hand. + /// + public List ClaimedCells { get; } = new(); +} + +public class ClaimedCellEntry +{ + public string Cell = ""; + + /// Plain-English description of what is removed (e.g. "ruleFeatures on LexicalEntry + /// VOKAD"). Read by a reviewer; not itself re-checked -- DataflowClaimGate derives which + /// element/attribute to sever from the ledger row, not from this text. + public string Severing = ""; + + /// The word's parse outcome (SignatureFormat's "status::signature" form) BEFORE either the + /// writer or the reader is severed. Empty means no inline evidence has been recorded for this claim + /// yet -- not a defect, just unreviewed. + public string Before = ""; + + /// The word's parse outcome AFTER severing either the writer or the reader (a genuine + /// pair witness means both severances produce the same After). DataflowClaimGate recomputes both + /// severances against the CURRENT grammar and treats any mismatch -- of Before or of either After -- + /// as a stale claim: reviewed once, against evidence that has since moved. + public string After = ""; + + /// + /// The plain control word (every claim needs a control) that demonstrates this cell's condition is + /// not vacuous -- MC/DC independence needs a second case + /// differing in exactly this one condition. DataflowClaimGate checks the named word exists in the + /// same fixture and that its outcome differs from this word's; it does not (yet) confirm the + /// grammar difference between them is the single named condition. + /// + public string DistinctFrom = ""; + + /// Prose: why this word demonstrates this cell. Read by a reviewer; not mechanically + /// checked. + public string Proof = ""; + + /// Whether the four review fields (Severing/Before/After/Proof) are present as a bundle -- + /// the loader enforces all-or-nothing, so checking any one of them is equivalent to checking all. + public bool HasReviewBundle => Before.Length != 0; +} + +public class ParseEntry +{ + public string Signature = ""; + public string Gloss = ""; + public bool Guess; + public List Rules { get; } = new(); + public List Exercises { get; } = new(); +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Conformance/WordsYamlLoader.cs b/src/SIL.Machine.Morphology.HermitCrab.Conformance/WordsYamlLoader.cs new file mode 100644 index 000000000..fdd80be49 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Conformance/WordsYamlLoader.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.RepresentationModel; + +namespace SIL.Machine.Morphology.HermitCrab.Conformance; + +/// +/// Strict parser for a fixture's words.yaml: enforces a fixed key vocabulary (unknown keys +/// are hard errors) and a plain YAML 1.2 subset only -- no anchors, aliases, merge keys, or custom +/// tags. +/// +public static class WordsYamlLoader +{ + // The complete, fixed key vocabulary at each of the three mapping levels. Anything else + // encountered is a hard parse error -- this is the mechanism behind "unknown keys are errors". + private static readonly HashSet FrontMatterKeys = new(StringComparer.Ordinal) + { + "language", + "inspired_by", + "sources", + "requires", + "budget_ms", + "expect_crash", + "words", + }; + private static readonly HashSet WordKeys = new(StringComparer.Ordinal) + { + "word", + "note", + "provenance", + "expect_fail", + "expect_skip", + "blocked_by", + "neutralizes", + "exercises", + "parses", + "claimed_cells", + }; + private static readonly HashSet ParseKeys = new(StringComparer.Ordinal) + { + "signature", + "gloss", + "guess", + "rules", + "exercises", + }; + private static readonly HashSet ClaimedCellKeys = new(StringComparer.Ordinal) + { + "cell", + "severing", + "before", + "after", + "distinct_from", + "proof", + }; + + // The inline-review bundle is all-or-nothing: a partial before/after (or a severing/proof with no + // outcome to check it against) cannot be recomputed, so it is rejected rather than silently treated + // as unreviewed. distinct_from is deliberately NOT in this set -- it is checkable on its own + // (existence + outcome difference within the fixture) whether or not a review bundle is present. + private static readonly string[] ReviewBundleKeys = { "severing", "before", "after", "proof" }; + + public static WordsYaml Load(string path) + { + string text = File.ReadAllText(path); + try + { + RejectNonPlainConstructs(text, path); + + var yamlStream = new YamlStream(); + using (var reader = new StringReader(text)) + yamlStream.Load(reader); + + if (yamlStream.Documents.Count != 1) + throw new WordsYamlException(path, "expected exactly one YAML document"); + + if (yamlStream.Documents[0].RootNode is not YamlMappingNode root) + throw new WordsYamlException(path, "top-level YAML node must be a mapping"); + + return ParseFrontMatter(root, path); + } + catch (YamlException ex) + { + throw new WordsYamlException(path, $"YAML syntax error at {ex.Start}-{ex.End}: {ex.Message}", ex); + } + } + + /// + /// Scans the raw parser event stream (not the composed node tree -- by the time + /// composes a tree, an alias has already been resolved into a shared + /// node reference and is no longer visible as such) for anchors, aliases, and non-core tags, + /// per the plan's "no anchors, aliases, merge keys, or custom tags" rule. Merge keys ("<<") + /// are a mapping-key convention layered on plain scalars, not a distinct event type, so those + /// are rejected in instead, where key strings are actually read. + /// + private static void RejectNonPlainConstructs(string text, string path) + { + var parser = new Parser(new StringReader(text)); + while (parser.MoveNext()) + { + ParsingEvent evt = parser.Current; + if (evt is AnchorAlias) + throw new WordsYamlException(path, "YAML aliases (*name) are not allowed in words.yaml"); + + if (evt is NodeEvent nodeEvent) + { + if (!nodeEvent.Anchor.IsEmpty) + throw new WordsYamlException(path, "YAML anchors (&name) are not allowed in words.yaml"); + if ( + !nodeEvent.Tag.IsEmpty + && !nodeEvent.Tag.Value.StartsWith("tag:yaml.org,2002:", StringComparison.Ordinal) + ) + { + throw new WordsYamlException( + path, + $"custom YAML tag '{nodeEvent.Tag.Value}' is not allowed in words.yaml" + ); + } + } + } + } + + private static WordsYaml ParseFrontMatter(YamlMappingNode root, string path) + { + var doc = new WordsYaml(); + Dictionary map = RequireMapping(root, FrontMatterKeys, path, "front matter"); + + doc.Language = RequireScalar(map, "language", path, "front matter"); + AppendScalarList(map, "inspired_by", doc.InspiredBy, path, "front matter"); + AppendScalarList(map, "sources", doc.Sources, path, "front matter"); + AppendScalarList(map, "requires", doc.Requires, path, "front matter"); + if (map.TryGetValue("budget_ms", out YamlNode budgetNode)) + doc.BudgetMs = long.Parse(RequireScalarNode(budgetNode, path, "front matter.budget_ms")); + if (map.TryGetValue("expect_crash", out YamlNode crashNode)) + doc.ExpectCrash = ParseBool(RequireScalarNode(crashNode, path, "front matter.expect_crash"), path); + + if (!map.TryGetValue("words", out YamlNode wordsNode) || wordsNode is not YamlSequenceNode wordsSeq) + throw new WordsYamlException(path, "front matter must have a 'words' sequence"); + if (wordsSeq.Children.Count == 0) + throw new WordsYamlException(path, "'words' must contain at least one word entry"); + + foreach (YamlNode wordNode in wordsSeq.Children) + doc.Words.Add(ParseWord(wordNode, path)); + + return doc; + } + + private static WordEntry ParseWord(YamlNode node, string path) + { + if (node is not YamlMappingNode mapNode) + throw new WordsYamlException(path, "each 'words' entry must be a mapping"); + Dictionary map = RequireMapping(mapNode, WordKeys, path, "word"); + + var entry = new WordEntry + { + Word = RequireScalar(map, "word", path, "word"), + Note = RequireScalar(map, "note", path, "word"), + }; + if (map.TryGetValue("provenance", out YamlNode provNode)) + entry.Provenance = RequireScalarNode(provNode, path, $"word '{entry.Word}'.provenance"); + if (map.TryGetValue("expect_fail", out YamlNode failNode)) + entry.ExpectFail = ParseBool(RequireScalarNode(failNode, path, $"word '{entry.Word}'.expect_fail"), path); + if (map.TryGetValue("expect_skip", out YamlNode skipNode)) + entry.ExpectSkip = ParseBool(RequireScalarNode(skipNode, path, $"word '{entry.Word}'.expect_skip"), path); + AppendScalarList(map, "blocked_by", entry.BlockedBy, path, $"word '{entry.Word}'"); + AppendScalarList(map, "neutralizes", entry.Neutralizes, path, $"word '{entry.Word}'"); + AppendScalarList(map, "exercises", entry.Exercises, path, $"word '{entry.Word}'"); + if (map.TryGetValue("claimed_cells", out YamlNode claimedCellsNode)) + { + if (claimedCellsNode is not YamlSequenceNode claimedCellsSeq) + throw new WordsYamlException(path, $"word '{entry.Word}'.claimed_cells: expected a sequence"); + foreach (YamlNode claimNode in claimedCellsSeq.Children) + entry.ClaimedCells.Add(ParseClaimedCell(claimNode, entry.Word, path)); + } + + if (entry.ExpectFail && entry.ExpectSkip) + { + throw new WordsYamlException( + path, + $"word '{entry.Word}': 'expect_fail' and 'expect_skip' are mutually exclusive " + + "(a word is either a genuine zero-parse 'ok' or a SKIPPED InvalidShapeException, not both)" + ); + } + if (entry.BlockedBy.Count > 0 && !entry.ExpectFail) + { + throw new WordsYamlException( + path, + $"word '{entry.Word}': 'blocked_by' is only meaningful on an 'expect_fail' word" + ); + } + + bool hasParses = map.TryGetValue("parses", out YamlNode parsesNode); + if (entry.ExpectFail || entry.ExpectSkip) + { + if (hasParses) + { + throw new WordsYamlException( + path, + $"word '{entry.Word}': expect_fail/expect_skip words must not have 'parses'" + ); + } + } + else + { + if (!hasParses || parsesNode is not YamlSequenceNode parsesSeq || parsesSeq.Children.Count == 0) + { + throw new WordsYamlException( + path, + $"word '{entry.Word}': non-expect_fail words must have at least one entry under 'parses'" + ); + } + foreach (YamlNode parseNode in parsesSeq.Children) + entry.Parses.Add(ParseParse(parseNode, entry.Word, path)); + } + + return entry; + } + + private static ParseEntry ParseParse(YamlNode node, string word, string path) + { + if (node is not YamlMappingNode mapNode) + throw new WordsYamlException(path, $"word '{word}': each 'parses' entry must be a mapping"); + Dictionary map = RequireMapping(mapNode, ParseKeys, path, $"word '{word}'.parses[]"); + + var parse = new ParseEntry { Signature = RequireScalar(map, "signature", path, $"word '{word}'.parses[]") }; + if (map.TryGetValue("gloss", out YamlNode glossNode)) + parse.Gloss = RequireScalarNode(glossNode, path, $"word '{word}'.parses[].gloss"); + if (map.TryGetValue("guess", out YamlNode guessNode)) + parse.Guess = ParseBool(RequireScalarNode(guessNode, path, $"word '{word}'.parses[].guess"), path); + if (!map.ContainsKey("rules")) + throw new WordsYamlException(path, $"word '{word}': every parse requires a 'rules' list (may be empty [])"); + AppendScalarList(map, "rules", parse.Rules, path, $"word '{word}'.parses[]"); + AppendScalarList(map, "exercises", parse.Exercises, path, $"word '{word}'.parses[]"); + + return parse; + } + + private static ClaimedCellEntry ParseClaimedCell(YamlNode node, string word, string path) + { + if (node is not YamlMappingNode mapNode) + throw new WordsYamlException(path, $"word '{word}'.claimed_cells[]: each entry must be a mapping"); + Dictionary map = RequireMapping( + mapNode, + ClaimedCellKeys, + path, + $"word '{word}'.claimed_cells[]" + ); + + var claim = new ClaimedCellEntry { Cell = RequireScalar(map, "cell", path, $"word '{word}'.claimed_cells[]") }; + + int bundlePresent = ReviewBundleKeys.Count(map.ContainsKey); + if (bundlePresent != 0 && bundlePresent != ReviewBundleKeys.Length) + { + throw new WordsYamlException( + path, + $"word '{word}'.claimed_cells[] for '{claim.Cell}': 'severing', 'before', 'after', and " + + "'proof' must all be present or all absent (a partial review bundle cannot be " + + "recomputed, so it would silently read as unreviewed instead of rejected)" + ); + } + if (bundlePresent == ReviewBundleKeys.Length) + { + claim.Severing = RequireScalar(map, "severing", path, $"word '{word}'.claimed_cells[]"); + claim.Before = RequireScalar(map, "before", path, $"word '{word}'.claimed_cells[]"); + claim.After = RequireScalar(map, "after", path, $"word '{word}'.claimed_cells[]"); + claim.Proof = RequireScalar(map, "proof", path, $"word '{word}'.claimed_cells[]"); + } + + if (map.TryGetValue("distinct_from", out YamlNode distinctFromNode)) + { + claim.DistinctFrom = RequireScalarNode( + distinctFromNode, + path, + $"word '{word}'.claimed_cells[].distinct_from" + ); + } + + return claim; + } + + /// + /// Reads a mapping node's keys into a dictionary, hard-failing on any key not in + /// (the "unknown keys are hard errors" rule) and on any + /// non-scalar key (which would indicate a merge key or other non-plain construct). + /// + private static Dictionary RequireMapping( + YamlMappingNode node, + HashSet allowedKeys, + string path, + string context + ) + { + var map = new Dictionary(StringComparer.Ordinal); + foreach (KeyValuePair entry in node.Children) + { + if (entry.Key is not YamlScalarNode keyScalar || keyScalar.Value == null) + throw new WordsYamlException(path, $"{context}: mapping keys must be plain scalars"); + string key = keyScalar.Value; + if (key == "<<") + throw new WordsYamlException(path, $"{context}: YAML merge keys ('<<') are not allowed"); + if (!allowedKeys.Contains(key)) + { + throw new WordsYamlException( + path, + $"{context}: unknown key '{key}' (allowed: {string.Join(", ", allowedKeys.OrderBy(k => k))})" + ); + } + if (map.ContainsKey(key)) + throw new WordsYamlException(path, $"{context}: duplicate key '{key}'"); + map[key] = entry.Value; + } + return map; + } + + private static string RequireScalar(Dictionary map, string key, string path, string context) + { + if (!map.TryGetValue(key, out YamlNode node)) + throw new WordsYamlException(path, $"{context}: missing required key '{key}'"); + return RequireScalarNode(node, path, $"{context}.{key}"); + } + + private static string RequireScalarNode(YamlNode node, string path, string context) + { + if (node is not YamlScalarNode scalar || scalar.Value == null || scalar.Value.Length == 0) + throw new WordsYamlException(path, $"{context}: expected a non-empty scalar value"); + return scalar.Value; + } + + private static void AppendScalarList( + Dictionary map, + string key, + List target, + string path, + string context + ) + { + if (!map.TryGetValue(key, out YamlNode node)) + return; + if (node is not YamlSequenceNode seq) + throw new WordsYamlException(path, $"{context}.{key}: expected a sequence"); + foreach (YamlNode child in seq.Children) + target.Add(RequireScalarNode(child, path, $"{context}.{key}[]")); + } + + private static bool ParseBool(string value, string path) + { + return value switch + { + "true" => true, + "false" => false, + _ => throw new WordsYamlException(path, $"expected 'true' or 'false', got '{value}'"), + }; + } +} + +public class WordsYamlException(string path, string message, Exception inner = null) + : Exception($"{path}: {message}", inner) { } diff --git a/src/SIL.Machine.Morphology.HermitCrab.Tool/BatchCommand.cs b/src/SIL.Machine.Morphology.HermitCrab.Tool/BatchCommand.cs new file mode 100644 index 000000000..64ffbfc3d --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Tool/BatchCommand.cs @@ -0,0 +1,74 @@ +using System.Diagnostics; +using System.IO; +using ManyConsole; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Parses every word in a word list and records a per-word result signature plus elapsed time, so two +/// runs (e.g. before/after an engine change on this branch) can be diffed to confirm parse results are +/// unchanged. Flushed per word and crash-resumable via --start, since some corpus words are expensive +/// enough (this branch is plain master, with none of the hc-rustify or parse-optimization speedups, so a +/// handful of words can take minutes) that losing partial progress on a long corpus run is unacceptable. +/// +/// Ported from the parse-opt worktree's BatchCommand.cs, with the --rule-stats and --parallel options +/// removed: those depend on Morpher.AccumulateRuleStats / AnalysisRuleStats / SynthesisRuleStats and +/// Morpher.MaxDegreeOfParallelism, which are parse-optimization-branch-only additions (#446/#451) that do +/// not exist on this branch's plain-master Morpher. +/// +internal class BatchCommand : ConsoleCommand +{ + private readonly HCContext _context; + private int _startIndex; + + public BatchCommand(HCContext context) + { + _context = context; + + IsCommand("batch", "Parses every word in a word list, recording a result signature and timing per word"); + SkipsCommandSummaryBeforeRunning(); + HasAdditionalArguments(2, " "); + HasOption("start=", "0-based line index to resume at (for crash recovery)", v => _startIndex = int.Parse(v)); + } + + public override int Run(string[] remainingArguments) + { + string wordListPath = remainingArguments[0]; + string outputPath = remainingArguments[1]; + + string[] words = SignatureFormat.LoadWords(wordListPath); + + return RunSequential(words, outputPath); + } + + private int RunSequential(string[] words, string outputPath) + { + using var writer = new StreamWriter(outputPath, append: _startIndex > 0) { AutoFlush = true }; + var totalSw = Stopwatch.StartNew(); + long parsed = 0, + skipped = 0; + for (int i = _startIndex; i < words.Length; i++) + { + string word = words[i]; + // Sentinel written before the attempt: if this word crashes the process, a wrapper script + // can read the last line to find where to resume. + writer.WriteLine($"{i}\t{word}\tSTARTED"); + (string status, long elapsedMs, string signature) = SignatureFormat.ParseOneWord(_context.Morpher, word); + writer.WriteLine($"{i}\t{word}\t{elapsedMs}\t{status}\t{signature}"); + if (status == "SKIPPED") + skipped++; + else + parsed++; + if (i % 100 == 0) + _context.Out.WriteLine("[{0}/{1}]", i, words.Length); + } + totalSw.Stop(); + _context.Out.WriteLine( + "batch complete: {0} words parsed ({1} skipped), {2}ms total", + parsed, + skipped, + totalSw.ElapsedMilliseconds + ); + return 0; + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab.Tool/Program.cs b/src/SIL.Machine.Morphology.HermitCrab.Tool/Program.cs index ff8e86bcc..45397e013 100644 --- a/src/SIL.Machine.Morphology.HermitCrab.Tool/Program.cs +++ b/src/SIL.Machine.Morphology.HermitCrab.Tool/Program.cs @@ -92,9 +92,11 @@ public static int Main(string[] args) new TracingCommand(context), new TestCommand(context), new StatsCommand(context), + new BatchCommand(context), }; string input; + int exitCode = 0; if (!string.IsNullOrEmpty(scriptFile)) { using (var scriptReader = new StreamReader(scriptFile)) @@ -105,7 +107,12 @@ public static int Main(string[] args) if (!input.Trim().StartsWith("#") && input.Trim() != "") { string[] cmdArgs = SplitCommandLine(input); - ConsoleCommandDispatcher.DispatchCommand(commands, cmdArgs, context.Out); + int result = ConsoleCommandDispatcher.DispatchCommand(commands, cmdArgs, context.Out); + // Remember the first nonzero result rather than the last: once a script + // line fails, later lines running (or not) shouldn't paper over that with + // a subsequent success. + if (result != 0 && exitCode == 0) + exitCode = result; } input = scriptReader.ReadLine(); } @@ -133,10 +140,15 @@ public static int Main(string[] args) output?.Close(); - return 0; + return exitCode; } - private static string[] SplitCommandLine(string commandLine) + /// Splits a command line into tokens, honoring double- and single-quoted segments. + /// Shared with SIL.Machine.Morphology.HermitCrab.Conformance's AdapterEngine via + /// InternalsVisibleTo so both consumers tokenize the exact same way instead of + /// maintaining a second, divergent implementation (the Conformance harness's own copy did not + /// handle single quotes). + internal static string[] SplitCommandLine(string commandLine) { var parmChars = commandLine.ToCharArray(); var inSingleQuote = false; diff --git a/src/SIL.Machine.Morphology.HermitCrab.Tool/Properties/AssemblyInfo.cs b/src/SIL.Machine.Morphology.HermitCrab.Tool/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d5bf0eece --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Tool/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using System.Runtime.CompilerServices; + +// Lets the conformance harness (SIL.Machine.Morphology.HermitCrab.Conformance, assembly name +// "hc-conformance" -- see its .csproj's ) call this project's internal +// Program.SplitCommandLine, so both share one command-line tokenizer instead of the harness +// maintaining a second, divergent copy. +[assembly: InternalsVisibleTo("hc-conformance")] diff --git a/src/SIL.Machine.Morphology.HermitCrab.Tool/SignatureFormat.cs b/src/SIL.Machine.Morphology.HermitCrab.Tool/SignatureFormat.cs new file mode 100644 index 000000000..1f1c5c0e0 --- /dev/null +++ b/src/SIL.Machine.Morphology.HermitCrab.Tool/SignatureFormat.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// The `batch` word-list loading, per-word parse, and signature algorithm, factored out of +/// so the conformance harness's self-check mode +/// (SIL.Machine.Morphology.HermitCrab.Conformance) computes byte-identical results from the +/// same code, rather than a second copy that could silently drift from the oracle. See +/// conformance/PROTOCOL.md sections 2-3 for the documented, engine-agnostic description of +/// the TSV format and this signature algorithm. +/// +public static class SignatureFormat +{ + /// Reads a word list file: one word per line, trimmed, blank lines dropped. + public static string[] LoadWords(string path) + { + return File.ReadAllLines(path).Select(w => w.Trim()).Where(w => w.Length > 0).ToArray(); + } + + /// + /// Parses one word, returning its batch-TSV status/elapsed-ms/signature triple. Only + /// is caught here (yielding ("SKIPPED", 0, "-"), per + /// conformance/PROTOCOL.md section 2) -- any other exception propagates, since that's a + /// genuine engine crash, not a normal per-word outcome. + /// + public static (string status, long elapsedMs, string signature) ParseOneWord(Morpher morpher, string word) + { + var sw = Stopwatch.StartNew(); + try + { + Word[] results = morpher.ParseWord(word, out _).ToArray(); + sw.Stop(); + return ("ok", sw.ElapsedMilliseconds, BuildSignature(results)); + } + catch (InvalidShapeException) + { + return ("SKIPPED", 0, "-"); + } + } + + /// + /// Builds the order-independent, sorted, semicolon-joined signature for a set of parse + /// results: one morph+morph|shape entry per distinct analysis, or "-" if empty. + /// + public static string BuildSignature(IEnumerable results) + { + List signatures = results + .Select(w => + string.Join("+", w.AllomorphsInMorphOrder.Select(a => a.Morpheme.Id)) + + "|" + + w.Shape.ToRegexString(w.Stratum.CharacterDefinitionTable, true) + ) + .OrderBy(s => s, StringComparer.Ordinal) + .ToList(); + return signatures.Count == 0 ? "-" : string.Join(";", signatures); + } +} diff --git a/src/SIL.Machine.Morphology.HermitCrab/Trace.cs b/src/SIL.Machine.Morphology.HermitCrab/Trace.cs index 10abc27ab..ebfd92948 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/Trace.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/Trace.cs @@ -152,5 +152,11 @@ public IHCRule Source public Word Output { get; internal set; } public FailureReason FailureReason { get; internal set; } + + /// The a node's + /// was raised against (e.g. the allomorph whose AllomorphCoOccurrenceRule/Environments check failed) -- + /// separate from because is not an + /// . + public Allomorph FailureAllomorph { get; internal set; } } } diff --git a/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs b/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs index 56a4119a5..7a0b12dd1 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/TraceManager.cs @@ -258,7 +258,12 @@ public void Successful(Language lang, Word word) public void Failed(Language lang, Word word, FailureReason reason, Allomorph allomorph, object failureObj) { ((Trace)word.CurrentTrace).Children.Add( - new Trace(TraceType.Failed, lang) { Output = word, FailureReason = reason } + new Trace(TraceType.Failed, lang) + { + Output = word, + FailureReason = reason, + FailureAllomorph = allomorph, + } ); } } diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/GuesserSignatureTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/GuesserSignatureTests.cs new file mode 100644 index 000000000..9103b1532 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/GuesserSignatureTests.cs @@ -0,0 +1,166 @@ +using NUnit.Framework; + +namespace SIL.Machine.Morphology.HermitCrab; + +// This test project does not (and should not, to avoid an unnecessary dependency) reference +// SIL.Machine.Morphology.HermitCrab.Tool, so it can't call the real SignatureFormat.BuildSignature +// directly -- this is a byte-for-byte transcription of that method (see +// src/SIL.Machine.Morphology.HermitCrab.Tool/SignatureFormat.cs), kept here ONLY so this test can +// assert on the exact string a real batch/self-check run would produce. +file static class MiniSignatureFormat +{ + public static string BuildSignature(IEnumerable results) + { + List signatures = results + .Select(w => + string.Join("+", w.AllomorphsInMorphOrder.Select(a => a.Morpheme.Id)) + + "|" + + w.Shape.ToRegexString(w.Stratum.CharacterDefinitionTable, true) + ) + .OrderBy(s => s, StringComparer.Ordinal) + .ToList(); + return signatures.Count == 0 ? "-" : string.Join(";", signatures); + } +} + +/// +/// Pins the exact rendering of a LexicalGuess (Guesser) parse in the 5-column batch +/// signature format (SignatureFormat.BuildSignature, transcribed locally below as +/// ). +/// +/// Two findings this test documents (see conformance/PROTOCOL.md's guess-stem addendum for the +/// full writeup): +/// +/// The signature's morph-chain component for a guessed root is literally the guessed +/// surface substring itself, e.g. "foo" -- Morpher.LexicalGuess (private) constructs a +/// throwaway with Id = shapeString (the matched text), and the +/// signature algorithm walks AllomorphsInMorphOrder reading each allomorph's +/// Morpheme.Id -- so a guessed root has no distinguishing marker at all in the signature +/// string; it is indistinguishable, by string alone, from a REAL lexical entry that happened to +/// have the identical id. +/// BatchCommand (the CLI `batch` subcommand every conformance adapter/oracle +/// invocation goes through) can NEVER produce a guess-stem parse: SignatureFormat.ParseOneWord +/// calls the 2-argument Morpher.ParseWord(word, out trace) overload, which hardcodes +/// guessRoot: false. No CLI command in SIL.Machine.Morphology.HermitCrab.Tool exposes the +/// 3-argument, guessRoot: true overload at all. This test therefore calls +/// directly -- the only way to exercise +/// this path in this codebase today. +/// +/// +[TestFixture] +public class GuesserSignatureTests +{ + private const string GrammarXml = """ + + + + + GuesserSignatureProbe + + n + + + Main + + f + o + s + + + + Any + + + + Main + + + plural + + + + s + + + PL + + + + + + [Any]* + + + + + + + """; + + private static string WriteTempGrammar() + { + string path = Path.Combine(Path.GetTempPath(), "hc-guesser-signature-" + Guid.NewGuid().ToString("N") + ".xml"); + File.WriteAllText(path, GrammarXml); + return path; + } + + [Test] + public void BatchCommandPath_NeverGuesses_ZeroResultsForAnUnknownRoot() + { + // "foos" has no real lexical entry for "foo" -- only the guess pattern exists. The + // 2-argument overload (what SignatureFormat.ParseOneWord, and therefore every `batch` + // invocation, actually calls) must find nothing. + string path = WriteTempGrammar(); + try + { + Language language = XmlLanguageLoader.Load(path); + var morpher = new Morpher(new TraceManager(), language); + + Word[] results = morpher.ParseWord("foos", out _).ToArray(); + + Assert.That(results, Is.Empty); + Assert.That(MiniSignatureFormat.BuildSignature(results), Is.EqualTo("-")); + } + finally + { + File.Delete(path); + } + } + + [Test] + public void GuessRootTrue_RendersGuessedStemAsItsOwnLiteralSurfaceText() + { + string path = WriteTempGrammar(); + try + { + Language language = XmlLanguageLoader.Load(path); + var morpher = new Morpher(new TraceManager(), language); + + Word[] results = morpher.ParseWord("foos", out _, guessRoot: true).ToArray(); + + Assert.That(results, Is.Not.Empty); + string signature = MiniSignatureFormat.BuildSignature(results); + // Pinned rendering: TWO guesses, because the guess pattern also matches the WHOLE + // surface string as a bare, unaffixed root (the pattern "[Any]*" is tried against every + // analysis-direction candidate, including the one where mrPlural was never unapplied at + // all) -- guessing is not restricted to "the largest/most plausible" segmentation: + // - "foo+PL|foos": PL ("-s") unapplied first, "foo" guessed as the root. + // - "foos|foos": no rule unapplied at all, the entire string "foos" guessed as the root. + // Both confirm the core finding either way: a guessed root's morph-chain component is + // the literal guessed surface substring itself ("foo", or "foos"), exactly as if a real + // LexEntry with that Id had matched -- a guess parse carries no distinguishing marker in + // the signature string itself. + Assert.That(signature, Is.EqualTo("foo+PL|foos;foos|foos")); + } + finally + { + File.Delete(path); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/MorpherTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/MorpherTests.cs index 1c32d4f1b..78d47f612 100644 --- a/tests/SIL.Machine.Morphology.HermitCrab.Tests/MorpherTests.cs +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/MorpherTests.cs @@ -1,4 +1,4 @@ -using NUnit.Framework; +using NUnit.Framework; using SIL.Machine.Annotations; using SIL.Machine.FeatureModel; using SIL.Machine.Matching; @@ -11,6 +11,22 @@ namespace SIL.Machine.Morphology.HermitCrab; [TestFixture] public class MorpherTests : HermitCrabTestBase { + // Pins the constructor defaults that PROTOCOL.md documents as the host configuration every + // conformance fixture's expected.tsv was generated under (BatchCommand/HCContext construct a + // Morpher with no overrides at all, so these constructor values ARE the fixtures' ground + // truth). A silent drift here would invalidate PROTOCOL.md without any fixture noticing, since + // no fixture exercises a non-default value. + [Test] + public void Constructor_DefaultsMatchDocumentedProtocolDefaults() + { + var morpher = new Morpher(TraceManager, Language); + + Assert.That(morpher.MaxStemCount, Is.EqualTo(2)); + Assert.That(morpher.DeletionReapplications, Is.EqualTo(0)); + Assert.That(morpher.MaxAlternatives, Is.EqualTo(0)); + Assert.That(morpher.MergeEquivalentAnalyses, Is.True); + } + [Test] public void AnalyzeWord_CanAnalyze_ReturnsCorrectAnalysis() { diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SIL.Machine.Morphology.HermitCrab.Tests.csproj b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SIL.Machine.Morphology.HermitCrab.Tests.csproj index c131a8b81..9bbc1abdd 100644 --- a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SIL.Machine.Morphology.HermitCrab.Tests.csproj +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SIL.Machine.Morphology.HermitCrab.Tests.csproj @@ -12,6 +12,8 @@ $(NoWarn);CS1591;CS1573 + + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -21,6 +23,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + @@ -36,6 +39,7 @@ + diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CSharpInventoryReaderTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CSharpInventoryReaderTests.cs new file mode 100644 index 000000000..e570dea1a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CSharpInventoryReaderTests.cs @@ -0,0 +1,1028 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class CSharpInventoryReaderTests +{ + private const string Dtd = ""; + + [Test] + public void SemanticCompilationUsesCanonicalOverloadAndDistinguishesLiteralAndDynamicElementNames() + { + const string Source = """ + using System.Xml.Linq; + using SIL.Machine.Morphology.HermitCrab; + using SIL.Machine.Rules; + using SIL.Machine.Annotations; + using System.Collections.Generic; + using System.Linq; + namespace Fixture; + public sealed class Foo { public string Element(string name) => name; } + public sealed class Loader + { + public XElement Load(string name) => new XElement("root").Element(name); + public XElement Load(int name) => new XElement("root").Element(nameof(name)); + public string Unrelated() => new Foo().Element("fake"); + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "loader.cs", + Source, + new[] { "Fixture.Loader.Load(System.String)", "Fixture.Loader.Load(System.Int32)" } + ), + } + ) + ); + + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Does.Contain("source:dynamic-xml-access/Fixture.Loader.Load(System.String)/Element#0") + ); + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Does.Contain("loader:Fixture.Loader.Load(System.Int32)/Element/name#0") + ); + var xmlParents = inventory + .Surfaces.Where(surface => surface.Kind is "xml-read" or "dynamic-xml-access") + .Select(surface => surface.Parent) + .Where(parent => parent is not null) + .ToArray(); + Assert.That(xmlParents, Does.Contain("Fixture.Loader.Load(System.String)")); + Assert.That(xmlParents, Does.Contain("Fixture.Loader.Load(System.Int32)")); + } + + [Test] + public void XmlResolutionUsesSemanticSymbolsAndFailsClosedForUnrelatedApis() + { + const string Source = """ + using Xml = System.Xml.Linq; + namespace Fixture; + public sealed class Unrelated + { + public string Element(string name) => name; + public string Elements() => string.Empty; + public string Attribute(string name) => name; + } + public sealed class Loader + { + public void Read(Xml.XElement xml, string name) + { + xml.Element("literal"); + xml.Element(nameof(name)); + xml.Element("pre" + "fix"); + xml.Element(name); + xml.Elements(); + xml.Elements("many"); + xml?.Element("conditional"); + new Unrelated().Element("fake"); + new Unrelated().Elements(); + new Unrelated().Attribute("fake"); + } + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet("fixture.dtd", Dtd, new[] { new CSharpInventoryInput("fixture.cs", Source) }) + ); + var loaderSurfaces = inventory + .Surfaces.Where(surface => surface.Parent == "Fixture.Loader.Read(System.Xml.Linq.XElement,System.String)") + .ToArray(); + Assert.That( + loaderSurfaces.Where(surface => surface.Kind == "xml-read").Select(surface => surface.Name), + Is.EquivalentTo(new[] { "literal", "name", "prefix", "many", "conditional" }) + ); + Assert.That(loaderSurfaces.Count(surface => surface.Kind == "dynamic-xml-access"), Is.EqualTo(1)); + Assert.That(loaderSurfaces.Count(surface => surface.Kind == "xml-all-elements"), Is.EqualTo(1)); + Assert.That( + loaderSurfaces.Any(surface => + surface.Parent?.StartsWith("Fixture.Unrelated", StringComparison.Ordinal) == true + ), + Is.False + ); + Assert.That(inventory.Surfaces.Any(surface => surface.Id.Contains("fake", StringComparison.Ordinal)), Is.False); + + const string Unresolved = + "namespace Fixture; public sealed class Loader { public void Read(XElement xml) { xml.Element(\"x\"); } }"; + SemanticInventory unresolved = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("unresolved.cs", Unresolved) } + ) + ); + Assert.That(unresolved.Surfaces.Count(surface => surface.Kind == "unresolved-xml-access"), Is.EqualTo(1)); + + const string UnresolvedAlias = + "using X = Missing.XElement; namespace Fixture; public sealed class Loader { public void Read(X xml) { xml.Element(\"x\"); } }"; + SemanticInventory unresolvedAlias = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("unresolved-alias.cs", UnresolvedAlias) } + ) + ); + Assert.That(unresolvedAlias.Surfaces.Count(surface => surface.Kind == "unresolved-xml-access"), Is.EqualTo(1)); + + const string UnresolvedAliasChain = + "using A = Missing.XElement; using B = A; namespace Fixture; public sealed class Loader { public void Read(B xml) { xml.Element(\"x\"); } }"; + SemanticInventory unresolvedAliasChain = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("unresolved-chain.cs", UnresolvedAliasChain) } + ) + ); + Assert.That( + unresolvedAliasChain.Surfaces.Count(surface => surface.Kind == "unresolved-xml-access"), + Is.EqualTo(1) + ); + } + + [Test] + public void RuleResolutionUsesExactSymbolsAndRejectsUnresolvedRelevantBases() + { + const string Source = """ + using RuleAlias = SIL.Machine.Morphology.HermitCrab.IHCRule; + namespace Other { public interface IHCRule { } } + namespace Fixture + { + public interface Local : RuleAlias { } + public abstract class Base : Local { } + public sealed class Concrete : Base { } + public sealed class Unrelated : Other.IHCRule { } + } + """; + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet("fixture.dtd", Dtd, new[] { new CSharpInventoryInput("fixture.cs", Source) }) + ); + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Does.Contain("model:rule/Fixture.Concrete/IHCRule") + ); + Assert.That( + inventory.Surfaces.Any(surface => surface.Id.Contains("Fixture.Unrelated", StringComparison.Ordinal)), + Is.False + ); + + const string Broken = "namespace Fixture; public sealed class Broken : IHCRule { }"; + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("broken.cs", Broken) } + ) + ) + ); + + const string BrokenAlias = "using R = Missing.IHCRule; namespace Fixture; public sealed class Broken : R { }"; + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("broken-alias.cs", BrokenAlias) } + ) + ) + ); + + const string BrokenTransitive = + "namespace Fixture; public interface Local : Missing.IHCRule { } public sealed class Broken : Local { }"; + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("broken-transitive.cs", BrokenTransitive) } + ) + ) + ); + + const string BrokenAliasChain = + "using A = Missing.IHCRule; using B = A; namespace Fixture; public sealed class Broken : B { }"; + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("broken-alias-chain.cs", BrokenAliasChain) } + ) + ) + ); + + const string ScopedUnrelatedAlias = """ + namespace Other + { + using R = Missing.IHCRule; + public sealed class Unrelated { } + } + namespace Fixture + { + public interface R { } + public sealed class Valid : R { } + } + """; + Assert.DoesNotThrow(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("scoped-alias.cs", ScopedUnrelatedAlias) } + ) + ) + ); + } + + [Test] + public void SameSignatureLocalFunctionsInDisjointScopesHaveDistinctCanonicalIds() + { + const string Source = """ + namespace Fixture; + public sealed class Loader + { + public void Run(bool value) + { + if (value) + { + void Local() { void Nested() { } Nested(); } + Local(); + } + else + { + void Local() { void Nested() { } Nested(); } + Local(); + } + } + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "fixture.cs", + Source, + new[] + { + "Fixture.Loader", + "Fixture.Loader.Run(System.Boolean)/local/Local()#0", + "Fixture.Loader.Run(System.Boolean)/local/Local()#1", + } + ), + } + ) + ); + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + Assert.That( + inventory.Surfaces.Count(surface => + surface.Kind == "decision-if" && surface.Parent == "Fixture.Loader.Run(System.Boolean)" + ), + Is.EqualTo(2), + "the internal local-function graph still gives decisions a canonical containing method" + ); + } + + [Test] + public void PartialTypeScopeCoversEveryDeclarationAndNestedExecution() + { + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "a.cs", + "namespace Fixture; public partial class Loader { public void First(bool value) { if (value) { } } }", + new[] { "Fixture.Loader" } + ), + new CSharpInventoryInput( + "b.cs", + "namespace Fixture; public partial class Loader { public void Second(bool value) { if (value) { } } }" + ), + } + ) + ); + + var parents = inventory + .Surfaces.Where(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)) + .Select(surface => surface.Parent) + .ToArray(); + Assert.That(parents, Does.Contain("Fixture.Loader.First(System.Boolean)")); + Assert.That(parents, Does.Contain("Fixture.Loader.Second(System.Boolean)")); + } + + [Test] + public void PartialMethodDeclarationsMergeToOneCanonicalCallable() + { + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "a.cs", + "namespace Fixture; public partial class C { partial void Visit(); public void Run() { Visit(); } }", + new[] { "Fixture.C.Visit()" } + ), + new CSharpInventoryInput( + "b.cs", + "namespace Fixture; public partial class C { partial void Visit() { if (true) { } } }" + ), + } + ) + ); + + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + Assert.That( + inventory.Surfaces.Any(surface => + surface.Kind.StartsWith("decision-", StringComparison.Ordinal) && surface.Parent == "Fixture.C.Visit()" + ), + Is.True + ); + } + + [Test] + public void OperatorAccessorAndLocalFunctionDecisionsUseCanonicalContainingSymbols() + { + const string Source = """ + namespace Fixture; + public sealed class C + { + private int _value; + public static C operator +(C left, C right) + { + if (left is null) return right; + return left; + } + public int Value + { + get { if (_value > 0) return _value; return 0; } + set { if (value > 0) _value = value; } + } + public void Outer(bool flag) + { + void Local() + { + if (flag) { } + } + Local(); + } + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("fixture.cs", Source, new[] { "Fixture.C" }) } + ) + ); + + var parents = inventory + .Surfaces.Where(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)) + .Select(surface => surface.Parent) + .Where(parent => parent is not null) + .ToArray(); + Assert.That(parents, Does.Contain("Fixture.C.operator-op_Addition(Fixture.C,Fixture.C)")); + Assert.That(parents, Does.Contain("Fixture.C.Value/get")); + Assert.That(parents, Does.Contain("Fixture.C.Value/set")); + Assert.That(parents, Does.Contain("Fixture.C.Outer(System.Boolean)/local/Local()")); + } + + [Test] + public void ExactCanonicalOverloadScopeFiltersDecisions() + { + const string Source = """ + namespace Fixture; + public sealed class Loader + { + public void Load(string value) { if (value.Length > 0) { } } + public void Load(int value) { if (value > 0) { } } + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("fixture.cs", Source, new[] { "Fixture.Loader.Load(System.Int32)" }) } + ) + ); + + var parents = inventory + .Surfaces.Where(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)) + .Select(surface => surface.Parent) + .Where(parent => parent is not null) + .Distinct(StringComparer.Ordinal) + .ToArray(); + Assert.That(parents, Is.EqualTo(new[] { "Fixture.Loader.Load(System.Int32)" })); + } + + [Test] + public void CanonicalCallableIdsIncludeGenericArityAndParameterKinds() + { + const string Source = """ + using System.Collections.Generic; + namespace Fixture; + public sealed class Signatures + { + public void Generic(List values) { } + public void Ref(ref int value) { } + public void Out(out int value) { value = 0; } + public void In(in int value) { } + public void Params(params int[] values) { } + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "fixture.cs", + Source, + new[] + { + "Fixture.Signatures", + "Fixture.Signatures.Generic`1(System.Collections.Generic.List`1)", + "Fixture.Signatures.Ref(ref System.Int32)", + "Fixture.Signatures.Out(out System.Int32)", + "Fixture.Signatures.In(in System.Int32)", + "Fixture.Signatures.Params(params System.Int32[])", + } + ), + } + ) + ); + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + } + + [Test] + public void RealXmlLanguageLoaderTypeScopeEnumeratesThreeLoadOverloads() + { + string sourcePath = FindRepositoryFile("src/SIL.Machine.Morphology.HermitCrab/XmlLanguageLoader.cs"); + string source = File.ReadAllText(sourcePath); + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "src/SIL.Machine.Morphology.HermitCrab/XmlLanguageLoader.cs", + source, + new[] + { + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load()", + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load(System.String)", + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load(System.String,System.Action`2)", + } + ), + } + ) + ); + + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + Assert.That(inventory.Surfaces, Has.Some.Matches(surface => surface.Kind == "xml-read")); + } + + private static string FindRepositoryFile(string relativePath) + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + string candidate = Path.Combine(directory, relativePath.Replace('/', Path.DirectorySeparatorChar)); + if (File.Exists(candidate)) + return candidate; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail($"Could not locate repository file '{relativePath}'."); + return string.Empty; + } + + [Test] + public void SourceManifestEnumeratesXmlEnumsRulesAndAuditedDecisions() + { + const string Source = """ + using System; + using System.Xml.Linq; + using SIL.Machine.Morphology.HermitCrab; + using SIL.Machine.Rules; + using SIL.Machine.Annotations; + using System.Collections.Generic; + using System.Linq; + namespace Fixture; + public enum Mode { First, Second } + public interface ILocal : IHCRule { } + public abstract class AbstractRule : ILocal { } + public sealed class ConcreteRule : AbstractRule { } + public sealed class Outer { public sealed class NestedRule : ILocal { } } + public sealed class GenericRule : IRule { } + public sealed class Loader + { + public XElement Load(XElement xml, bool test, int value) + { + XElement one = xml.Element("one"); + IEnumerable many = xml.Elements("many"); + XAttribute attr = xml.Attribute("isActive"); + XElement dynamicElement = xml.Element(GetName(value)); + if (test) + { + value = value + 1; + } + else if (value > 1) + { + value = value - 1; + } + switch (value) + { + case 0: + break; + default: return; + } + Mode selected = test ? Mode.First : Mode.Second; + try { return one; } + catch (Exception ex) when (test) { return many.FirstOrDefault(); } + for (int i = 0; i < value; i++) + { + if (i == 2) continue; + } + + return attr is null ? dynamicElement : one; + } + + private static string GetName(int value) => value.ToString(); + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "loader.cs", + Source, + new[] + { + "Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)", + "Fixture.ConcreteRule", + "Fixture.GenericRule", + "Fixture.Outer.NestedRule", + } + ), + } + ) + ); + + var ids = inventory.Surfaces.Select(surface => surface.Id).ToArray(); + Assert.That( + ids, + Does.Contain( + "loader:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/Element/one#0" + ) + ); + Assert.That( + ids, + Does.Contain( + "loader:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/Elements/many#0" + ) + ); + Assert.That( + ids, + Does.Contain( + "loader:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/Attribute/isActive#0" + ) + ); + Assert.That( + ids, + Does.Contain( + "source:dynamic-xml-access/Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/Element#1" + ) + ); + Assert.That(ids, Does.Contain("model:enum/Fixture.Mode/First")); + Assert.That(ids, Does.Contain("model:enum/Fixture.Mode/Second")); + Assert.That(ids, Does.Contain("model:rule/Fixture.ConcreteRule/IHCRule")); + Assert.That(ids, Does.Contain("model:rule/Fixture.GenericRule/IRule")); + Assert.That(ids, Does.Contain("model:rule/Fixture.Outer.NestedRule/IHCRule")); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/if/true#", + StringComparison.Ordinal + ) + ) + ); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/if/false#", + StringComparison.Ordinal + ) + ) + ); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/switch/default#", + StringComparison.Ordinal + ) + ) + ); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/conditional/true#", + StringComparison.Ordinal + ) + ) + ); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/catch-filter/false#", + StringComparison.Ordinal + ) + ) + ); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/loop/natural-exit#", + StringComparison.Ordinal + ) + ) + ); + Assert.That( + ids.Any(id => + id.StartsWith( + "decision:Fixture.Loader.Load(System.Xml.Linq.XElement,System.Boolean,System.Int32)/loop/continue#", + StringComparison.Ordinal + ) + ) + ); + } + + [Test] + public void AuditedScopesAreExactAndUnknownScopesFailClosed() + { + const string Source = """ + namespace Fixture; + public sealed class Loader + { + public void Load(bool value) + { + if (value) { } + } + } + """; + + SemanticInventory none = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet("fixture.dtd", Dtd, new[] { new CSharpInventoryInput("loader.cs", Source) }) + ); + Assert.That( + none.Surfaces.Any(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)), + Is.False + ); + + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "loader.cs", + Source, + new[] { "Fixture.Loader.Missing(System.Boolean)" } + ), + } + ) + ) + ); + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("loader.cs", Source, new[] { "Fixture.*" }) } + ) + ) + ); + foreach ( + string malformed in new[] { "Fixture.Loader.Foo[][", "Fixture.Loader.Foo]", "Fixture.Loader.Foo[abc]" } + ) + { + Assert.Throws( + () => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("loader.cs", Source, new[] { malformed }) } + ) + ), + malformed + ); + } + } + + [Test] + public void SourceOrderLineEndingsAndPathsDoNotChangeManifestOrHash() + { + const string First = "namespace Fixture {\r\n public enum Mode {\r\n A, B\r\n }\r\n}"; + const string Second = "namespace Other { public enum Mode { C } }"; + SemanticInventory left = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput("z.cs", Second), + new CSharpInventoryInput("a.cs", First.Replace("\r\n", "\n", StringComparison.Ordinal)), + } + ) + ); + SemanticInventory right = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("a.cs", First), new CSharpInventoryInput("z.cs", Second) } + ) + ); + + Assert.That(left.SourceHash, Is.EqualTo(right.SourceHash)); + Assert.That( + left.Surfaces.Select(surface => surface.Id), + Is.EqualTo(right.Surfaces.Select(surface => surface.Id)) + ); + } + + [Test] + public void DuplicatePathsAndMalformedSourcesAreControlledErrors() + { + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput("same.cs", "class A {}"), + new CSharpInventoryInput("same.cs", "class B {}"), + } + ) + ) + ); + + Assert.Throws(() => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("bad.cs", "class A { void M( { }") } + ) + ) + ); + } + + [Test] + public void RuleInheritanceAcrossSourceInputsIsEnumerated() + { + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "a.cs", + "using SIL.Machine.Morphology.HermitCrab; namespace Fixture { public sealed class CrossRule : LocalRule { } }" + ), + new CSharpInventoryInput( + "b.cs", + "using SIL.Machine.Morphology.HermitCrab; namespace Fixture { public class LocalRule : IHCRule { } }" + ), + } + ) + ); + + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Does.Contain("model:rule/Fixture.CrossRule/IHCRule") + ); + } + + // HermitCrab compiles under SINGLE_THREADED and OUTPUT_ANALYSES; a single-configuration + // census cannot see a decision that only exists when a symbol is defined. + [Test] + public void DecisionsInsideEveryConditionalConfigurationAreCensused() + { + const string Source = """ + namespace Fixture; + public sealed class Loader + { + public void Load(bool value) + #if SINGLE_THREADED + { + if (value) { } + } + #else + { + while (value) { } + } + #endif + public void Report(bool value) + { + #if OUTPUT_ANALYSES + switch (value) { default: break; } + #endif + } + } + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("loader.cs", Source, new[] { "Fixture.Loader" }) } + ) + ); + + string[] kinds = inventory + .Surfaces.Where(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)) + .Select(surface => surface.Kind) + .Distinct(StringComparer.Ordinal) + .OrderBy(kind => kind, StringComparer.Ordinal) + .ToArray(); + + Assert.That(kinds, Does.Contain("decision-loop"), "the !SINGLE_THREADED branch must be censused"); + Assert.That(kinds, Does.Contain("decision-if"), "the SINGLE_THREADED branch must be censused"); + Assert.That(kinds, Does.Contain("decision-switch"), "the OUTPUT_ANALYSES branch must be censused"); + } + + // A configuration-only decision sharing a parent and kind with an unconditional one + // shifts per-configuration ordinals, so IDs must be assigned after the union. + private const string SharedGroupSource = """ + namespace Fixture; + public sealed class Loader + { + public void Load(bool value) + { + #if SINGLE_THREADED + if (value) { } + #endif + if (!value) { } + } + } + """; + + [Test] + public void ConfigurationOnlyDecisionsDoNotDuplicateSharedOrdinalGroups() + { + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("loader.cs", SharedGroupSource, new[] { "Fixture.Loader" }) } + ) + ); + + InventorySurface[] taken = inventory + .Surfaces.Where(surface => surface.Name == "Fixture.Loader.Load(System.Boolean)/if/true") + .ToArray(); + + Assert.That(taken, Has.Length.EqualTo(2), "each source decision must yield exactly one surface"); + Assert.That( + taken + .Select(surface => surface.Id.Substring(surface.Id.LastIndexOf('-') + 1)) + .Distinct(StringComparer.Ordinal) + .Count(), + Is.EqualTo(2), + "the two decisions must keep distinct fingerprints" + ); + Assert.That( + taken.Select(surface => surface.Id.Split('#')[1].Split('-')[0]).Distinct(StringComparer.Ordinal).Count(), + Is.EqualTo(2), + "one ordinal per decision, assigned over the unioned candidate set" + ); + } + + [Test] + public void SurfacesRecordTheConfigurationsThatContainThem() + { + const string Everywhere = "OUTPUT_ANALYSES,OUTPUT_ANALYSES+SINGLE_THREADED,SINGLE_THREADED,base"; + const string SingleThreadedOnly = "OUTPUT_ANALYSES+SINGLE_THREADED,SINGLE_THREADED"; + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("loader.cs", SharedGroupSource, new[] { "Fixture.Loader" }) } + ) + ); + + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + + string[] availability = inventory + .Surfaces.Where(surface => surface.Name == "Fixture.Loader.Load(System.Boolean)/if/true") + .Select(surface => surface.Configurations) + .OrderBy(value => value, StringComparer.Ordinal) + .ToArray(); + Assert.That(availability, Is.EqualTo(new[] { SingleThreadedOnly, Everywhere })); + + InventorySurface dtdSurface = inventory.Surfaces.First(surface => + surface.Source.StartsWith("fixture.dtd", StringComparison.Ordinal) + ); + Assert.That(dtdSurface.Configurations, Is.Empty, "DTD surfaces are not configuration-scoped"); + } + + [Test] + public void RealMorpherExposesConfigurationOnlyDecisionsAndTheirConfigurations() + { + const string Relative = "src/SIL.Machine.Morphology.HermitCrab/Morpher.cs"; + // Scoped to the type rather than to one method signature. This is a real engine file, so an + // upstream rename must not be able to present itself here as a census defect. + const string Scope = "SIL.Machine.Morphology.HermitCrab.Morpher"; + const string OutputAnalysesOnly = "OUTPUT_ANALYSES,OUTPUT_ANALYSES+SINGLE_THREADED"; + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput(Relative, File.ReadAllText(FindRepositoryFile(Relative)), new[] { Scope }), + } + ) + ); + + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + + InventorySurface[] decisions = inventory + .Surfaces.Where(surface => + surface.Kind.StartsWith("decision-", StringComparison.Ordinal) + && string.Equals(surface.Configurations, OutputAnalysesOnly, StringComparison.Ordinal) + ) + .ToArray(); + Assert.That( + decisions, + Is.Not.Empty, + "a configuration-only region's decisions must still be censused, under the configurations that contain them" + ); + } + + [Test] + public void CallablesRemainInternalWhileAuditedDecisionsRemainSemanticSurfaces() + { + const string Source = """ + namespace Fixture; + public sealed class Loader + { + public void Run(bool value) + { + Helper(); + if (value) Helper(); + } + + private static void Helper() { } + } + """; + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("fixture.cs", Source, new[] { "Fixture.Loader" }) } + ) + ); + + Assert.Multiple(() => + { + Assert.That(inventory.Surfaces, Has.None.Matches(surface => surface.Kind == "callable")); + Assert.That( + inventory.Surfaces.Count(surface => + surface.Kind == "decision-if" && surface.Parent == "Fixture.Loader.Run(System.Boolean)" + ), + Is.EqualTo(2), + "the internal callable graph must still provide canonical parents and audited decision discovery" + ); + }); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CatalogBootstrapAuthorityTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CatalogBootstrapAuthorityTests.cs new file mode 100644 index 000000000..cb0706711 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CatalogBootstrapAuthorityTests.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class CatalogBootstrapAuthorityTests +{ + [Test] + public void BootstrapExposesProposalOutputButNoCanonicalCatalogWriter() + { + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("fixture.dtd", "") + ); + using var proposal = new StringWriter(); + + CatalogBootstrap.WriteProposal(proposal, inventory); + + Assert.Multiple(() => + { + Assert.That(proposal.ToString(), Is.EqualTo(CatalogBootstrap.Generate(inventory))); + Assert.That( + typeof(CatalogBootstrap) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .Select(method => method.Name), + Does.Not.Contain("Write"), + "bootstrap code must have no API that can overwrite the canonical catalog" + ); + }); + } + + [Test] + public void ProposalScopesRoundTripAsExactSortedCanonicalIds() + { + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("fixture.dtd", "") + ); + string[] scopes = + { + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load(System.String,System.Action`2)", + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load(System.Int32[])", + }; + + string proposal = CatalogBootstrap.Generate(inventory, scopes.Reverse().ToArray()); + SemanticCatalog parsed = SemanticCatalogLoader.Parse(proposal, "proposal.yaml"); + + Assert.That( + parsed.AuditedSourceScopes, + Is.EqualTo(scopes.OrderBy(scope => scope, StringComparer.Ordinal).ToArray()) + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ChildProcessHarness.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ChildProcessHarness.cs new file mode 100644 index 000000000..6faf881ef --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ChildProcessHarness.cs @@ -0,0 +1,103 @@ +#nullable enable + +using System.Diagnostics; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Runs one child process (a test-side dotnet hc-conformance.dll invocation) and guarantees its +/// lifetime is bounded by the caller's: the whole process tree is killed via +/// on cancellation, on the backstop timeout, and on any exception, not +/// only on a plain timeout. A bare Process.WaitForExit()/ReadToEnd() pair does not observe a +/// at all, which is exactly how an NUnit [CancelAfter] test leaves +/// its child running after the test itself is reported cancelled. +/// +internal static class ChildProcessHarness +{ + /// + /// Safety-net ceiling applied whenever a call site supplies no tighter backstop: bounds the + /// child even for tests with no [CancelAfter] of their own, without changing the timeout + /// behavior of call sites that already pass one. + /// + private static readonly TimeSpan DefaultBackstop = TimeSpan.FromMinutes(10); + + internal readonly record struct Result(int ExitCode, string StandardOutput, string StandardError); + + /// + /// Synchronous front end for callers (most NUnit test methods here) that are not themselves async. + /// + internal static Result Run( + ProcessStartInfo startInfo, + CancellationToken cancellationToken, + TimeSpan? backstop = null + ) => RunAsync(startInfo, cancellationToken, backstop).GetAwaiter().GetResult(); + + internal static async Task RunAsync( + ProcessStartInfo startInfo, + CancellationToken cancellationToken, + TimeSpan? backstop = null + ) + { + ArgumentNullException.ThrowIfNull(startInfo); + startInfo.UseShellExecute = false; + startInfo.RedirectStandardOutput = true; + startInfo.RedirectStandardError = true; + + using var backstopSource = new CancellationTokenSource(backstop ?? DefaultBackstop); + using CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource( + cancellationToken, + backstopSource.Token + ); + + using Process process = + Process.Start(startInfo) + ?? throw new InvalidOperationException($"Could not start child process '{startInfo.FileName}'."); + try + { + Task stdout = process.StandardOutput.ReadToEndAsync(linked.Token); + Task stderr = process.StandardError.ReadToEndAsync(linked.Token); + await process.WaitForExitAsync(linked.Token).ConfigureAwait(false); + return new Result(process.ExitCode, await stdout.ConfigureAwait(false), await stderr.ConfigureAwait(false)); + } + catch (OperationCanceledException exception) + when (backstopSource.IsCancellationRequested && !cancellationToken.IsCancellationRequested) + { + throw new TimeoutException( + $"'{startInfo.FileName} {string.Join(' ', startInfo.ArgumentList)}' exceeded its " + + $"{(backstop ?? DefaultBackstop).TotalSeconds:0}-second backstop.", + exception + ); + } + finally + { + KillTree(process); + } + } + + /// + /// Kills the whole process tree if it is still alive, and confirms the kill actually took, so a caller + /// never reports "done" while a descendant is still exiting. + /// + private static void KillTree(Process process) + { + try + { + if (process.HasExited) + { + return; + } + process.Kill(entireProcessTree: true); + if (!process.WaitForExit(5_000) || !process.HasExited) + { + throw new InvalidOperationException( + $"Child process {process.Id} did not exit within 5s of Process.Kill(entireProcessTree: true)." + ); + } + } + catch (InvalidOperationException) when (process.HasExited) + { + // Process.Kill throws "no process associated" if the child exited between the HasExited + // check and the call; that race means the tree is already gone, which is the goal anyway. + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CompilationGraphHashingTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CompilationGraphHashingTests.cs new file mode 100644 index 000000000..c5bcc62ac --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CompilationGraphHashingTests.cs @@ -0,0 +1,563 @@ +using System.Collections.Immutable; +using System.Text; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class CompilationGraphHashingTests +{ + [Test] + public void ComputesThreeIndependentLowercaseSha256Domains() + { + CompilationGraphHashInputs baseline = Inputs(); + GraphHashes hashes = CompilationGraphHashing.Compute(baseline); + + Assert.Multiple(() => + { + Assert.That(hashes.GraphInputHash, Does.Match("^[0-9a-f]{64}$")); + Assert.That(hashes.ToolchainHash, Does.Match("^[0-9a-f]{64}$")); + Assert.That(hashes.GraphHash, Does.Match("^[0-9a-f]{64}$")); + Assert.That(hashes.GraphInputHash, Is.Not.EqualTo(hashes.ToolchainHash)); + Assert.That(hashes.GraphHash, Is.Not.EqualTo(hashes.GraphInputHash)); + }); + + GraphHashes sourceChanged = CompilationGraphHashing.Compute(Inputs(sourceText: "class C { int X; }\n")); + GraphHashes toolchainChanged = CompilationGraphHashing.Compute(Inputs(roslynText: "roslyn-v2")); + GraphHashes edgeChanged = CompilationGraphHashing.Compute(Inputs(edgeTarget: "other-owned-project")); + + Assert.Multiple(() => + { + Assert.That(sourceChanged.GraphInputHash, Is.Not.EqualTo(hashes.GraphInputHash)); + Assert.That(sourceChanged.ToolchainHash, Is.EqualTo(hashes.ToolchainHash)); + Assert.That(toolchainChanged.ToolchainHash, Is.Not.EqualTo(hashes.ToolchainHash)); + Assert.That(toolchainChanged.GraphInputHash, Is.EqualTo(hashes.GraphInputHash)); + Assert.That(edgeChanged.GraphHash, Is.Not.EqualTo(hashes.GraphHash)); + }); + } + + [Test] + public void TextEolAndPhysicalRootRelocationDoNotChangeHashes() + { + GraphHashFile windowsSource = File("repo:/src/C.cs", "class C {\r\n}\r\n", GraphHashFileKind.Text); + GraphHashFile linuxSource = File("repo:/src/C.cs", "class C {\n}\n", GraphHashFileKind.Text); + + GraphHashes windows = CompilationGraphHashing.Compute(Inputs(source: windowsSource)); + GraphHashes linux = CompilationGraphHashing.Compute(Inputs(source: linuxSource)); + + Assert.That(windows, Is.EqualTo(linux)); + Assert.Multiple(() => + { + Assert.That( + LogicalPathTokens.FromAbsolute( + @"C:\checkout\src\C.cs", + new LogicalPathRoots(@"C:\checkout", @"C:\sdk", @"C:\nuget", @"C:\generated") + ), + Is.EqualTo("repo:/src/C.cs") + ); + Assert.That( + LogicalPathTokens.FromAbsolute( + "/mnt/checkout/src/C.cs", + new LogicalPathRoots("/mnt/checkout", "/opt/sdk", "/home/me/.nuget", "/tmp/generated") + ), + Is.EqualTo("repo:/src/C.cs") + ); + }); + } + + [Test] + public void AncestorEditorConfigFilesAreAdmittedWithALocationIndependentLogicalIdentity() + { + var roots = new LogicalPathRoots( + @"C:\outer\machine\worktrees\squashed", + @"C:\sdk", + @"C:\nuget", + @"C:\generated" + ); + + string logical = LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig( + @"C:\outer\machine\.editorconfig", + roots + ); + + string unixShaped = LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig( + "/outer/machine/.editorconfig", + new LogicalPathRoots("/outer/machine/worktrees/squashed", "/opt/sdk", "/home/me/.nuget", "/tmp/generated") + ); + + Assert.Multiple(() => + { + Assert.That(logical, Is.EqualTo("ancestor-editorconfig:/2")); + Assert.That(LogicalPathTokens.IsLogicalPath(logical), Is.True); + Assert.That(unixShaped, Is.EqualTo(logical)); + }); + } + + [Test] + public void AncestorEditorConfigIdentityAndHashSurviveRelocationOfBothTheOuterCheckoutAndTheWorktree() + { + var hereRoots = new LogicalPathRoots( + @"C:\Users\dev1\machine\.worktrees\squashed", + @"C:\sdk", + @"C:\nuget", + @"C:\generated" + ); + var thereRoots = new LogicalPathRoots( + @"D:\ci\agent7\machine\.worktrees\squashed", + @"D:\sdk", + @"D:\nuget", + @"D:\generated" + ); + + string hereLogical = LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig( + @"C:\Users\dev1\machine\.editorconfig", + hereRoots + ); + string thereLogical = LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig( + @"D:\ci\agent7\machine\.editorconfig", + thereRoots + ); + + Assert.That(hereLogical, Is.EqualTo(thereLogical)); + + GraphHashFile hereFile = File(hereLogical, "root = true\n", GraphHashFileKind.Text); + GraphHashFile thereFile = File(thereLogical, "root = true\n", GraphHashFileKind.Text); + Assert.That( + CompilationGraphHashing.Compute(InputsWithEditorConfig(hereFile)), + Is.EqualTo(CompilationGraphHashing.Compute(InputsWithEditorConfig(thereFile))) + ); + } + + [Test] + public void FromAbsoluteAdmittingAncestorEditorConfigStillFailsClosedOutsideTheEditorConfigCase() + { + var roots = new LogicalPathRoots( + @"C:\outer\machine\worktrees\squashed", + @"C:\sdk", + @"C:\nuget", + @"C:\generated" + ); + + Assert.That( + () => + LogicalPathTokens.FromAbsoluteAdmittingAncestorEditorConfig( + @"C:\outer\machine\Directory.Build.props", + roots + ), + Throws.TypeOf() + ); + } + + [Test] + public void CompilerOrderIsSemanticButSetOrderIsNot() + { + CompilationGraphHashInputs baseline = Inputs( + arguments: new[] { new OrderedHashValue(0, "/define:A"), new OrderedHashValue(1, "/nullable:enable") }, + profileSymbols: new[] { "A", "B" } + ); + CompilationGraphHashInputs reorderedArguments = Inputs( + arguments: new[] { new OrderedHashValue(0, "/nullable:enable"), new OrderedHashValue(1, "/define:A") }, + profileSymbols: new[] { "A", "B" } + ); + CompilationGraphHashInputs reorderedSet = Inputs( + arguments: new[] { new OrderedHashValue(0, "/define:A"), new OrderedHashValue(1, "/nullable:enable") }, + profileSymbols: new[] { "B", "A" } + ); + + Assert.That( + CompilationGraphHashing.Compute(reorderedArguments).GraphInputHash, + Is.Not.EqualTo(CompilationGraphHashing.Compute(baseline).GraphInputHash) + ); + Assert.That( + CompilationGraphHashing.Compute(reorderedSet), + Is.EqualTo(CompilationGraphHashing.Compute(baseline)) + ); + } + + [Test] + public void LogicalPathsRejectUnknownRootsAndCaseCollisions() + { + var roots = new LogicalPathRoots(@"C:\repo", @"C:\sdk", @"C:\nuget", @"C:\generated"); + + Assert.That( + () => LogicalPathTokens.FromAbsolute(@"C:\elsewhere\file.cs", roots), + Throws.TypeOf() + ); + Assert.That( + () => LogicalPathTokens.ValidateUnique(new[] { "repo:/src/C.cs", "repo:/src/c.cs" }), + Throws.TypeOf() + ); + } + + [Test] + public void ExactLogicalFileReuseAcrossProfilesIsAllowedButCaseVariantsAreRejected() + { + GraphHashFile source = File("repo:/src/C.cs", "class C { }\n", GraphHashFileKind.Text); + NodeHashInput baseNode = Node("base", source); + NodeHashInput alternateNode = Node("single-threaded", source); + + Assert.DoesNotThrow(() => + new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/src/hc.csproj", "netstandard2.0") }, + new[] + { + new ProfileHashInput("base", Array.Empty()), + new ProfileHashInput("single-threaded", new[] { "SINGLE_THREADED" }), + }, + new[] { baseNode, alternateNode }, + Array.Empty(), + Toolchain(), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ) + ); + + GraphHashFile caseVariant = File("repo:/src/c.cs", "class C { }\n", GraphHashFileKind.Text); + Assert.That( + () => + new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/src/hc.csproj", "netstandard2.0") }, + new[] + { + new ProfileHashInput("base", Array.Empty()), + new ProfileHashInput("single-threaded", new[] { "SINGLE_THREADED" }), + }, + new[] { baseNode, Node("single-threaded", caseVariant) }, + Array.Empty(), + Toolchain(), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ), + Throws.TypeOf() + ); + } + + [Test] + public void OrderedInputsRequireUniqueContiguousOrdinals() + { + GraphHashFile source = File("repo:/src/C.cs", "class C { }\n", GraphHashFileKind.Text); + Assert.That( + () => Node("base", source, arguments: new[] { new OrderedHashValue(0, "a"), new OrderedHashValue(0, "b") }), + Throws.TypeOf() + ); + Assert.That( + () => Node("base", source, arguments: new[] { new OrderedHashValue(0, "a"), new OrderedHashValue(2, "b") }), + Throws.TypeOf() + ); + Assert.That( + () => + new NodeHashInput( + new RepositoryGraphNodeKey("hc", "netstandard2.0", "base"), + new Dictionary(), + Array.Empty(), + new[] { new OrderedGraphHashFile(1, source) }, + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty() + ), + Throws.TypeOf() + ); + } + + [Test] + public void OverlappingPhysicalRootsAreRejectedAsAmbiguous() + { + Assert.That( + () => new LogicalPathRoots(@"C:\repo", @"C:\sdk", @"C:\nuget", @"C:\repo\obj\generated"), + Throws.TypeOf() + ); + } + + [Test] + public void TraversalSegmentsAreRejectedAndJsonStringEolIsNormalized() + { + var roots = new LogicalPathRoots(@"C:\repo", @"C:\sdk", @"C:\nuget", @"C:\generated"); + Assert.That( + () => LogicalPathTokens.FromAbsolute(@"C:\repo\sub\..\C.cs", roots), + Throws.TypeOf() + ); + + GraphHashFile windowsJson = File( + "repo:/obj/project.assets.json", + "{\"text\":\"a\\r\\nb\"}", + GraphHashFileKind.Json + ); + GraphHashFile linuxJson = File("repo:/obj/project.assets.json", "{\"text\":\"a\\nb\"}", GraphHashFileKind.Json); + Assert.That( + CompilationGraphHashing.Compute(InputsWithAsset(windowsJson)), + Is.EqualTo(CompilationGraphHashing.Compute(InputsWithAsset(linuxJson))) + ); + } + + [Test] + public void ProjectPathsRequireLogicalTokensAndShareTheGlobalCollisionDomain() + { + Assert.That( + () => new ProjectHashInput("hc", @"C:\repo\src\hc.csproj", "netstandard2.0"), + Throws.TypeOf() + ); + Assert.That( + () => new ProjectHashInput("hc", "other:/src/hc.csproj", "netstandard2.0"), + Throws.TypeOf() + ); + + Assert.That( + () => + new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/SRC/C.cs", "netstandard2.0") }, + new[] { new ProfileHashInput("base", Array.Empty()) }, + new[] { Node("base", File("repo:/src/C.cs", "class C { }\n", GraphHashFileKind.Text)) }, + Array.Empty(), + Toolchain(), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ), + Throws.TypeOf() + ); + + Assert.DoesNotThrow(() => + new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/src/hc.csproj", "netstandard2.0") }, + new[] { new ProfileHashInput("base", Array.Empty()) }, + new[] + { + new NodeHashInput( + new RepositoryGraphNodeKey("hc", "netstandard2.0", "base"), + new Dictionary(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + new[] { File("repo:/src/hc.csproj", "\n", GraphHashFileKind.Text) } + ), + }, + Array.Empty(), + Toolchain(), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ) + ); + } + + [Test] + public void FilesMapCorrectlyWhenAnAdmittedRootIsAFileSystemRoot() + { + Assert.That( + LogicalPathTokens.FromAbsolute( + @"C:\repo\file.cs", + new LogicalPathRoots(@"C:\", @"D:\sdk", @"D:\nuget", @"D:\generated") + ), + Is.EqualTo("repo:/repo/file.cs") + ); + Assert.That( + LogicalPathTokens.FromAbsolute("/repo/file.cs", new LogicalPathRoots("/", "/sdk", "/nuget", "/generated")), + Is.EqualTo("repo:/repo/file.cs") + ); + } + + [Test] + public void HashModelsRejectNullElementsDuplicateIdentitiesAndAmbiguousNodeSegments() + { + Assert.That(() => new ProfileHashInput("base", new string[] { null! }), Throws.ArgumentException); + Assert.That( + () => + new ToolchainHashInput("sdk", "msbuild", "roslyn", "compiler", "loader", new GraphHashFile[] { null! }), + Throws.ArgumentException + ); + + CompilationGraphHashInputs baseline = Inputs(); + Assert.That( + () => + new CompilationGraphHashInputs( + baseline.SchemaVersion, + baseline.Projects.Concat(baseline.Projects).ToArray(), + baseline.Profiles, + baseline.Nodes, + baseline.Edges, + baseline.Toolchain, + baseline.CaptureTarget, + baseline.LockFile + ), + Throws.TypeOf() + ); + Assert.That( + () => + new CompilationGraphHashInputs( + baseline.SchemaVersion, + baseline.Projects, + baseline.Profiles, + baseline.Nodes.Concat(baseline.Nodes).ToArray(), + baseline.Edges, + baseline.Toolchain, + baseline.CaptureTarget, + baseline.LockFile + ), + Throws.TypeOf() + ); + Assert.That(() => new RepositoryGraphNodeKey("hc/other", "netstandard2.0", "base"), Throws.ArgumentException); + } + + [Test] + public void CanonicalJsonRejectsDuplicatePropertiesAndNormalizesEquivalentNumbers() + { + Assert.That( + () => CanonicalJson.NormalizeJson(Encoding.UTF8.GetBytes("{\"a\":1,\"a\":2}")), + Throws.TypeOf() + ); + Assert.That( + CanonicalJson.NormalizeJson(Encoding.UTF8.GetBytes("{\"n\":1}")), + Is.EqualTo(CanonicalJson.NormalizeJson(Encoding.UTF8.GetBytes("{\"n\":1.0}"))) + ); + } + + [Test] + public void NullLogicalPathsAndDuplicateFilesystemRootsFailClosed() + { + Assert.That( + () => new GraphHashFile(null!, ImmutableArray.Empty, GraphHashFileKind.Binary), + Throws.ArgumentException + ); + Assert.That(() => new ProjectHashInput("hc", null!, "netstandard2.0"), Throws.ArgumentException); + Assert.That( + () => new LogicalPathRoots("/", "/", "/nuget", "/generated"), + Throws.TypeOf() + ); + Assert.That( + () => new LogicalPathRoots(@"C:\", @"c:\", @"D:\nuget", @"D:\generated"), + Throws.TypeOf() + ); + } + + private static CompilationGraphHashInputs Inputs( + string sourceText = "class C { }\n", + string roslynText = "roslyn-v1", + string edgeTarget = "machine", + GraphHashFile? source = null, + IReadOnlyList? arguments = null, + IReadOnlyList? profileSymbols = null + ) + { + GraphHashFile actualSource = source ?? File("repo:/src/C.cs", sourceText, GraphHashFileKind.Text); + var key = new RepositoryGraphNodeKey("hc", "netstandard2.0", "base"); + return new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/src/hc.csproj", "netstandard2.0") }, + new[] { new ProfileHashInput("base", profileSymbols ?? Array.Empty()) }, + new[] { Node("base", actualSource, arguments) }, + new[] { new RepositoryProjectEdge("hc", edgeTarget) }, + Toolchain(roslynText), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ); + } + + private static NodeHashInput Node( + string profileId, + GraphHashFile source, + IReadOnlyList? arguments = null + ) => + new( + new RepositoryGraphNodeKey("hc", "netstandard2.0", profileId), + new Dictionary { ["nullable"] = "enable" }, + arguments ?? new[] { new OrderedHashValue(0, "/nullable:enable") }, + new[] { new OrderedGraphHashFile(0, source) }, + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + new[] { File("repo:/obj/project.assets.json", "{}\n", GraphHashFileKind.Json) }, + new[] { File("repo:/Directory.Build.props", "\n", GraphHashFileKind.Text) } + ); + + private static ToolchainHashInput Toolchain(string roslynText = "roslyn-v1") => + new( + "10.0.303", + "18.0.0", + "Microsoft.CodeAnalysis.CSharp, Version=5.6.0.0", + "csc 5.6.0", + "hc-conformance-loader/v1", + new[] { File("sdk:/Roslyn/Microsoft.CodeAnalysis.CSharp.dll", roslynText, GraphHashFileKind.Binary) } + ); + + private static CompilationGraphHashInputs InputsWithAsset(GraphHashFile asset) => + new( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/src/hc.csproj", "netstandard2.0") }, + new[] { new ProfileHashInput("base", Array.Empty()) }, + new[] + { + new NodeHashInput( + new RepositoryGraphNodeKey("hc", "netstandard2.0", "base"), + new Dictionary(), + Array.Empty(), + new[] + { + new OrderedGraphHashFile(0, File("repo:/src/C.cs", "class C { }\n", GraphHashFileKind.Text)), + }, + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + new[] { asset }, + Array.Empty() + ), + }, + Array.Empty(), + Toolchain(), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ); + + private static CompilationGraphHashInputs InputsWithEditorConfig(GraphHashFile editorConfig) => + new( + "hc-compilation-graph/v1", + new[] { new ProjectHashInput("hc", "repo:/src/hc.csproj", "netstandard2.0") }, + new[] { new ProfileHashInput("base", Array.Empty()) }, + new[] + { + new NodeHashInput( + new RepositoryGraphNodeKey("hc", "netstandard2.0", "base"), + new Dictionary(), + Array.Empty(), + new[] + { + new OrderedGraphHashFile(0, File("repo:/src/C.cs", "class C { }\n", GraphHashFileKind.Text)), + }, + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + new[] { editorConfig }, + Array.Empty(), + Array.Empty(), + Array.Empty() + ), + }, + Array.Empty(), + Toolchain(), + File("repo:/eng/HcSemanticCompilerInputs.targets", "\n", GraphHashFileKind.Text), + new OptionalGraphHashFile(false, null) + ); + + private static GraphHashFile File(string path, string content, GraphHashFileKind kind) => + new(path, ImmutableArray.CreateRange(Encoding.UTF8.GetBytes(content)), kind); +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConformanceFixtureGateTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConformanceFixtureGateTests.cs new file mode 100644 index 000000000..526dd9619 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConformanceFixtureGateTests.cs @@ -0,0 +1,170 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Runs every conformance fixture inside the ordinary test suite. Before this existed the fixtures +/// were reachable only through the standalone hc-conformance CLI, which no CI step invoked, so a +/// fixture could regress without any build failing. The coverage ledger is only meaningful if the +/// grammars it measures are actually executed. +/// +[TestFixture] +public sealed class ConformanceFixtureGateTests +{ + /// Guards against the suite silently shrinking to nothing and still reporting green. + private const int MinimumFixtures = 25; + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static List Discover() => Fixture.DiscoverAll(Path.Combine(RepositoryRoot(), "conformance")); + + [Test] + public void EveryConformanceFixturePassesSelfCheck() + { + List fixtures = Discover(); + Assert.That(fixtures, Has.Count.GreaterThanOrEqualTo(MinimumFixtures)); + + var engine = new SelfCheckEngine(null); + RunReport report = Runner.RunSelfCheck( + fixtures, + includePathological: false, + engine.Capabilities, + propose: false, + TextWriter.Null + ); + + string[] failures = report + .Results.Where(result => result.Outcome == FixtureOutcome.Failed) + .Select(result => $"{result.FixtureId}: {result.Reason}") + .OrderBy(line => line, StringComparer.Ordinal) + .ToArray(); + + Assert.That(failures, Is.Empty, $"conformance fixtures failed:\n {string.Join("\n ", failures)}"); + Assert.That( + report.Passed, + Is.GreaterThanOrEqualTo(MinimumFixtures), + "the run must actually execute fixtures, not skip them all" + ); + } + + // A fixture whose grammar the coverage gate reads but which never runs would let the ledger + // credit surfaces nothing executes. + [Test] + public void EveryGrammarTheCoverageGateReadsBelongsToADiscoveredFixture() + { + string root = RepositoryRoot(); + var discovered = Discover() + .Select(fixture => Path.GetFullPath(fixture.GrammarPath)) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + + string[] unrun = GrammarCoverageGate + .DiscoverGrammars(root) + .Select(item => Path.GetFullPath(item.GrammarPath)) + .Where(path => !discovered.Contains(path)) + .OrderBy(path => path, StringComparer.Ordinal) + .ToArray(); + + Assert.That(unrun, Is.Empty, $"these grammars feed coverage but are not run:\n {string.Join("\n ", unrun)}"); + } + + // coverage.csv and rules.csv are only written by an explicit --coverage-report run, and + // parity-check.py gates on them. Adding a construct to constructs.txt without regenerating them + // left that gate red for two commits. + [Test] + public void CheckedInCoverageTablesAreUpToDate() + { + string root = RepositoryRoot(); + string temp = Path.Combine(Path.GetTempPath(), $"hc-coverage-{Guid.NewGuid():N}"); + Directory.CreateDirectory(temp); + try + { + string coverage = Path.Combine(temp, "coverage.csv"); + string rules = Path.Combine(temp, "rules.csv"); + CoverageReport.WriteCsvs(Discover(), coverage, rules); + + Assert.Multiple(() => + { + Assert.That( + File.ReadAllText(coverage).ReplaceLineEndings("\n"), + Is.EqualTo( + File.ReadAllText(Path.Combine(root, "conformance", "coverage.csv")).ReplaceLineEndings("\n") + ), + "regenerate with: hc-conformance --fixtures conformance --coverage-report" + ); + Assert.That( + File.ReadAllText(rules).ReplaceLineEndings("\n"), + Is.EqualTo( + File.ReadAllText(Path.Combine(root, "conformance", "rules.csv")).ReplaceLineEndings("\n") + ), + "regenerate with: hc-conformance --fixtures conformance --coverage-report" + ); + }); + } + finally + { + Directory.Delete(temp, recursive: true); + } + } + + // Every construct a fixture claims must be a real line in the checklist, and every checklist line + // must be claimed. parity-check.py enforces the second half; nothing enforced the first. + [Test] + public void EveryExercisedConstructIsDeclaredInTheChecklist() + { + string root = RepositoryRoot(); + var declared = CoverageReport + .LoadConstructChecklist(Path.Combine(root, "conformance", "constructs.txt")) + .ToHashSet(StringComparer.Ordinal); + + string[] unknown = Discover() + .SelectMany(fixture => fixture.Words.Words) + .SelectMany(word => word.Exercises.Concat(word.Parses.SelectMany(parse => parse.Exercises))) + .Distinct(StringComparer.Ordinal) + .Where(construct => !declared.Contains(construct)) + .OrderBy(construct => construct, StringComparer.Ordinal) + .ToArray(); + + Assert.That( + unknown, + Is.Empty, + $"add these to constructs.txt or fix the tag:\n {string.Join("\n ", unknown)}" + ); + } + + // WordsYamlLoader already requires at least one word and a parse unless the word is + // expect_fail/expect_skip, so asserting that is a tautology. What it does NOT guarantee is that any + // word attributes its parse to a rule, which is the only thing trace evidence can be built from. + [Test] + public void FixturesWithRulesAttributeAtLeastOneParseToThem() + { + var silent = new List(); + foreach (Fixture fixture in Discover()) + { + bool declaresRules = File.ReadAllText(fixture.GrammarPath) + .Contains("MorphologicalRule id=", StringComparison.Ordinal); + bool attributesAny = fixture.Words.Words.Any(word => word.Parses.Any(parse => parse.Rules.Count > 0)); + if (declaresRules && !attributesAny) + silent.Add(fixture.Id); + } + + Assert.That( + silent, + Is.Empty, + "these declare morphological rules but no parse names one, so nothing they contain can be trace-verified" + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConformanceManifestTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConformanceManifestTests.cs new file mode 100644 index 000000000..0017212b0 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConformanceManifestTests.cs @@ -0,0 +1,306 @@ +using System.Globalization; +using System.Text.Json; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class ConformanceManifestTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static ConformanceManifest Manifest() => ConformanceManifestGenerator.Generate(RepositoryRoot()); + + private static string Absolute(string relative) => + Path.Combine(RepositoryRoot(), relative.Replace('/', Path.DirectorySeparatorChar)); + + [Test] + public void FormatIdentifiersAreExact() + { + ConformanceManifest manifest = Manifest(); + + Assert.Multiple(() => + { + Assert.That(manifest.FormatVersion, Is.EqualTo("hc-conformance-manifest/v1")); + Assert.That(manifest.WordsAuthoringFormatVersion, Is.EqualTo("hc-conformance-words/v1")); + Assert.That(manifest.GrammarFormatVersion, Is.EqualTo("sil-machine-hermit-crab-input-xml/v1")); + Assert.That(manifest.SourceHash, Has.Length.EqualTo(64)); + Assert.That(manifest.DtdSha256, Has.Length.EqualTo(64)); + Assert.That(manifest.Fixtures, Is.Not.Empty); + }); + } + + // A consumer receives conformance/ alone, so every path the manifest names has to resolve + // inside it. + [Test] + public void EveryPathTheManifestNamesLivesUnderConformance() + { + ConformanceManifest manifest = Manifest(); + + Assert.Multiple(() => + { + Assert.That(manifest.DtdPath, Does.StartWith("conformance/")); + Assert.That(File.Exists(Absolute(manifest.DtdPath)), Is.True, manifest.DtdPath); + foreach (ManifestFixture fixture in manifest.Fixtures) + { + Assert.That(fixture.GrammarPath, Is.EqualTo($"conformance/{fixture.FixtureId}/grammar.xml")); + Assert.That(fixture.WordsPath, Is.EqualTo($"conformance/{fixture.FixtureId}/words.yaml")); + Assert.That(File.Exists(Absolute(fixture.GrammarPath)), Is.True, fixture.GrammarPath); + Assert.That(File.Exists(Absolute(fixture.WordsPath)), Is.True, fixture.WordsPath); + Assert.That(fixture.GrammarPath, Does.Not.Contain("\\")); + Assert.That(fixture.GrammarSha256, Has.Length.EqualTo(64)); + Assert.That(fixture.WordsSha256, Has.Length.EqualTo(64)); + Assert.That(fixture.DisplayLanguage, Is.Not.Empty, fixture.FixtureId); + Assert.That(fixture.CaseCount, Is.GreaterThan(0), fixture.FixtureId); + Assert.That( + fixture.Category, + Is.EqualTo( + fixture.FixtureId.StartsWith("languages/", StringComparison.Ordinal) ? "language" : "edge-case" + ) + ); + } + }); + } + + // The library reads its DTD as an embedded resource and cannot move; the published copy is what + // a consumer receives. They must not drift. + [Test] + public void PublishedDtdMatchesTheLibraryResource() + { + Assert.That( + File.ReadAllText(Absolute(GrammarCoverageGate.DtdRelativePath)).ReplaceLineEndings("\n"), + Is.EqualTo(File.ReadAllText(Absolute(GrammarCoverageGate.LibraryDtdRelativePath)).ReplaceLineEndings("\n")), + $"copy {GrammarCoverageGate.LibraryDtdRelativePath} over {GrammarCoverageGate.DtdRelativePath}" + ); + } + + [Test] + public void CrashFixturesDeclareExactlyOneCase() + { + Assert.Multiple(() => + { + foreach (ManifestFixture fixture in Manifest().Fixtures.Where(item => item.ExpectedCrash)) + Assert.That(fixture.CaseCount, Is.EqualTo(1), fixture.FixtureId); + }); + } + + // A regenerated manifest must be byte-identical, or `--check-manifest` cannot detect drift. + [Test] + public void GenerationIsDeterministicAndCanonical() + { + string first = ManifestJson.Serialize(Manifest()); + string second = ManifestJson.Serialize(Manifest()); + + Assert.That(second, Is.EqualTo(first)); + Assert.That(() => JsonDocument.Parse(first), Throws.Nothing); + } + + [Test] + public void TheCheckedInManifestMatchesRegeneration() + { + string path = Absolute("conformance/generated/hc-conformance-manifest.v1.json"); + + Assert.That(File.Exists(path), Is.True, "regenerate with: hc-conformance --generate-manifest"); + Assert.That( + File.ReadAllText(path).ReplaceLineEndings("\n"), + Is.EqualTo(ManifestJson.Serialize(Manifest()) + "\n"), + "regenerate with: hc-conformance --generate-manifest" + ); + } + + [Test] + public void TheManifestValidatesAgainstItsPublishedSchema() + { + Json.Schema.JsonSchema schema = Json.Schema.JsonSchema.FromFile( + Absolute("conformance/schema/conformance-manifest.schema.json") + ); + using JsonDocument document = JsonDocument.Parse(ManifestJson.Serialize(Manifest())); + + Json.Schema.EvaluationResults results = schema.Evaluate( + document.RootElement, + new Json.Schema.EvaluationOptions { OutputFormat = Json.Schema.OutputFormat.List } + ); + + IEnumerable failures = (results.Details ?? new List()) + .Where(detail => detail.Errors is { Count: > 0 }) + .SelectMany(detail => detail.Errors!.Select(error => $"{detail.InstanceLocation}: {error.Value}")) + .Take(20); + + Assert.That(results.IsValid, Is.True, string.Join(Environment.NewLine, failures)); + } + + // words.yaml is the canonical authored format, so the published schema has to describe every + // file the loader already accepts. + [Test] + public void EveryWordsFileValidatesAgainstThePublishedSchema() + { + string schema = Absolute(WordsSchemaValidation.SchemaRelativePath); + + Assert.Multiple(() => + { + foreach (ManifestFixture fixture in Manifest().Fixtures) + { + IReadOnlyList violations = WordsSchemaValidation.Validate(Absolute(fixture.WordsPath), schema); + Assert.That(violations, Is.Empty, $"{fixture.FixtureId}: {string.Join(" | ", violations.Take(6))}"); + } + }); + } + + [TestCase("anchors", "language: X\nwords: &a []\n")] + [TestCase("merge keys", "language: X\nwords:\n - <<: {word: a}\n note: n\n")] + public void PlainYamlOnlyIsEnforced(string _, string yaml) + { + string schema = Absolute(WordsSchemaValidation.SchemaRelativePath); + string path = Path.Combine(Path.GetTempPath(), $"hc-words-{Guid.NewGuid():N}.yaml"); + File.WriteAllText(path, yaml); + try + { + Assert.That(() => WordsSchemaValidation.Validate(path, schema), Throws.TypeOf()); + } + finally + { + File.Delete(path); + } + } + + /// A minimal repository carrying one real fixture, for mutation tests. + private static string CreateMiniRepository(string fixtureId) + { + string source = RepositoryRoot(); + string root = Path.Combine(Path.GetTempPath(), $"hc-manifest-repo-{Guid.NewGuid():N}"); + + void Copy(string relative) + { + string target = Path.Combine(root, relative.Replace('/', Path.DirectorySeparatorChar)); + Directory.CreateDirectory(Path.GetDirectoryName(target)!); + File.Copy(Path.Combine(source, relative.Replace('/', Path.DirectorySeparatorChar)), target); + } + + Copy(GrammarCoverageGate.DtdRelativePath); + Copy("conformance/constructs.txt"); + Copy("conformance/parity-check.py"); + Copy("conformance/schema/words.schema.json"); + Copy("conformance/schema/conformance-manifest.schema.json"); + Copy($"conformance/{fixtureId}/grammar.xml"); + Copy($"conformance/{fixtureId}/words.yaml"); + return root; + } + + // Every input the manifest rests on must move its sourceHash, or a stale manifest cannot be + // told from a current one. + [TestCase("conformance/{0}/grammar.xml")] + [TestCase("conformance/{0}/words.yaml")] + [TestCase("conformance/constructs.txt")] + [TestCase("conformance/parity-check.py")] + [TestCase("conformance/schema/words.schema.json")] + public void EverySourceFileMovesTheSourceHash(string relativeTemplate) + { + const string FixtureId = "edge-cases/strrep-identity"; + string root = CreateMiniRepository(FixtureId); + try + { + string before = ConformanceManifestGenerator.Generate(root).SourceHash; + string target = Path.Combine( + root, + string.Format(CultureInfo.InvariantCulture, relativeTemplate, FixtureId) + .Replace('/', Path.DirectorySeparatorChar) + ); + File.AppendAllText(target, "\n# drift\n"); + + Assert.That( + ConformanceManifestGenerator.Generate(root).SourceHash, + Is.Not.EqualTo(before), + relativeTemplate + ); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + + // Fixture identity comes from the two declared roots only; a stray directory elsewhere under + // conformance/ must not be able to present itself as a fixture. + [Test] + public void DiscoveryAcceptsOnlyTheTwoDeclaredFixtureRoots() + { + const string FixtureId = "edge-cases/strrep-identity"; + string root = CreateMiniRepository(FixtureId); + try + { + string legacy = Path.Combine(root, "conformance", "allomorphy", "strrep-identity"); + Directory.CreateDirectory(legacy); + foreach (string name in new[] { "grammar.xml", "words.yaml" }) + { + File.Copy( + Path.Combine(root, "conformance", "edge-cases", "strrep-identity", name), + Path.Combine(legacy, name) + ); + } + + Assert.That( + ConformanceManifestGenerator.Generate(root).Fixtures.Select(fixture => fixture.FixtureId), + Is.EqualTo(new[] { FixtureId }) + ); + } + finally + { + Directory.Delete(root, recursive: true); + } + } + + [Test] + public void EveryGrammarValidatesAgainstThePublishedDtd() + { + string dtd = Absolute(GrammarCoverageGate.DtdRelativePath); + + Assert.Multiple(() => + { + foreach (ManifestFixture fixture in Manifest().Fixtures) + { + Assert.That( + GrammarValidation.Validate(Absolute(fixture.GrammarPath), dtd), + Is.Empty, + $"{fixture.FixtureId}: grammar must validate against the published DTD" + ); + } + }); + } + + [Test] + public void TheResolverAdmitsOnlyThePinnedDtdSystemIdentifier() + { + string dtd = Absolute(GrammarCoverageGate.DtdRelativePath); + string directory = Path.Combine(Path.GetTempPath(), $"hc-manifest-{Guid.NewGuid():N}"); + Directory.CreateDirectory(directory); + try + { + string hostile = Path.Combine(directory, "grammar.xml"); + File.WriteAllText( + hostile, + "\n" + + "\n" + + "\n" + ); + + Assert.That(() => GrammarValidation.Validate(hostile, dtd), Throws.TypeOf()); + } + finally + { + Directory.Delete(directory, recursive: true); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConstructClaimCorroborationTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConstructClaimCorroborationTests.cs new file mode 100644 index 000000000..38e87aaa5 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ConstructClaimCorroborationTests.cs @@ -0,0 +1,108 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class ConstructClaimCorroborationTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // 444 total claims matches conformance/coverage.csv's own row count (the same (fixture, word, + // signature, construct) enumeration CoverageReport.WriteCsvs already produces). Of those, 185 map + // to a real DTD identifier this fixture's grammar.xml actually contains (Confirmed), 244 name a + // construct whose text ConstructClaimCorroboration.MapConstructsToDtdTokens cannot mechanically + // resolve to any DTD identifier at all (Unmapped -- most constructs are prose, not identifiers, + // so this is the expected majority, not a defect), and 15 are Contradicted. (Was 441/185/241/15 + // before the coverage-cell word `idil` (metathesis-phase-isolation) added one claimed-construct + // row for its PartOfSpeech::LexicalEntry.partOfSpeech->PhonologicalSubrule.requiredPartsOfSpeech + // AbsentGatedForm witness; 442 -> 444 when author-coverage-cell added `gofz`/`ygofz` to + // languages/fusional-realizational-morphology, each claiming the prose construct "MPR + // features/groups" -- both Unmapped, for `ygofz`'s MorphologicalOutput.MPRFeatures-> + // MorphologicalInput.requiredMPRFeatures AbsentGatedForm witness.) + [Test] + public void CheckedInLedgerHasTheMeasuredClaimAndStatusCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = ConstructClaimCorroboration.Read(root); + + int confirmed = rows.Count(r => r.Status == ConstructClaimStatus.Confirmed); + int contradicted = rows.Count(r => r.Status == ConstructClaimStatus.Contradicted); + int unmapped = rows.Count(r => r.Status == ConstructClaimStatus.Unmapped); + + TestContext.Out.WriteLine( + $"rows={rows.Count} confirmed={confirmed} contradicted={contradicted} unmapped={unmapped}" + ); + + Assert.That(rows, Has.Count.EqualTo(452)); + Assert.That(confirmed, Is.EqualTo(187)); + Assert.That(contradicted, Is.EqualTo(15)); + Assert.That(unmapped, Is.EqualTo(250)); + } + + // All 15 Contradicted claims trace to one (fixture, construct) pair: edge-cases/morphotactic- + // attribute-breadth claiming the bundled construct "Ordinary/realizational rule constraints + // (MaxApplicationCount/RequiredStemName/Blockable)". Manually verified (see the task report) that + // this is a corroboration-heuristic limitation, not a false claim by the fixture author: the + // fixture genuinely exercises multipleApplication and blockable (2 of the 3 bundled things), but + // "MaxApplicationCount" names no real DTD identifier (the real attribute is multipleApplication) + // and "Blockable" is filtered out by the internal-capital heuristic (a bare English word) -- so the + // only token this mapping could ever check for this construct is requiredStemName, which this + // fixture indeed never uses. Pinned so a change here is investigated, not silently re-baselined. + [Test] + public void AllContradictedClaimsTraceToTheKnownBundledConstructLimitation() + { + string root = RepositoryRoot(); + IReadOnlyList rows = ConstructClaimCorroboration.Read(root); + ConstructClaimCorroboration.Row[] contradicted = rows.Where(r => r.Status == ConstructClaimStatus.Contradicted) + .ToArray(); + + Assert.That(contradicted, Has.Length.EqualTo(15)); + Assert.That( + contradicted.Select(r => r.Fixture).Distinct(), + Is.EquivalentTo(new[] { "edge-cases/morphotactic-attribute-breadth" }) + ); + Assert.That( + contradicted.Select(r => r.Construct).Distinct(), + Is.EquivalentTo( + new[] { "Ordinary/realizational rule constraints (MaxApplicationCount/RequiredStemName/Blockable)" } + ) + ); + Assert.That(contradicted.Select(r => r.MatchedTokens.Count), Is.All.EqualTo(1)); + } + + // Cheap: constructs.txt, the DTD (once), and every fixture's already-loaded grammar.xml/words.yaml + // -- no reparse, so this runs on every pass rather than needing [Explicit]. + [Test] + public void CheckedInConstructClaimCorroborationIsUpToDate() + { + string root = RepositoryRoot(); + string constructsPath = Path.Combine(root, "conformance", "constructs.txt"); + IReadOnlyList fresh = ConstructClaimCorroboration.Compute( + root, + constructsPath + ); + string freshText = ConstructClaimCorroboration.ToText(fresh); + string checkedIn = File.ReadAllText( + Path.Combine(root, ConstructClaimCorroboration.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + freshText.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-coverage-traceability --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CounterfactualGateTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CounterfactualGateTests.cs new file mode 100644 index 000000000..eefda7af2 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CounterfactualGateTests.cs @@ -0,0 +1,625 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class CounterfactualGateTests +{ + // A minimal, DTD-valid grammar with exactly one root ("a") so each test can neutralize one + // surface and know precisely what should (or should not) change. + private const string ProbeGrammar = """ + + + + + CounterfactualProbe + Any + + Table + + a + + + + + Only + + + a + ROOT + root-gloss + + + + + + + """; + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static SemanticInventory Inventory() => GrammarCoverageGate.ReadInventory(RepositoryRoot()); + + private string _fixtureDirectory = string.Empty; + private string _scratchDirectory = string.Empty; + + [SetUp] + public void SetUp() + { + _fixtureDirectory = Path.Combine( + Path.GetTempPath(), + "hc-counterfactual-gate-tests", + Guid.NewGuid().ToString("N") + ); + _scratchDirectory = Path.Combine(_fixtureDirectory, "scratch"); + Directory.CreateDirectory(_fixtureDirectory); + File.WriteAllText(Path.Combine(_fixtureDirectory, "grammar.xml"), ProbeGrammar); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_fixtureDirectory)) + Directory.Delete(_fixtureDirectory, recursive: true); + } + + private Fixture ProbeFixture() + { + var words = new WordsYaml { Language = "CounterfactualProbe" }; + words.Words.Add(new WordEntry { Word = "a" }); + return new Fixture("probe/fixture", _fixtureDirectory, words); + } + + [Test] + public void ASurfaceWhoseMutationChangesAResultIsEvidenced() + { + Fixture fixture = ProbeFixture(); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + // MorphemeId is optional per the DTD, so deleting it leaves a loadable document -- but the + // loader falls back to a null morpheme ID, which changes the parse signature. + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + "dtd:element/MorphemeId", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Evidenced)); + Assert.That(result.Delta, Does.Contain("->")); + } + + [Test] + public void ASurfaceWhoseMutationChangesNothingIsUnobservable() + { + Fixture fixture = ProbeFixture(); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + // Gloss is never read by the parser or folded into a signature, so removing it cannot + // change any word's outcome. + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + "dtd:element/Gloss", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Unobservable)); + } + + [Test] + public void DeletingTheRootLanguageElementIsRequiredByDtd() + { + Fixture fixture = ProbeFixture(); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + // Language is an element surface: removing it fails generic DTD content-model validation + // (HermitCrabInput's declared sequence) before XmlLanguageLoader ever runs. + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + "dtd:element/Language", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.RequiredByDtd)); + } + + [Test] + public void TheGateDoesNotMutateTheOriginalDocumentOnDisk() + { + Fixture fixture = ProbeFixture(); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + string before = File.ReadAllText(fixture.GrammarPath); + + CounterfactualGate.Evaluate(fixture, "dtd:element/MorphemeId", Inventory(), baseline, _scratchDirectory); + CounterfactualGate.Evaluate(fixture, "dtd:element/Language", Inventory(), baseline, _scratchDirectory); + + Assert.That(File.ReadAllText(fixture.GrammarPath), Is.EqualTo(before)); + } + + // A fail-fast-IDREF probe mirroring the real loader-isactive-breadth shape: an inactive Family + // ("famX") that only an equally inactive LexicalEntry ("eB") names. Activating famX alone + // changes nothing (nothing references it); activating eB alone throws at load (the family it + // names was never loaded); only activating both lets "b" parse. + private const string JointFamilyProbeGrammar = """ + + + + + JointFamilyProbe + Any + + Table + + a + b + + + + X + + + + Only + + + a + ROOT + root-gloss + + + b + B + b-gloss + + + + + + + """; + + // A tolerant-IDREF probe where the "partner" (an inactive Slot naming both mrX and the + // already-active mrY) changes "ya" all by itself -- mrY needs no help from mrX to reach the + // slot -- so the joint delta must NOT be credited to MorphologicalRule/isActive/no for mrX. + private const string PartnerAloneExplainsItGrammar = """ + + + + + JointRejectProbe + Any + + Table + + a + x + y + + + + Any + + + + Only + + + xPrefix + + + + x + + + X + x-gloss + + + yPrefix + + + + y + + + Y + y-gloss + + + + + tmpl + slot + + + + + a + ROOT + root-gloss + + + + + + + """; + + private Fixture ProbeFixtureFor(string grammar, string language, params string[] words) + { + File.WriteAllText(Path.Combine(_fixtureDirectory, "grammar.xml"), grammar); + var wordsYaml = new WordsYaml { Language = language }; + foreach (string word in words) + wordsYaml.Words.Add(new WordEntry { Word = word }); + return new Fixture("probe/joint-fixture", _fixtureDirectory, wordsYaml); + } + + [Test] + public void ASurfaceEvidencedOnlyJointlyIsReportedAsEvidencedJointly() + { + Fixture fixture = ProbeFixtureFor(JointFamilyProbeGrammar, "JointFamilyProbe", "a", "b"); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + CounterfactualResult single = CounterfactualGate.Evaluate( + fixture, + "dtd:enum/Family/isActive/no", + Inventory(), + baseline, + _scratchDirectory + ); + Assert.That( + single.Verdict, + Is.EqualTo(CounterfactualVerdict.Unobservable), + "flipping famX alone must change nothing" + ); + + CounterfactualResult joint = CounterfactualGate.EvaluateJointly( + fixture, + "dtd:enum/Family/isActive/no", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(joint.Verdict, Is.EqualTo(CounterfactualVerdict.EvidencedJointly)); + Assert.That(joint.Delta, Does.Contain("target alone")); + Assert.That(joint.Delta, Does.Contain("partner alone")); + Assert.That( + joint.Delta, + Does.Contain("RequiredByLoader"), + "the partner alone must throw, not silently drop the reference" + ); + Assert.That(joint.Delta, Does.Contain("'b'"), "the joint delta must name the word that newly parses"); + } + + [Test] + public void ADeltaThePartnerAloneAlreadyExplainsIsNotEvidenced() + { + Fixture fixture = ProbeFixtureFor(PartnerAloneExplainsItGrammar, "JointRejectProbe", "a", "ya"); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + CounterfactualResult joint = CounterfactualGate.EvaluateJointly( + fixture, + "dtd:enum/MorphologicalRule/isActive/no", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That( + joint.Verdict, + Is.EqualTo(CounterfactualVerdict.Unobservable), + "the slot alone already makes 'ya' parse via mrY; mrX contributes nothing extra on this word list" + ); + Assert.That(joint.Delta, Does.Contain("partner alone reproduces the identical delta")); + } + + [Test] + public void NoIndependentPartnerYieldsUnobservableNotAThrow() + { + // eB itself is filtered out (isActive="no"), so mrX/famX above are both eligible targets in + // GrammarFeatureUsage terms, but a surface this grammar never declares at all has no target + // to even look for a partner around. + Fixture fixture = ProbeFixtureFor(JointFamilyProbeGrammar, "JointFamilyProbe", "a", "b"); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + CounterfactualResult result = CounterfactualGate.EvaluateJointly( + fixture, + "dtd:enum/FeatureNaturalClass/isActive/no", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Unobservable)); + Assert.That(result.Delta, Does.Contain("no independently-inactive referencing declaration")); + } + + // mrNever requires a part of speech no lexical entry carries, so it never applies and none of + // multipleApplication's nine declared sibling values can change any outcome. + private const string RuleNeverAppliesGrammar = """ + + + + + MultipleApplicationProbe + + Other + + + Table + + a + x + + + + Any + + + + Only + + + never + + + + x + + + NEVER + + + + + a + ROOT + root-gloss + + + + + + + """; + + [Test] + public void ASurfaceUnobservableAgainstEverySiblingRecordsTheFullList() + { + Fixture fixture = ProbeFixtureFor(RuleNeverAppliesGrammar, "MultipleApplicationProbe", "a"); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + "dtd:enum/MorphologicalRule/multipleApplication/1", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Unobservable)); + Assert.That(result.Mutation, Does.Contain("9 declared sibling")); + foreach (string sibling in new[] { "0", "2", "3", "4", "5", "6", "7", "8", "9" }) + Assert.That(result.Mutation, Does.Contain($"\"{sibling}\""), $"sibling {sibling} must be named"); + Assert.That(result.Delta, Does.Contain("none produced a delta")); + } + + [Test] + public void RepeatedEvaluationsOfAnUnobservableEnumSurfaceAgreeOnTheSiblingsTried() + { + Fixture fixture = ProbeFixtureFor(RuleNeverAppliesGrammar, "MultipleApplicationProbe", "a"); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + CounterfactualResult first = CounterfactualGate.Evaluate( + fixture, + "dtd:enum/MorphologicalRule/multipleApplication/1", + Inventory(), + baseline, + _scratchDirectory + ); + CounterfactualResult second = CounterfactualGate.Evaluate( + fixture, + "dtd:enum/MorphologicalRule/multipleApplication/1", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(second.Verdict, Is.EqualTo(first.Verdict)); + Assert.That(second.Mutation, Is.EqualTo(first.Mutation)); + Assert.That(second.Delta, Is.EqualTo(first.Delta)); + } + + // redupMorphType's alphabetically-first sibling "implicit" is a no-op on this fixture, but the + // untried "prefix" sibling swaps the morph order -- the proven false-negative this fixes. + [Test] + public void ASurfaceWhoseFirstSiblingIsANoOpButALaterSiblingDiscriminatesIsEvidenced() + { + string root = RepositoryRoot(); + string fixtureDirectory = Path.Combine(root, "conformance", "languages", "suffixing-extension-slot-ordering"); + var words = new WordsYaml { Language = "SuffixingExtensionSlotOrdering" }; + words.Words.Add(new WordEntry { Word = "kimbiakimbia" }); + var fixture = new Fixture("languages/suffixing-extension-slot-ordering", fixtureDirectory, words); + + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + Assert.That( + baseline, + Is.EqualTo(new[] { "ok::KIMB+RED|kimbiakimbia" }), + "pins the baseline this test reasons from" + ); + + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + "dtd:enum/MorphologicalOutput/redupMorphType/suffix", + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Evidenced)); + Assert.That(result.Mutation, Does.Contain("to \"prefix\""), "the discriminating sibling must be named"); + Assert.That(result.Delta, Does.Contain("sibling \"prefix\"")); + Assert.That(result.Delta, Does.Contain("KIMB+RED")); + Assert.That(result.Delta, Does.Contain("RED+KIMB")); + } + + // The enum-sibling search must not stop at the first RequiredByLoader it finds: Word and + // LoadFailure are different strengths of evidence (CounterexampleKind), and a later sibling's + // word-level contrast is stronger. Stopping early would make the recorded strength depend on the + // DTD's alphabetical value ordering rather than on what the grammar shows. + [Test] + public void FirstSiblingRequiredByLoaderThenLaterSiblingEvidencedResultsInEvidencedWithWordCounterexample() + { + var requiredToLoad = new CounterfactualResult( + "s", + "fx", + CounterfactualVerdict.RequiredByLoader, + "rewrote to sibling A", + "InvalidOperationException: boom", + CounterexampleKind: CounterexampleKind.LoadFailure, + CounterexampleOutcome: "InvalidOperationException: boom" + ); + var evidenced = new CounterfactualResult( + "s", + "fx", + CounterfactualVerdict.Evidenced, + "rewrote to sibling B", + "'w': ok::X -> ok::Y", + ExampleWord: "w", + ExampleOutcome: "ok::X", + CounterexampleKind: CounterexampleKind.Word, + CounterexampleOutcome: "ok::Y" + ); + + (CounterfactualResult? bestAfterFirst, CounterfactualGate.EnumSiblingSearchAction actionAfterFirst) = + CounterfactualGate.ConsiderEnumSiblingResult(null, requiredToLoad); + Assert.That(bestAfterFirst, Is.EqualTo(requiredToLoad)); + Assert.That( + actionAfterFirst, + Is.EqualTo(CounterfactualGate.EnumSiblingSearchAction.Continue), + "a load failure alone must not stop the search for a stronger result" + ); + + (CounterfactualResult? bestAfterSecond, CounterfactualGate.EnumSiblingSearchAction actionAfterSecond) = + CounterfactualGate.ConsiderEnumSiblingResult(bestAfterFirst, evidenced); + Assert.That(bestAfterSecond, Is.EqualTo(evidenced)); + Assert.That(bestAfterSecond!.Verdict, Is.EqualTo(CounterfactualVerdict.Evidenced)); + Assert.That(bestAfterSecond.CounterexampleKind, Is.EqualTo(CounterexampleKind.Word)); + Assert.That(actionAfterSecond, Is.EqualTo(CounterfactualGate.EnumSiblingSearchAction.Stop)); + } + + [Test] + public void ConsiderEnumSiblingResultStopsImmediatelyOnWordEvidence() + { + var evidenced = new CounterfactualResult( + "s", + "fx", + CounterfactualVerdict.Evidenced, + "m", + "d", + CounterexampleKind: CounterexampleKind.Word + ); + + (CounterfactualResult? best, CounterfactualGate.EnumSiblingSearchAction action) = + CounterfactualGate.ConsiderEnumSiblingResult(null, evidenced); + + Assert.That(best, Is.EqualTo(evidenced)); + Assert.That(action, Is.EqualTo(CounterfactualGate.EnumSiblingSearchAction.Stop)); + } + + [Test] + public void ConsiderEnumSiblingResultKeepsTheFirstLoadFailureWhenNoStrongerResultFollows() + { + var first = new CounterfactualResult( + "s", + "fx", + CounterfactualVerdict.RequiredByLoader, + "m1", + "d1", + CounterexampleKind: CounterexampleKind.LoadFailure + ); + var second = new CounterfactualResult( + "s", + "fx", + CounterfactualVerdict.RequiredByLoader, + "m2", + "d2", + CounterexampleKind: CounterexampleKind.LoadFailure + ); + var unobservable = new CounterfactualResult("s", "fx", CounterfactualVerdict.Unobservable, "m3", "d3"); + + (CounterfactualResult? best1, _) = CounterfactualGate.ConsiderEnumSiblingResult(null, first); + (CounterfactualResult? best2, _) = CounterfactualGate.ConsiderEnumSiblingResult(best1, second); + (CounterfactualResult? best3, _) = CounterfactualGate.ConsiderEnumSiblingResult(best2, unobservable); + + Assert.That(best3, Is.EqualTo(first), "the first load failure wins when nothing stronger is ever found"); + } + + // Recomputes the whole sweep, so it costs minutes and is excluded from the default suite; the + // counterfactual-coverage workflow is what runs it. + [Test] + [Explicit("re-parses every fixture once per surface")] + [Category("Counterfactual")] + public void TheCheckedInLedgerMatchesAFreshRecomputeExactly() + { + string root = RepositoryRoot(); + IReadOnlyList fresh = CounterfactualLedger.Sweep(root, Inventory()); + IReadOnlyList checkedIn = CounterfactualLedger.Read(root); + + var freshById = fresh.ToDictionary(entry => entry.SurfaceId, StringComparer.Ordinal); + var checkedInById = checkedIn.ToDictionary(entry => entry.SurfaceId, StringComparer.Ordinal); + + string[] added = freshById + .Keys.Except(checkedInById.Keys, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] removed = checkedInById + .Keys.Except(freshById.Keys, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] changed = freshById + .Keys.Intersect(checkedInById.Keys, StringComparer.Ordinal) + .Where(id => freshById[id] != checkedInById[id]) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That( + added, + Is.Empty, + $"new surfaces; regenerate with --write-counterfactual:\n {string.Join("\n ", added)}" + ); + Assert.That( + removed, + Is.Empty, + $"stale surfaces; delete from {CounterfactualLedger.RelativePath}:\n {string.Join("\n ", removed)}" + ); + Assert.That( + changed, + Is.Empty, + $"changed verdicts; regenerate with --write-counterfactual after checking why:\n {string.Join("\n ", changed)}" + ); + }); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageCliAuthorityTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageCliAuthorityTests.cs new file mode 100644 index 000000000..351e81001 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageCliAuthorityTests.cs @@ -0,0 +1,246 @@ +using System.Diagnostics; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class CoverageCliAuthorityTests +{ + private string _repositoryRoot = string.Empty; + + [SetUp] + public void SetUp() + { + _repositoryRoot = Path.Combine(Path.GetTempPath(), "hc-coverage-cli-tests", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(Path.Combine(_repositoryRoot, "conformance")); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_repositoryRoot)) + Directory.Delete(_repositoryRoot, recursive: true); + } + + [Test] + public void CoverageEvidenceExitsNonzeroWhenTheAuthoritativeGateRejectsAProof() + { + CounterfactualLedger.Write( + _repositoryRoot, + new[] + { + new CounterfactualResult( + "dtd:enum/Stratum/cyclicity/cyclic", + "edge-cases/synthetic", + CounterfactualVerdict.Unobservable, + "set cyclicity", + "unchanged" + ), + } + ); + File.WriteAllText( + Path.Combine(_repositoryRoot, ImpossibilityProofs.RelativePath), + "surface\tkind\tevidence\n" + + "dtd:enum/Stratum/cyclicity/cyclic\tno-consumer\tchecked-in prose is not a proof\n" + ); + + ProcessResult result = RunCoverageCli("--coverage-evidence", CancellationToken.None); + + Assert.That(result.ExitCode, Is.EqualTo(1), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("rejected proof")); + Assert.That(result.CombinedOutput, Does.Contain("complete: False")); + } + + // The checked-in catalog's empty auditedSourceScopes no longer short-circuits the run: the + // semantic coverage program audits the grammar format (dtd: surfaces), not the C# engine's + // internals, so an empty scope list runs the audit against the DTD-only inventory and fails + // on the real, expected-for-now backlog (unclassified grammar features) instead. + [Test] + [CancelAfter(300_000)] + public void CheckedInEmptyCatalogRunsTheAuditAndFailsOnUnclassifiedMappings(CancellationToken cancellationToken) + { + string root = RepositoryRoot(); + ProcessResult result = RunCoverageCli("--semantic-coverage", cancellationToken, root); + + Assert.That(result.ExitCode, Is.EqualTo(1), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Not.Contain("audited-source-scopes-empty")); + Assert.That(result.CombinedOutput, Does.Contain("generated surfaces:")); + Assert.That(result.CombinedOutput, Does.Contain("unclassified-mapping")); + } + + [Test] + public void ProposalNeverChangesCanonicalCatalogBytes() + { + string root = RepositoryRoot(); + string catalogPath = Path.Combine(root, "conformance", "semantic-catalog.yaml"); + byte[] before = File.ReadAllBytes(catalogPath); + + ProcessResult result = RunCoverageCli( + "--propose-semantic-catalog", + CancellationToken.None, + root, + "--audited-source-scope", + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader" + ); + + Assert.That(result.ExitCode, Is.EqualTo(1), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("proposal only")); + Assert.That( + result.CombinedOutput, + Does.Contain("auditedSourceScopes: [\"SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader\"]") + ); + Assert.That(File.ReadAllBytes(catalogPath), Is.EqualTo(before)); + } + + [Test] + public void EmptyCatalogWithoutExplicitProposalScopeIsControlledError() + { + string root = RepositoryRoot(); + ProcessResult result = RunCoverageCli("--propose-semantic-catalog", CancellationToken.None, root); + + Assert.That(result.ExitCode, Is.EqualTo(2), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("requires one or more")); + } + + // The census is the compiler's own graph now, so a CLI census test needs a restored + // repository; a synthetic directory has no compiler inputs to capture. The checked-in + // catalog carries no audited scopes, so --semantic-coverage's own census contributes no C# + // surfaces; the proposal with an explicit scope is the only way to exercise the live C# + // census from the CLI. + [Test] + [CancelAfter(300_000)] + public void ScopedProposalRunsTheLiveGraphCensusAndPreservesCatalog(CancellationToken cancellationToken) + { + string root = RepositoryRoot(); + string catalogPath = Path.Combine(root, "conformance", "semantic-catalog.yaml"); + byte[] before = File.ReadAllBytes(catalogPath); + + ProcessResult result = RunCoverageCli( + "--propose-semantic-catalog", + cancellationToken, + root, + "--audited-source-scope", + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load(System.String)" + ); + + Assert.That(result.ExitCode, Is.EqualTo(1), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("schema/decision-if"), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Not.Contain("proposal unavailable"), result.CombinedOutput); + Assert.That(File.ReadAllBytes(catalogPath), Is.EqualTo(before)); + } + + [Test] + public void WildcardProposalScopeIsControlledError() + { + string root = CreateSyntheticRepository(); + ProcessResult result = RunCoverageCli( + "--propose-semantic-catalog", + CancellationToken.None, + root, + "--audited-source-scope", + "Fixture.*" + ); + + Assert.That(result.ExitCode, Is.EqualTo(2), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("patterns are not allowed")); + } + + [Test] + public void MissingRequiredBaselineIsControlledAuthorityError() + { + string root = CreateSyntheticRepository(); + File.Delete(Path.Combine(root, "conformance", "semantic-coverage-baseline.txt")); + + ProcessResult result = RunCoverageCli("--semantic-coverage", CancellationToken.None, root); + + Assert.That(result.ExitCode, Is.EqualTo(2), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("semantic coverage authority unavailable")); + } + + [Test] + public void MalformedFixtureGrammarIsControlledAuthorityError() + { + string root = CreateSyntheticRepository(); + string fixture = Path.Combine(root, "conformance", "malformed"); + Directory.CreateDirectory(fixture); + File.WriteAllText(Path.Combine(fixture, "grammar.xml"), ""); + + ProcessResult result = RunCoverageCli("--semantic-coverage", CancellationToken.None, root); + + Assert.That(result.ExitCode, Is.EqualTo(2), result.CombinedOutput); + Assert.That(result.CombinedOutput, Does.Contain("semantic coverage authority unavailable")); + Assert.That(result.CombinedOutput, Does.Not.Contain("Unhandled exception")); + } + + // cancellationToken is required, not defaulted, so every call site above states outright whether it + // rides on the test's own [CancelAfter] token or deliberately has none -- see ChildProcessHarness for + // why an unwired token leaves this method's child process running past a cancelled test. + private ProcessResult RunCoverageCli( + string mode, + CancellationToken cancellationToken, + string? repositoryRoot = null, + params string[] extraArgs + ) + { + string tool = Path.Combine(TestContext.CurrentContext.TestDirectory, "hc-conformance.dll"); + Assert.That(File.Exists(tool), Is.True, $"missing test-side CLI at {tool}"); + var start = new ProcessStartInfo + { + FileName = "dotnet", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + start.ArgumentList.Add(tool); + start.ArgumentList.Add(mode); + start.ArgumentList.Add("--repository-root"); + start.ArgumentList.Add(repositoryRoot ?? _repositoryRoot); + foreach (string extraArg in extraArgs) + start.ArgumentList.Add(extraArg); + + ChildProcessHarness.Result result = ChildProcessHarness.Run(start, cancellationToken); + return new ProcessResult(result.ExitCode, result.StandardOutput + result.StandardError); + } + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private string CreateSyntheticRepository() + { + string engine = Path.Combine(_repositoryRoot, "src", "SIL.Machine.Morphology.HermitCrab"); + string tool = Path.Combine(_repositoryRoot, "src", "SIL.Machine.Morphology.HermitCrab.Tool"); + Directory.CreateDirectory(engine); + Directory.CreateDirectory(tool); + File.WriteAllText(Path.Combine(_repositoryRoot, "conformance", "constructs.txt"), "synthetic\n"); + File.WriteAllText(Path.Combine(engine, "HermitCrabInput.dtd"), "\n"); + File.WriteAllText( + Path.Combine(engine, "Engine.cs"), + "namespace Fixture { public sealed class Root { public void Run(bool value) { if (value) { } } } }" + ); + File.WriteAllText(Path.Combine(tool, "Tool.cs"), "namespace Fixture { public sealed class Tool { } }"); + File.WriteAllText(Path.Combine(_repositoryRoot, "conformance", "semantic-coverage-baseline.txt"), ""); + File.WriteAllText(Path.Combine(_repositoryRoot, "conformance", "semantic-coverage-presence-waivers.txt"), ""); + File.WriteAllText( + Path.Combine(_repositoryRoot, "conformance", "semantic-catalog.yaml"), + "profile: sil.machine.hc-semantic-catalog/v1\n" + + "auditedSourceScopes: [Fixture.Root]\n" + + "features: []\n" + + "surfaceMappings: []\n" + ); + return _repositoryRoot; + } + + private sealed record ProcessResult(int ExitCode, string CombinedOutput); +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageCompletenessGateTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageCompletenessGateTests.cs new file mode 100644 index 000000000..386a82e45 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageCompletenessGateTests.cs @@ -0,0 +1,715 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class CoverageCompletenessGateTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static CoverageItem Item(string id, CoverageItemKind kind = CoverageItemKind.Surface) => + new(id, kind, "dtd-element", "fx"); + + private static Evidence WordEvidence(string itemId) => + new( + itemId, + "fx", + "w", + "ok::before", + CounterexampleKind.Word, + "ok::after", + "removed 1 element", + CounterfactualVerdict.Evidenced + ); + + [Test] + public void AnItemWithNoEvidenceAndNoProofIsUnresolvedAndFailsCompleteness() + { + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + Array.Empty(), + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Unresolved)); + } + + [Test] + public void AnItemWithBothEvidenceAndAProofIsConflictingAndFailsCompleteness() + { + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { WordEvidence("a") }, + new[] { new Proof("a", ImpossibilityProofs.NoConsumer, "no reference in the engine") } + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Conflicting)); + } + + [Test] + public void AnItemWithEvidenceAndAnUnsupportedProofStillFailsCompleteness() + { + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a"), Item("b") }, + new[] { WordEvidence("a") }, + new[] { new Proof("b", ImpossibilityProofs.NoConsumer, "checked-in prose claim") } + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single(i => i.ItemId == "b").Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } + + [TestCase(ImpossibilityProofs.DtdDefault)] + [TestCase(ImpossibilityProofs.NoConsumer)] + [TestCase(ImpossibilityProofs.NotInSignature)] + [TestCase(ImpossibilityProofs.BlockedByDefect)] + [TestCase("unknown-proof-kind")] + public void AnUnsupportedProofKindIsRejectedUntilItHasAMechanicalVerifier(string proofKind) + { + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + Array.Empty(), + new[] { new Proof("a", proofKind, "checked-in prose claim") } + ); + + Assert.That(report.IsComplete, Is.False); + CoverageResolutionResult result = report.Items.Single(); + Assert.That(result.Resolution, Is.EqualTo(CoverageResolution.Rejected)); + Assert.That(result.Detail, Does.Contain("mechanical verifier")); + } + + [TestCase("languages/suffixing-evidential-adjacency-chain", "person", "number", TemplateMaskedProofs.Kind)] + [TestCase("edge-cases/feature-system-breadth", "prHighTrigger", "mtSwap", NeverFiresProofs.Kind)] + [TestCase( + "edge-cases/mpr-gated-exception", + "prNasalAssimBilabial", + "prNasalAssimAlveolar", + FeatureValueDisjointProofs.Kind + )] + public void ARecomputedStructuralProofKindIsAdmittedByTheGate( + string fixtureId, + string memberA, + string memberB, + string expectedKind + ) + { + string root = RepositoryRoot(); + Fixture fixture = Fixture.DiscoverAll(Path.Combine(root, "conformance")).Single(f => f.Id == fixtureId); + XDocument grammar = XDocument.Load(fixture.GrammarPath); + OrderingItem orderingItem = OrderingGenerator + .EnumerateAdjacentPairs(grammar, fixtureId) + .Single(item => item.MemberA == memberA && item.MemberB == memberB); + Proof? proof = expectedKind switch + { + var kind when kind == TemplateMaskedProofs.Kind => TemplateMaskedProofs.TryBuild(grammar, orderingItem), + var kind when kind == NeverFiresProofs.Kind => NeverFiresProofs.TryBuild(grammar, orderingItem), + var kind when kind == FeatureValueDisjointProofs.Kind => FeatureValueDisjointProofs.TryBuild( + grammar, + orderingItem + ), + _ => throw new ArgumentOutOfRangeException(nameof(expectedKind), expectedKind, "test proof kind"), + }; + Assert.That(proof, Is.Not.Null, $"{expectedKind} proof should build for the checked-in fixture"); + Assert.That(proof!.Kind, Is.EqualTo(expectedKind)); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", fixtureId); + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.True, report.Items.Single().Detail); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Proven)); + } + + [Test] + public void CountsAreReportedPerCounterexampleKindNeverBlended() + { + Evidence loadFailure = new( + "b", + "fx", + "w", + "ok", + CounterexampleKind.LoadFailure, + "threw", + "removed root", + CounterfactualVerdict.RequiredByDtd + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a"), Item("b") }, + new[] { WordEvidence("a"), loadFailure }, + Array.Empty() + ); + + Assert.That(report.EvidencedCountsByCounterexampleKind[CounterexampleKind.Word], Is.EqualTo(1)); + Assert.That(report.EvidencedCountsByCounterexampleKind[CounterexampleKind.LoadFailure], Is.EqualTo(1)); + } + + [Test] + public void AProofNamingAnItemNoLongerInTheInventoryIsOrphanedAndFailsCompleteness() + { + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { WordEvidence("a") }, + new[] { new Proof("gone", ImpossibilityProofs.NoConsumer, "no reference in the engine") } + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.OrphanedProofItemIds, Is.EqualTo(new[] { "gone" })); + } + + [Test] + public void EvidenceNamingAnItemNoLongerInTheInventoryIsOrphanedAndFailsCompleteness() + { + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { WordEvidence("a"), WordEvidence("gone") }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.OrphanedEvidenceItemIds, Is.EqualTo(new[] { "gone" })); + } + + [Test] + public void EvidenceFromADifferentFixtureCannotResolveTheItem() + { + Evidence wrongFixture = WordEvidence("a") with { Fixture = "other-fixture" }; + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { wrongFixture }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Unresolved)); + Assert.That(report.Items.Single().Detail, Does.Contain("fixture")); + } + + [Test] + public void AnEvidenceRecordWithNoneCounterexampleKindDoesNotCountAsEvidence() + { + // Unobservable/Timeout results carry CounterexampleKind.None: not a counter-example, and + // must not silently resolve the item without a proof. + Evidence unobservable = new( + "a", + "fx", + null, + null, + CounterexampleKind.None, + null, + "none", + CounterfactualVerdict.Unobservable + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { unobservable }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Unresolved)); + } + + [TestCase(CounterfactualVerdict.Timeout, CounterexampleKind.Word)] + [TestCase(CounterfactualVerdict.Unobservable, CounterexampleKind.Word)] + [TestCase(CounterfactualVerdict.Evidenced, CounterexampleKind.LoadFailure)] + [TestCase(CounterfactualVerdict.RequiredByDtd, CounterexampleKind.Word)] + [TestCase(CounterfactualVerdict.RequiredByLoader, CounterexampleKind.Word)] + public void AContradictoryVerdictAndCounterexampleKindDoesNotCountAsEvidence( + CounterfactualVerdict verdict, + CounterexampleKind counterexampleKind + ) + { + Evidence contradictory = new("a", "fx", "w", "before", counterexampleKind, "after", "mutation", verdict); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { contradictory }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Unresolved)); + Assert.That(report.EvidencedCountsByCounterexampleKind.Values.Sum(), Is.Zero); + } + + [TestCase(CounterfactualVerdict.Evidenced)] + [TestCase(CounterfactualVerdict.EvidencedJointly)] + public void AWordCounterexampleCountsForEitherMechanicallyEvidencedVerdict(CounterfactualVerdict verdict) + { + Evidence evidence = new("a", "fx", "w", "before", CounterexampleKind.Word, "after", "mutation", verdict); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { evidence }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Evidenced)); + Assert.That(report.EvidencedCountsByCounterexampleKind[CounterexampleKind.Word], Is.EqualTo(1)); + } + + [Test] + public void AJointLoadFailureCounterexampleCountsAsEvidence() + { + Evidence evidence = new( + "a", + "fx", + "w", + "before", + CounterexampleKind.LoadFailure, + "FormatException: mutant rejected", + "joint mutation", + CounterfactualVerdict.EvidencedJointly + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { evidence }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Evidenced)); + Assert.That(report.EvidencedCountsByCounterexampleKind[CounterexampleKind.LoadFailure], Is.EqualTo(1)); + } + + // Both required-to-load verdicts still count as completeness evidence: RequiredByDtd is a weaker + // witness than RequiredByLoader (no HermitCrab-specific code was ever reached), but it is still a + // real, structural load-failure counter-example, not the absence of one. + [TestCase(CounterfactualVerdict.RequiredByDtd)] + [TestCase(CounterfactualVerdict.RequiredByLoader)] + public void ALoadFailureCounterexampleCountsAsEvidenceForEitherRequiredToLoadVerdict(CounterfactualVerdict verdict) + { + Evidence evidence = new( + "a", + "fx", + "w", + "before", + CounterexampleKind.LoadFailure, + "InvalidOperationException: mutant rejected", + "removed 1 element", + verdict + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { evidence }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Evidenced)); + Assert.That(report.EvidencedCountsByCounterexampleKind[CounterexampleKind.LoadFailure], Is.EqualTo(1)); + } + + [TestCase("word")] + [TestCase("example")] + [TestCase("counterexample")] + [TestCase("unchanged")] + public void AnIncompleteCounterexamplePayloadDoesNotCountAsEvidence(string missing) + { + Evidence incomplete = new( + "a", + "fx", + missing == "word" ? null : "w", + missing == "example" ? null : "same", + CounterexampleKind.Word, + missing == "counterexample" ? null + : missing == "unchanged" ? "same" + : "different", + "mutation", + CounterfactualVerdict.Evidenced + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { incomplete }, + Array.Empty() + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Unresolved)); + Assert.That(report.EvidencedCountsByCounterexampleKind.Values.Sum(), Is.Zero); + } + + [Test] + public void AnInvalidEvidenceClaimCannotDisappearBehindAProof() + { + Evidence invalid = new( + "a", + "fx", + null, + null, + CounterexampleKind.Word, + null, + "mutation", + CounterfactualVerdict.Evidenced + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { invalid }, + new[] { new Proof("a", ImpossibilityProofs.NoConsumer, "no reference in the engine") } + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.Not.EqualTo(CoverageResolution.Proven)); + } + + [Test] + public void DuplicateEvidenceRowsAreRejectedBeforeInvalidRowsCanBeFilteredOut() + { + Evidence invalidDuplicate = WordEvidence("a") with { Verdict = CounterfactualVerdict.Timeout }; + + Assert.Throws(() => + CoverageCompletenessGate.Evaluate( + new[] { Item("a") }, + new[] { WordEvidence("a"), invalidDuplicate }, + Array.Empty() + ) + ); + } + + // Two PhonologicalRule elements whose input/output both name segment "cA", so CheckDisjointDomains + // recomputes Overlaps. + private const string OverlappingPhonologicalRulesGrammar = """ + + p1 + + + + + + p2 + + + + + + + Only + + """; + + // A Slot pair is never modeled by CheckDisjointDomains, so it is always Undetermined -- the common + // case, not a corner case. + private const string UndeterminedSlotPairGrammar = """ + Only + tmpl + s1 + s2 + + + """; + + [Test] + public void ADisjointDomainsProofForAPairThatRecomputesOverlapsIsRejectedNotProven() + { + XDocument grammar = XDocument.Parse(OverlappingPhonologicalRulesGrammar); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Assert.That( + OrderingGenerator.CheckDisjointDomains(grammar, orderingItem).Relation, + Is.EqualTo(DomainRelation.Overlaps), + "sanity: this pair must genuinely overlap for the rejection below to test the right thing" + ); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + var falseProof = new Proof(orderingItem.Id, OrderingProofs.Kind, "hand-waved claim of independence"); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { falseProof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } + + [Test] + public void ADisjointDomainsProofForAPairThatRecomputesUndeterminedIsRejectedNotProven() + { + XDocument grammar = XDocument.Parse(UndeterminedSlotPairGrammar); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Assert.That( + OrderingGenerator.CheckDisjointDomains(grammar, orderingItem).Relation, + Is.EqualTo(DomainRelation.Undetermined), + "sanity: Slot pairs are never modeled by CheckDisjointDomains, so this must be Undetermined" + ); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + var falseProof = new Proof(orderingItem.Id, OrderingProofs.Kind, "hand-waved claim of independence"); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { falseProof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } + + [Test] + public void ADisjointDomainsProofWithNoGrammarLoaderIsRejectedRatherThanTrusted() + { + XDocument grammar = XDocument.Parse(OverlappingPhonologicalRulesGrammar); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + var proof = new Proof(orderingItem.Id, OrderingProofs.Kind, "unverifiable without a grammar"); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof } + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } + + [Test] + public void ADisjointDomainsProofThatRecomputesDisjointIsProven() + { + XDocument grammar = XDocument.Parse( + """ + + + aOnly + bOnly + + + p1 + + + + + + p2 + + + + + + + Only + + """ + ); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Proof? proof = OrderingProofs.TryBuild(grammar, orderingItem); + Assert.That(proof, Is.Not.Null); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof! }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Proven)); + } + + private const string UnorderedStratumGrammar = """ + + S + + """; + + [Test] + public void AnUnorderedInvariantProofThatRecomputesUnorderedIsProven() + { + XDocument grammar = XDocument.Parse(UnorderedStratumGrammar); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Proof proof = UnorderedInvariantProofs.TryBuild(grammar, orderingItem)!; + Assert.That(proof, Is.Not.Null, "sanity: this stratum is unordered"); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Proven)); + } + + // Guard: a hand-claimed unordered-invariant proof for a stratum that has since gone linear must be + // REJECTED at gate time, not trusted as prose. + [Test] + public void AnUnorderedInvariantProofForANowLinearStratumIsRejectedNotProven() + { + XDocument grammar = XDocument.Parse(UnorderedStratumGrammar.Replace("unordered", "linear")); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Assert.That( + UnorderedInvariantProofs.TryBuild(grammar, orderingItem), + Is.Null, + "sanity: linear cannot license this kind" + ); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + var falseProof = new Proof( + orderingItem.Id, + UnorderedInvariantProofs.Kind, + "hand-waved claim of unordered invariance" + ); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { falseProof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } + + private const string InactiveSecondMemberGrammar = """ + + S + + r1 + r2 + + + + """; + + [Test] + public void AnInactiveMemberProofThatRecomputesInactiveIsProven() + { + XDocument grammar = XDocument.Parse(InactiveSecondMemberGrammar); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Proof proof = InactiveMemberProofs.TryBuild(grammar, orderingItem)!; + Assert.That(proof, Is.Not.Null, "sanity: m2 is inactive"); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Proven)); + } + + // Guard: a hand-claimed inactive-member proof where both members are active must be REJECTED. + [Test] + public void AnInactiveMemberProofWhereBothMembersAreActiveIsRejectedNotProven() + { + XDocument grammar = XDocument.Parse(InactiveSecondMemberGrammar.Replace(" isActive=\"no\"", "")); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Assert.That(InactiveMemberProofs.TryBuild(grammar, orderingItem), Is.Null, "sanity: both members are active"); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + var falseProof = new Proof(orderingItem.Id, InactiveMemberProofs.Kind, "hand-waved claim of inactivity"); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { falseProof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } + + private const string PosDisjointNoBridgeGrammar = """ + + S + + rA + rB + + + + """; + + [Test] + public void APosDisjointProofThatRecomputesDisjointIsProven() + { + XDocument grammar = XDocument.Parse(PosDisjointNoBridgeGrammar); + OrderingItem orderingItem = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Proof proof = PosDisjointProofs.TryBuild(grammar, orderingItem)!; + Assert.That(proof, Is.Not.Null, "sanity: posX/posY never intersect and nothing bridges them"); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.True); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Proven)); + } + + // Guard: a hand-claimed pos-disjoint proof must be REJECTED once a bridging rule exists in the + // grammar it is re-verified against -- the exact danger the task calls out for this kind. + [Test] + public void APosDisjointProofIsRejectedNotProvenWhenABridgingRuleExists() + { + XDocument grammar = XDocument.Parse( + PosDisjointNoBridgeGrammar.Replace( + "", + """ + rC + + """ + ) + ); + OrderingItem orderingItem = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "mA" && i.MemberB == "mB"); + Assert.That(PosDisjointProofs.TryBuild(grammar, orderingItem), Is.Null, "sanity: mC bridges posX to posY"); + + var item = new CoverageItem(orderingItem.Id, CoverageItemKind.Ordering, "adjacent-transposition", "fx"); + var falseProof = new Proof(orderingItem.Id, PosDisjointProofs.Kind, "hand-waved claim of pos-disjointness"); + + CompletenessReport report = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { falseProof }, + loadGrammar: _ => grammar + ); + + Assert.That(report.IsComplete, Is.False); + Assert.That(report.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageGapRatchetTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageGapRatchetTests.cs new file mode 100644 index 000000000..2912c65bf --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoverageGapRatchetTests.cs @@ -0,0 +1,210 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Pins the corpus-wide gap count -- items neither evidenced (conformance/semantic-coverage-evidence.tsv) +/// nor proven (conformance/semantic-coverage-proofs.tsv plus a fresh, cheap disjoint-domains/unordered- +/// invariant/inactive-member/pos-disjoint recompute for Ordering) -- without recomputing the expensive +/// sweep: every input here is either a checked-in file or a pure, engine-free grammar read. Gaps may only +/// go down. A gate that fails on every existing gap would block all ordinary work and get switched off, so +/// this is a ratchet: it fails only if the count goes UP. +/// +[TestFixture] +public sealed class CoverageGapRatchetTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // From a real corpus-wide run: 194 Surface items with 191 evidenced + 3 rejected prose proofs; 138 + // Ordering items with 32 evidenced + 88 recomputed proven + 18 gap. Lower this pin whenever a fresh + // --write-coverage-evidence run finds fewer gaps. Never raise it without explaining why coverage + // regressed. + // + // Raised 31 -> 32: disjoint-domains now also checks Environment/LeftEnvironment/RightEnvironment + // (feeding/bleeding), not only PhoneticOutput vs PhoneticInput, which un-certifies 4 phonological + // pairs that were never actually independent. None of the four has evidence yet, so each is now an + // honest gap. A fifth un-certified pair has real empirical evidence already in the ledger, so it was + // never a gap either way -- see OrderingGeneratorTests for that pair by name. + // + // Lowered 32 -> 29: the new template-masked proof kind certifies 3 AffixTemplateSlots pairs whose + // owning Stratum is unordered and whose template's rules are all in the cascade (person~number and + // number~evidential in suffixing-evidential-adjacency-chain; tense~number in suffixing-vowel-harmony). + // + // Lowered 26 -> 24: inactive-member now also certifies an AffixTemplateSlots member that is itself + // active but whose morphologicalRules all fail to resolve to an active rule (an empty Slot), not + // only a member carrying isActive="no" itself. Certifies realSlot~realDecoySlot and + // realDecoySlot~coASlot in edge-cases/morphotactic-attribute-breadth, both empty because their only + // rule mrRealDecoy is isActive="no". + // + // Lowered 24 -> 22: two new recomputed kinds. never-fires certifies edge-cases/feature-system-breadth's + // prHighTrigger~mtSwap (prHighTrigger's LeftEnvironment names ncHighCons, which resolves to zero active + // segments -- no active segment is both hiPlus and hiCons). feature-value-disjoint certifies + // edge-cases/mpr-gated-exception's prNasalAssimBilabial~prNasalAssimAlveolar (disjoint featPlace + // environment classes, neither output reachable from the other's environment or input class). A third + // candidate, edge-cases/right-to-left-anchor-environment's prRtlAnchor~prSpread, was investigated and + // rejected: the two rules' Environments genuinely differ (a word-final RightEnvironment anchor vs. a + // LeftEnvironment natural class), so it does not meet this kind's own "environments must not + // differentiate them" bar even though input class and output segment happen to coincide -- left an + // open gap rather than shipped as a proof. + // + // Lowered 22 -> 18: pos-disjoint now distinguishes a same-side POS-preserving MorphologicalRule + // from a bridge that crosses between the two compared required-POS sets. This certifies four + // suffixing-extension-slot-ordering pairs that were blocked only by their own or a sibling rule's + // trivial posVn -> posVn output; cross-side, unrestricted, and CompoundingRule bridges still fail + // closed. + // + // Raised 21 -> 23 (Surface still 3; Ordering 18 -> 20): f8199d69 ("Take the four fixtures + // conformance-framework added, without its harness") added edge-cases/{free-fluctuating- + // allomorph-pair, mpr-group-overwrite-without-realizational, process-morphology-in-place-mutation, + // stem-name-restricted-root-allomorph}. Three of the four contribute zero Ordering gaps -- every + // adjacent pair they declare is already evidenced or proven. The fourth, + // mpr-group-overwrite-without-realizational, contributes exactly two: + // ordering:edge-cases/mpr-group-overwrite-without-realizational/morphologicalRules/mrThemeA~mrThemeB + // ordering:edge-cases/mpr-group-overwrite-without-realizational/morphologicalRules/mrThemeB~mrEndC + // Both are genuinely order-sensitive (that is this fixture's entire point: mrThemeB's Overwrite + // MPR-group semantics drop mprA, so mrEndC's requiredMPRFeatures="mprA" gate only passes before + // mrThemeB runs -- see the fixture's own wudofq row, expect_fail: true). None of the seven + // recomputed Ordering proof kinds model MPR-feature accumulation at all (pos-disjoint comes + // closest but correctly reports Overlaps, not Disjoint, since all three rules share + // requiredPartsOfSpeech="posN" -- POS alone cannot show these are independent, and they are not). + // So neither pair can ever be closed by a *proof*; only real evidence from + // --write-coverage-evidence (a checked-in row in conformance/semantic-coverage-evidence.tsv) can + // resolve them, and generating that evidence is out of scope here -- semantic-coverage-evidence.tsv + // is a shared, concurrently-owned artifact this fix does not touch. Recorded here by name, not + // merely by count, so lowering this pin later means finding these two exact ids evidenced, not + // just watching the total drop. + // Raised 14 -> 18. The four added gaps are all NEW ordering pairs, created by adding two rules + // to existing grammars while covering obligation cells -- each new rule forms pairs with the + // rules already present, and an ordering pair is evidenced only by the [Explicit] ordering + // measurement, not by the sweep that witnesses the cell: + // ordering:edge-cases/morphotactic-attribute-breadth/morphologicalRules/mrConferExcl~mrExclReader + // ordering:edge-cases/morphotactic-attribute-breadth/morphologicalRules/mrRep2~mrConferExcl + // ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/mrPhonoDestroy~mrPhXSource + // ordering:languages/suffixing-extension-slot-ordering/morphologicalRules/rrRRealTest~mrPhonoDestroy + // Named rather than absorbed, so lowering this pin means evidencing these four, not watching a + // total drift down. The inventory grew with them (332 -> 348 items), so this is the cost of new + // constructs rather than lost coverage -- but it IS a cost, and it is recorded as one. + private const int PinnedGapCount = 18; + + [Test] + public void CorpusWideGapCountNeverIncreasesFromThePinnedValue() + { + string root = RepositoryRoot(); + + // The evidenced set: read, never recomputed -- this is what makes the test cheap. + IReadOnlyList evidenceLedger = EvidenceLedger.Read(root); + var evidencedIds = evidenceLedger.Select(row => row.ItemId).ToHashSet(StringComparer.Ordinal); + + // The full inventory, built structurally with no engine sweep: 194 Surface ids from the checked-in + // Surface ledger (itself produced by a real sweep, but reading it back costs one file parse) plus + // 138 Ordering ids enumerated fresh from the checked-in grammars. + IReadOnlyList surfaceResults = CounterfactualLedger.Read(root); + IReadOnlyList orderingItems = CoverageEvidencePipeline.BuildOrderingItems(root); + + Assert.That(surfaceResults, Is.Not.Empty, "run --write-counterfactual first to populate the Surface ledger"); + Assert.That(orderingItems, Is.Not.Empty, "the corpus must declare at least one Ordering item"); + + IReadOnlyList items = CoverageEvidencePipeline + .BuildItems(surfaceResults, Array.Empty()) + .Concat(orderingItems) + .OrderBy(item => item.Id, StringComparer.Ordinal) + .ToArray(); + var itemsById = items.ToDictionary(item => item.Id, StringComparer.Ordinal); + string[] orphanedEvidenceRows = evidenceLedger + .Select(row => row.ItemId) + .Where(id => !itemsById.ContainsKey(id)) + .Distinct(StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + Assert.That( + orphanedEvidenceRows, + Is.Empty, + "evidence rows outside the generated inventory must fail independently of the gap pin" + ); + IReadOnlyList evidence = evidenceLedger + .Select(row => EvidenceLedger.ToEvidence(row, itemsById[row.ItemId])) + .ToArray(); + CoverageItem[] nonEvidencedOrdering = orderingItems.Where(item => !evidencedIds.Contains(item.Id)).ToArray(); + IReadOnlyList proofs = CoverageEvidencePipeline.BuildProofs(root, nonEvidencedOrdering); + CompletenessReport completeness = CoverageCompletenessGate.Evaluate( + items, + evidence, + proofs, + CoverageEvidencePipeline.GrammarLoader(root) + ); + Assert.That( + completeness.OrphanedEvidenceItemIds, + Is.Empty, + "evidence outside the generated inventory must fail independently of the gap pin" + ); + Assert.That( + completeness.Items.Where(result => result.Resolution == CoverageResolution.Conflicting), + Is.Empty, + "evidence/proof conflicts are stale claims, not gaps the numeric ratchet may absorb" + ); + Assert.That( + completeness.OrphanedProofItemIds, + Is.Empty, + "proofs outside the generated inventory must fail independently of the gap pin" + ); + var kindByItemId = items.ToDictionary(item => item.Id, item => item.Kind, StringComparer.Ordinal); + int surfaceGaps = completeness.Items.Count(result => + result.Resolution is CoverageResolution.Unresolved or CoverageResolution.Rejected + && kindByItemId[result.ItemId] == CoverageItemKind.Surface + ); + int orderingGaps = completeness.Items.Count(result => + result.Resolution is CoverageResolution.Unresolved or CoverageResolution.Rejected + && kindByItemId[result.ItemId] == CoverageItemKind.Ordering + ); + int totalGaps = surfaceGaps + orderingGaps; + + TestContext.Out.WriteLine( + $"total items: {surfaceResults.Count + orderingItems.Count} " + + $"(Surface {surfaceResults.Count}, Ordering {orderingItems.Count})" + ); + TestContext.Out.WriteLine( + $"gaps: {totalGaps} (Surface {surfaceGaps}, Ordering {orderingGaps}); pinned at {PinnedGapCount}" + ); + foreach ( + var group in completeness + .Items.Where(result => result.Resolution == CoverageResolution.Proven) + .GroupBy(result => result.Detail.Split(':')[0]) + .OrderByDescending(group => group.Count()) + ) + { + TestContext.Out.WriteLine($" proven ({group.Key}): {group.Count()}"); + } + TestContext.Out.WriteLine( + $" rejected: {completeness.Items.Count(result => result.Resolution == CoverageResolution.Rejected)}" + ); + TestContext.Out.WriteLine( + $" unresolved: {completeness.Items.Count(result => result.Resolution == CoverageResolution.Unresolved)}" + ); + + Assert.That( + totalGaps, + Is.LessThanOrEqualTo(PinnedGapCount), + $"corpus-wide gaps increased from the pinned {PinnedGapCount} to {totalGaps}; coverage regressed" + ); + if (totalGaps < PinnedGapCount) + { + Assert.Warn( + $"corpus-wide gaps decreased from the pinned {PinnedGapCount} to {totalGaps}; " + + $"lower CoverageGapRatchetTests.PinnedGapCount to {totalGaps}." + ); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoveragePilotCandidatesTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoveragePilotCandidatesTests.cs new file mode 100644 index 000000000..1041e4114 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/CoveragePilotCandidatesTests.cs @@ -0,0 +1,290 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Pilots five coverage-item candidates end to end against the real checked-in fixtures: a word +/// counter-example that removes a parse, one that adds a parse, a LoadFailure, a hand-constructed +/// Ordering item, and a Proof-only item. +/// +[TestFixture] +public sealed class CoveragePilotCandidatesTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static SemanticInventory Inventory() => GrammarCoverageGate.ReadInventory(RepositoryRoot()); + + private static Fixture FindFixture(string id) + { + Fixture? fixture = Fixture + .DiscoverAll(Path.Combine(RepositoryRoot(), "conformance")) + .FirstOrDefault(f => f.Id == id); + Assert.That(fixture, Is.Not.Null, $"fixture '{id}' not found"); + return fixture!; + } + + private string _scratchDirectory = string.Empty; + + [SetUp] + public void SetUp() + { + _scratchDirectory = Path.Combine(Path.GetTempPath(), "hc-coverage-pilot-tests", Guid.NewGuid().ToString("N")); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_scratchDirectory)) + Directory.Delete(_scratchDirectory, recursive: true); + } + + // Candidate 1: word counter-example, parse -> no-parse ('takul': ok::TA+KUL|takul -> ok::-). + [Test] + public void Candidate1AffixTemplatesElementRemovesAParse() + { + var item = new CoverageItem( + "dtd:element/AffixTemplates", + CoverageItemKind.Surface, + "dtd-element", + "edge-cases/loader-isactive-breadth" + ); + Fixture fixture = FindFixture(item.Fixture); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + item.Id, + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Evidenced)); + Assert.That(result.CounterexampleKind, Is.EqualTo(CounterexampleKind.Word)); + Assert.That(result.ExampleOutcome, Does.StartWith("ok::"), "the item intact must produce a real parse"); + Assert.That(result.CounterexampleOutcome, Is.EqualTo("ok::-"), "neutralizing it must lose the parse entirely"); + + Evidence evidence = Evidence.FromCounterfactualResult(item.Id, result); + CompletenessReport gate = CoverageCompletenessGate.Evaluate( + new[] { item }, + new[] { evidence }, + Array.Empty() + ); + Assert.That(gate.IsComplete, Is.True); + Assert.That(gate.EvidencedCountsByCounterexampleKind[CounterexampleKind.Word], Is.EqualTo(1)); + } + + // Candidate 2: the OTHER direction, no-parse -> parse ('sol': ok::- -> ok::SOL|sol). + [Test] + public void Candidate2AllomorphCoOccurrenceRulesElementAddsAParse() + { + var item = new CoverageItem( + "dtd:element/AllomorphCoOccurrenceRules", + CoverageItemKind.Surface, + "dtd-element", + "edge-cases/morphotactic-attribute-breadth" + ); + Fixture fixture = FindFixture(item.Fixture); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + item.Id, + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.Evidenced)); + Assert.That(result.CounterexampleKind, Is.EqualTo(CounterexampleKind.Word)); + Assert.That(result.ExampleOutcome, Is.EqualTo("ok::-"), "the item intact must have no parse for this word"); + Assert.That(result.CounterexampleOutcome, Does.StartWith("ok::"), "neutralizing it must newly admit a parse"); + + Evidence evidence = Evidence.FromCounterfactualResult(item.Id, result); + CompletenessReport gate = CoverageCompletenessGate.Evaluate( + new[] { item }, + new[] { evidence }, + Array.Empty() + ); + Assert.That(gate.IsComplete, Is.True); + Assert.That(gate.EvidencedCountsByCounterexampleKind[CounterexampleKind.Word], Is.EqualTo(1)); + } + + // Candidate 3: counterexampleKind = LoadFailure, the weaker class that must not blend into the + // Word headline. AffixTemplate is an element surface, so this fails generic DTD content-model + // validation (RequiredByDtd), not HermitCrab's own loader. + [Test] + public void Candidate3AffixTemplateElementIsRequiredByDtd() + { + var item = new CoverageItem( + "dtd:element/AffixTemplate", + CoverageItemKind.Surface, + "dtd-element", + "edge-cases/diacritic-segments" + ); + Fixture fixture = FindFixture(item.Fixture); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + CounterfactualResult result = CounterfactualGate.Evaluate( + fixture, + item.Id, + Inventory(), + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.RequiredByDtd)); + Assert.That(result.CounterexampleKind, Is.EqualTo(CounterexampleKind.LoadFailure)); + Assert.That(result.ExampleWord, Is.Not.Null); + Assert.That(result.ExampleOutcome, Does.StartWith("ok::"), "the item intact must still load and parse"); + Assert.That(result.CounterexampleOutcome, Does.Contain("Exception")); + + Evidence evidence = Evidence.FromCounterfactualResult(item.Id, result); + CompletenessReport gate = CoverageCompletenessGate.Evaluate( + new[] { item }, + new[] { evidence }, + Array.Empty() + ); + Assert.That(gate.IsComplete, Is.True); + Assert.That(gate.EvidencedCountsByCounterexampleKind[CounterexampleKind.LoadFailure], Is.EqualTo(1)); + Assert.That( + gate.EvidencedCountsByCounterexampleKind[CounterexampleKind.Word], + Is.EqualTo(0), + "a LoadFailure must never be summed into the Word count" + ); + } + + // Candidate 4: an Ordering item, hand-constructed since the OrderingGenerator does not exist yet. + // Adjacent swap of prAlpha/prHighTrigger, the two rules declared next to each other in + // feature-system-breadth's single phonologicalRules list. + [Test] + public void Candidate4OrderingItemProvesTheDataModelAgainstAHandBuiltSwap() + { + Fixture fixture = FindFixture("edge-cases/feature-system-breadth"); + string[] words = fixture.Words.Words.Select(w => w.Word).ToArray(); + Directory.CreateDirectory(_scratchDirectory); + IReadOnlyList baseline = CounterfactualGate.EvaluateOneGrammar( + fixture.GrammarPath, + WriteWordsFile(words) + ); + + XDocument mutant = XDocument.Load(fixture.GrammarPath); + XAttribute? rules = mutant + .Descendants("Stratum") + .Select(e => e.Attribute("phonologicalRules")) + .FirstOrDefault(a => a is not null); + Assert.That(rules, Is.Not.Null); + string original = rules!.Value; + Assert.That(original, Does.Contain("prAlpha prHighTrigger"), "pins the adjacency this item swaps"); + rules.Value = original.Replace("prAlpha prHighTrigger", "prHighTrigger prAlpha"); + + // No need to place a local HermitCrabInput.dtd copy beside the mutant: + // XmlLanguageLoader.ResourceXmlResolver resolves that filename to an embedded resource + // regardless of the document's own directory. + string mutatedPath = Path.Combine(_scratchDirectory, "mutated.xml"); + mutant.Save(mutatedPath); + IReadOnlyList mutated = CounterfactualGate.EvaluateOneGrammar(mutatedPath, WriteWordsFile(words)); + + var item = new CoverageItem( + "ordering:edge-cases/feature-system-breadth/phonologicalRules/prAlpha~prHighTrigger", + CoverageItemKind.Ordering, + "adjacent-transposition", + "edge-cases/feature-system-breadth" + ); + + int diffIndex = Enumerable.Range(0, words.Length).FirstOrDefault(i => baseline[i] != mutated[i], -1); + + CompletenessReport gate; + if (diffIndex >= 0) + { + var evidence = new Evidence( + item.Id, + item.Fixture, + words[diffIndex], + baseline[diffIndex], + CounterexampleKind.Word, + mutated[diffIndex], + "swapped prAlpha and prHighTrigger's declared order in phonologicalRules", + CounterfactualVerdict.Evidenced + ); + gate = CoverageCompletenessGate.Evaluate(new[] { item }, new[] { evidence }, Array.Empty()); + } + else + { + // No word discriminates the swap, so independence must be recomputed from the grammar, not + // asserted from the words. + XDocument unswapped = XDocument.Load(fixture.GrammarPath); + OrderingItem orderingItem = OrderingGenerator + .EnumerateAdjacentPairs(unswapped, item.Fixture) + .Single(candidate => candidate.Id == item.Id); + Proof? proof = OrderingProofs.TryBuild(unswapped, orderingItem); + Assert.That(proof, Is.Not.Null, "prAlpha's output and prHighTrigger's input must recompute Disjoint"); + + gate = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof! }, + loadGrammar: fixtureId => XDocument.Load(FindFixture(fixtureId).GrammarPath) + ); + } + + TestContext.Out.WriteLine( + $"candidate 4 resolved as: {gate.Items.Single().Resolution} ({gate.Items.Single().Detail})" + ); + Assert.That(gate.IsComplete, Is.True); + } + + // Candidate 5: the Proof branch -- no evidence exists and none should be manufactured. + [Test] + public void Candidate5StratumCyclicityIsProofOnly() + { + var item = new CoverageItem( + "dtd:enum/Stratum/cyclicity/cyclic", + CoverageItemKind.Surface, + "dtd-enum", + "edge-cases/morphotactic-attribute-breadth" + ); + + IReadOnlyList proofs = ImpossibilityProofs.Read(RepositoryRoot()); + ImpossibilityProof matched = proofs.Single(p => p.SurfaceId == item.Id); + var proof = new Proof(item.Id, matched.Kind, matched.Evidence); + + CompletenessReport gate = CoverageCompletenessGate.Evaluate( + new[] { item }, + Array.Empty(), + new[] { proof } + ); + Assert.That( + gate.IsComplete, + Is.False, + "the no-consumer claim remains pending until a mechanical verifier exists" + ); + Assert.That(gate.Items.Single().Resolution, Is.EqualTo(CoverageResolution.Rejected)); + + // The checked-in sweep already recorded this item Unobservable, never Evidenced: the proof is + // not stale. A proof for something the sweep now evidences must fail instead, per + // ImpossibilityProofs.Stale. + IReadOnlyList checkedInLedger = CounterfactualLedger.Read(RepositoryRoot()); + CounterfactualResult recorded = checkedInLedger.Single(r => r.SurfaceId == item.Id); + Assert.That(recorded.Verdict, Is.EqualTo(CounterfactualVerdict.Unobservable)); + } + + private string WriteWordsFile(IReadOnlyList words) + { + string path = Path.Combine(_scratchDirectory, $"words-{Guid.NewGuid():N}.txt"); + File.WriteAllLines(path, words); + return path; + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DataflowClaimGateTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DataflowClaimGateTests.cs new file mode 100644 index 000000000..5634ce8d0 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DataflowClaimGateTests.cs @@ -0,0 +1,335 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class DataflowClaimGateTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private const string SatisfiedCellId = + "MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm"; + + private static DataflowObligationLedger.Row SatisfiedRow(string cellId = SatisfiedCellId) => + new( + cellId, + "LexicalEntry", + "ruleFeatures", + "MorphologicalPhonologicalRuleFeature", + "MorphologicalInput", + "excludedMPRFeatures", + "McDc", + "PresentGatedForm", + "-", + ObligationStatus.Satisfied, + "paired witness: severing writer and reader both flip 'vokadan' from failed to successful " + + "parse in edge-cases/mpr-gated-exception (conformance/interface-witness.tsv)" + ); + + private static DataflowObligationLedger.Row UnknownStatusRow(string cellId) => + new(cellId, "A", "a", "P", "B", "b", "McDc", "AbsentControl", "-", ObligationStatus.Unknown, "no witness yet"); + + private static WordEntry PlainWord(string word, bool expectFail = false) => + new() + { + Word = word, + Note = "test fixture", + ExpectFail = expectFail, + }; + + private static WordEntry WordWithClaims(string word, params ClaimedCellEntry[] claims) + { + var entry = new WordEntry { Word = word, Note = "test fixture" }; + entry.ClaimedCells.AddRange(claims); + return entry; + } + + private static WordEntry WordWithClaims(string word, bool expectFail, params ClaimedCellEntry[] claims) + { + var entry = new WordEntry + { + Word = word, + Note = "test fixture", + ExpectFail = expectFail, + }; + entry.ClaimedCells.AddRange(claims); + return entry; + } + + private static Fixture FixtureWith(string id, params WordEntry[] words) + { + var yaml = new WordsYaml { Language = "Test" }; + yaml.Words.AddRange(words); + return new Fixture(id, "unused-directory", yaml); + } + + private static ClaimedCellEntry ReviewedClaim(string cell, string before, string after) => + new() + { + Cell = cell, + Severing = "test severing description", + Before = before, + After = after, + Proof = "test proof", + }; + + // Falsification #1: a claimed cell id that does not appear anywhere in dataflow-obligations.tsv + // must fail -- catches a typo or an id orphaned when a chain's schema shape changed. + [Test] + public void ClaimOnNonexistentCellIdFails() + { + var ledger = new[] { SatisfiedRow() }; + var fixture = FixtureWith( + "edge-cases/fake", + WordWithClaims("w1", new ClaimedCellEntry { Cell = "totally-fake-cell-id" }) + ); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + Assert.That(report.AllClaimsValid, Is.False); + DataflowClaimResult result = report.Claims.Single(); + Assert.That(result.Validity, Is.EqualTo(DataflowClaimValidity.UnknownCellId)); + } + + // Falsification #2: a claim on a cell id that DOES exist but whose ledger status is not Satisfied + // must fail -- the author intended a witness and did not get one. + [Test] + public void ClaimOnNotSatisfiedCellFails() + { + var ledger = new[] { UnknownStatusRow("cell-x") }; + var fixture = FixtureWith("edge-cases/fake", WordWithClaims("w1", new ClaimedCellEntry { Cell = "cell-x" })); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + Assert.That(report.AllClaimsValid, Is.False); + DataflowClaimResult result = report.Claims.Single(); + Assert.That(result.Validity, Is.EqualTo(DataflowClaimValidity.NotSatisfied)); + } + + // A claim on a cell id that exists AND is Satisfied passes, with no review bundle recorded -- + // recompute is never even called, since there is nothing to recompute. + [Test] + public void ClaimOnSatisfiedCellPassesUnreviewedWithNoReviewBundle() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var fixture = FixtureWith( + "edge-cases/mpr-gated-exception", + WordWithClaims("vokadan", new ClaimedCellEntry { Cell = "cell-ok" }) + ); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + Assert.That(report.AllClaimsValid, Is.True); + DataflowClaimResult result = report.Claims.Single(); + Assert.That(result.Validity, Is.EqualTo(DataflowClaimValidity.Valid)); + Assert.That(result.Review, Is.EqualTo(DataflowClaimReviewStatus.Unreviewed)); + } + + // A review bundle whose before/after matches what recomputation produces (for the unsevered + // baseline, the writer severed, and the reader severed) is Reviewed. + [Test] + public void ReviewBundleMatchingRecomputationIsReviewed() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var claim = ReviewedClaim("cell-ok", before: "ok::-", after: "ok::VOKAD+SUF|vokadan"); + var fixture = FixtureWith("edge-cases/mpr-gated-exception", WordWithClaims("vokadan", claim)); + + RecomputeSeverance recompute = (f, element, attribute, word) => + new SeveranceRecomputation(element is null ? "ok::-" : "ok::VOKAD+SUF|vokadan", null); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, recompute); + + Assert.That(report.AllClaimsValid, Is.True); + Assert.That(report.Claims.Single().Review, Is.EqualTo(DataflowClaimReviewStatus.Reviewed)); + } + + // A review bundle whose after no longer matches recomputation (the evidence moved) is Stale -- + // reported, but the claim itself still passes (staleness never fails the build by itself). + [Test] + public void ReviewBundleDisagreeingWithRecomputationIsStaleNotFailed() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var claim = ReviewedClaim("cell-ok", before: "ok::-", after: "ok::VOKAD+SUF|vokadan"); + var fixture = FixtureWith("edge-cases/mpr-gated-exception", WordWithClaims("vokadan", claim)); + + // The writer-severed recomputation now produces something different from what was claimed -- + // e.g. the fixture grew a second entry so the mutant's outcome changed. + RecomputeSeverance recompute = (f, element, attribute, word) => + element == "LexicalEntry" + ? new SeveranceRecomputation("ok::VOKAD+SUF|vokadan-different", null) + : new SeveranceRecomputation(element is null ? "ok::-" : "ok::VOKAD+SUF|vokadan", null); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, recompute); + + Assert.That(report.AllClaimsValid, Is.True, "staleness must never fail the build by itself"); + Assert.That(report.Claims.Single().Review, Is.EqualTo(DataflowClaimReviewStatus.Stale)); + } + + // A review bundle whose recomputation cannot even be attempted (e.g. the attribute no longer + // occurs in the fixture to sever) is Stale, never silently Reviewed. + [Test] + public void ReviewBundleThatCannotBeRecomputedIsStaleNotReviewed() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var claim = ReviewedClaim("cell-ok", before: "ok::-", after: "ok::VOKAD+SUF|vokadan"); + var fixture = FixtureWith("edge-cases/mpr-gated-exception", WordWithClaims("vokadan", claim)); + + RecomputeSeverance recompute = (f, element, attribute, word) => + element == "MorphologicalInput" + ? new SeveranceRecomputation(null, "attribute no longer occurs") + : new SeveranceRecomputation(element is null ? "ok::-" : "ok::VOKAD+SUF|vokadan", null); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, recompute); + + Assert.That(report.AllClaimsValid, Is.True); + Assert.That(report.Claims.Single().Review, Is.EqualTo(DataflowClaimReviewStatus.Stale)); + } + + // distinct_from, existence-plus-outcome-difference: the named word exists in the same fixture and + // its expect_fail outcome differs from the claiming word's. + [Test] + public void DistinctFromExistingWordWithDifferentOutcomeIsVerified() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var claim = new ClaimedCellEntry { Cell = "cell-ok", DistinctFrom = "control" }; + var fixture = FixtureWith( + "edge-cases/mpr-gated-exception", + WordWithClaims("vokadan", expectFail: true, claim), + PlainWord("control", expectFail: false) + ); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + DataflowClaimResult result = report.Claims.Single(); + Assert.That(result.DistinctFromVerified, Is.True); + } + + // distinct_from naming a word that does not exist in the fixture is reported unverified, never + // silently accepted. + [Test] + public void DistinctFromMissingWordIsUnverified() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var claim = new ClaimedCellEntry { Cell = "cell-ok", DistinctFrom = "nonexistent" }; + var fixture = FixtureWith("edge-cases/mpr-gated-exception", WordWithClaims("vokadan", expectFail: true, claim)); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + Assert.That(report.Claims.Single().DistinctFromVerified, Is.False); + } + + // distinct_from naming a word whose outcome does NOT differ (both fail, or both pass) fails to + // demonstrate independence and is reported unverified. + [Test] + public void DistinctFromWithSameOutcomeIsUnverified() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var claim = new ClaimedCellEntry { Cell = "cell-ok", DistinctFrom = "alsofails" }; + var fixture = FixtureWith( + "edge-cases/mpr-gated-exception", + WordWithClaims("vokadan", expectFail: true, claim), + PlainWord("alsofails", expectFail: true) + ); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + Assert.That(report.Claims.Single().DistinctFromVerified, Is.False); + } + + // The reverse direction: a Satisfied cell no word claims is reported, never failed. Uses a + // throwing recompute to also confirm recomputation is never invoked when there is nothing claimed. + [Test] + public void UnclaimedSatisfiedCellIsReportedNotFailed() + { + var ledger = new[] { SatisfiedRow("cell-ok") }; + var fixture = FixtureWith("edge-cases/mpr-gated-exception", WordWithClaims("someOtherWord")); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(new[] { fixture }, ledger, ThrowingRecompute); + + Assert.That(report.AllClaimsValid, Is.True, "an unclaimed Satisfied cell must never fail the build"); + Assert.That(report.UnclaimedSatisfiedCells, Has.Count.EqualTo(1)); + Assert.That(report.UnclaimedSatisfiedCells.Single().WitnessWord, Is.EqualTo("vokadan")); + } + + private static SeveranceRecomputation ThrowingRecompute( + Fixture fixture, + string? element, + string? attribute, + string word + ) => throw new InvalidOperationException("recompute should not be invoked when there is no review bundle to check"); + + // Falsification #3, on the real corpus, with the REAL severance recomputation (DefaultRecompute): + // the two seeded claims (edge-cases/mpr-gated-exception's 'vokadan' and + // languages/polysynthetic-stratal-derivation-chain's 'nunavuq') must validate, their inline + // before/after must actually recompute as Reviewed against the real grammars, and their + // distinct_from words must verify. Deliberately does not pin the total Satisfied-cell count or the + // unclaimed count -- both are expected to move as the concurrent mutator-class work and future + // authoring land (see this task's own "tolerate the ledger gaining rows" instruction). + [Test] + public void SeededRealClaimsValidateAndReviewAgainstTheRealCorpus() + { + string root = RepositoryRoot(); + IReadOnlyList fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + IReadOnlyList ledger = DataflowObligationLedger.Read(root); + + DataflowClaimReport report = DataflowClaimGate.Evaluate(fixtures, ledger, DataflowClaimGate.DefaultRecompute); + + Assert.That( + report.AllClaimsValid, + Is.True, + string.Join( + "\n", + report + .Claims.Where(c => c.Validity != DataflowClaimValidity.Valid) + .Select(c => $"{c.FixtureId}/{c.Word}: {c.CellId}: {c.Detail}") + ) + ); + + (string FixtureId, string Word, string CellId)[] seeded = + { + ("edge-cases/mpr-gated-exception", "vokadan", SatisfiedCellId), + ( + "languages/polysynthetic-stratal-derivation-chain", + "nunavuq", + "PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm" + ), + }; + foreach ((string fixtureId, string word, string cellId) in seeded) + { + DataflowClaimResult match = report.Claims.Single(c => + c.FixtureId == fixtureId && c.Word == word && c.CellId == cellId + ); + Assert.That(match.Validity, Is.EqualTo(DataflowClaimValidity.Valid), $"{fixtureId}/{word}"); + Assert.That( + match.Review, + Is.EqualTo(DataflowClaimReviewStatus.Reviewed), + $"{fixtureId}/{word}: {match.ReviewDetail}" + ); + Assert.That(match.DistinctFromVerified, Is.True, $"{fixtureId}/{word}: {match.DistinctFromDetail}"); + } + + TestContext.Out.WriteLine( + $"total claims={report.Claims.Count} unclaimed satisfied cells={report.UnclaimedSatisfiedCells.Count}" + ); + foreach (UnclaimedSatisfiedCell cell in report.UnclaimedSatisfiedCells) + { + TestContext.Out.WriteLine( + $" unclaimed: {cell.CellId} (witness: '{cell.WitnessWord}' in {cell.FixtureId})" + ); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DataflowObligationLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DataflowObligationLedgerTests.cs new file mode 100644 index 000000000..94484d8ba --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DataflowObligationLedgerTests.cs @@ -0,0 +1,366 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class DataflowObligationLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Pins the headline counts so a change has to be acknowledged. 40 chains x 4 McDc cells = 160 + // (every chain gates -- see DataflowObligationLedger's own doc comment for why there is no + // plain/gated split keyed off the required*/excluded* attribute-name prefix); 4 ConditionExtension + // cells (two MPR-payload chains whose exercising corpus carries a 2-condition + // requiredMPRFeatures/excludedMPRFeatures value, e.g. mpr-overwrite-order-dependence's + // "mprP mprQ"); 182 Mutator cells (91 schema-applicable (chain, ObligationMutatorClass) pairs x 2 -- + // see MutatorClassApplicabilityIsSchemaDerived for the per-class breakdown, in particular why + // CompoundingNonHeadDrop is 12 chains, not a naive 8). + [Test] + public void RealCorpusProducesTheDeclaredCellCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = DataflowObligationLedger.Compute(root); + + int mcDc = rows.Count(r => r.CellKind == "McDc"); + int conditionExtension = rows.Count(r => r.CellKind == "ConditionExtension"); + int mutator = rows.Count(r => r.CellKind == "Mutator"); + int satisfied = rows.Count(r => r.Status == ObligationStatus.Satisfied); + int notSatisfied = rows.Count(r => r.Status == ObligationStatus.NotSatisfied); + int unknown = rows.Count(r => r.Status == ObligationStatus.Unknown); + + TestContext.Out.WriteLine( + $"cells={rows.Count} mcDc={mcDc} conditionExtension={conditionExtension} mutator={mutator} " + + $"satisfied={satisfied} notSatisfied={notSatisfied} unknown={unknown}" + ); + + Assert.That(rows, Has.Count.EqualTo(346)); + Assert.That(mcDc, Is.EqualTo(160)); + Assert.That(conditionExtension, Is.EqualTo(4)); + Assert.That(mutator, Is.EqualTo(182)); + Assert.That(satisfied + notSatisfied + unknown, Is.EqualTo(rows.Count)); + // Raised 3 -> 4, unknown 165 -> 164: author-coverage-cell added 'ygofz' to + // languages/fusional-realizational-morphology/words.yaml (MorphologicalPhonologicalRuleFeature:: + // MorphologicalOutput.MPRFeatures->MorphologicalInput.requiredMPRFeatures::McDc:AbsentGatedForm). + // GOF's own lexically-preset mprPedA is destroyed by mrThemeY's Overwrite-group write before + // mrEndZ's requiredMPRFeatures gate is checked; severing either mrThemeY's own + // MorphologicalOutput.MPRFeatures write (so the overwrite never triggers) or mrEndZ's own + // requiredMPRFeatures (so the gate stops needing mprPedA) unblocks the SAME word identically. + Assert.That(satisfied, Is.EqualTo(9)); + Assert.That(notSatisfied, Is.EqualTo(120)); + Assert.That(unknown, Is.EqualTo(217)); + } + + // Mutator-class applicability is schema/engine-derived (payload type + writer + -- for + // CompoundingNonHeadDrop -- reader), never corpus-derived -- pins the exact (class -> chain count) + // mapping ApplicableMutatorClasses computes: Blocking on every chain (40), Overwrite scoped to the + // MPR-feature junction (24 chains), PosPriorityUnion scoped to the PartOfSpeech junction (15 + // chains), CompoundingNonHeadDrop scoped to all three MPR writers but ONLY the + // MorphologicalInput/PhonologicalSubrule readers (12 chains) -- engine-verified NOT to reach + // CompoundingRule.headProdRestrictionsMprFeatures/HeadMorphologicalInput's own gates (which read the + // pre-drop head state) or CompoundingRule.nonHeadProdRestrictionsMprFeatures (analysis-direction + // only, reads the lexicon entry directly), so a naive "writer is LexicalEntry.ruleFeatures" guess of + // 8 is both too narrow (misses the other two MPR writers reaching the same two readers) and too + // wide (includes four provably-inert readers). + [Test] + public void MutatorClassApplicabilityIsSchemaDerived() + { + string root = RepositoryRoot(); + IReadOnlyList rows = DataflowObligationLedger.Compute(root); + DataflowObligationLedger.Row[] mutatorRows = rows.Where(r => r.CellKind == "Mutator").ToArray(); + + (string ClassName, int ExpectedCells)[] expected = + { + ("Blocking", 80), + ("Overwrite", 48), + ("PosPriorityUnion", 30), + ("CompoundingNonHeadDrop", 24), + }; + foreach ((string className, int expectedCells) in expected) + { + int actual = mutatorRows.Count(r => r.MutatorClass == className); + Assert.That(actual, Is.EqualTo(expectedCells), $"{className} cell count"); + } + } + + // CompoundingNonHeadDrop's reader restriction, pinned directly: the writer/reader pairs it must + // (not) generate obligations for, independent of the cell-count arithmetic above. + [Test] + public void CompoundingNonHeadDropExcludesTheProvenInertReaders() + { + string root = RepositoryRoot(); + DataflowObligationLedger.Row[] cndRows = DataflowObligationLedger + .Compute(root) + .Where(r => r.MutatorClass == "CompoundingNonHeadDrop") + .ToArray(); + + var pairs = cndRows.Select(r => (r.ReaderElement, r.ReaderAttribute)).Distinct().ToArray(); + + Assert.That( + pairs, + Is.EquivalentTo( + new[] + { + ("MorphologicalInput", "requiredMPRFeatures"), + ("MorphologicalInput", "excludedMPRFeatures"), + ("PhonologicalSubrule", "requiredMPRFeatures"), + ("PhonologicalSubrule", "excludedMPRFeatures"), + } + ) + ); + Assert.That( + cndRows.Select(r => r.WriterElement).Distinct(), + Is.EquivalentTo(new[] { "LexicalEntry", "MorphologicalOutput", "CompoundingRule" }) + ); + } + + // The nine chains this generator has mechanically confirmed via a same-word PAIR witness (severing + // writer AND reader both flip the SAME word from a failed to a successful parse -- see + // DataflowObligationLedger.FindPairedWitness). Two were found by the mechanical scan (vokadan in + // mpr-gated-exception, nunavuq in polysynthetic-stratal-derivation-chain); the rest were authored. + // The recurring shape worth knowing: a feature the ROOT presets cannot witness a required-gate + // chain, because severing it can only turn a passing word into a failing one. What works is a + // feature an AFFIX confers or destroys before the reader checks it -- ygofz established that against + // MorphologicalInput, and the PhonologicalSubrule pairs reuse it against a sound-rule reader. + // Every other exercised chain stays Unknown -- deliberately: "writer witnessed somewhere, reader + // witnessed somewhere" is not this bar. + [Test] + public void SatisfiedCellsAreExactlyTheMechanicallyConfirmedPairWitnesses() + { + string root = RepositoryRoot(); + IReadOnlyList rows = DataflowObligationLedger.Compute(root); + DataflowObligationLedger.Row[] satisfied = rows.Where(r => r.Status == ObligationStatus.Satisfied).ToArray(); + + Assert.That(satisfied, Has.Length.EqualTo(9)); + Assert.That( + satisfied.Select(r => (r.WriterElement, r.WriterAttribute, r.ReaderElement, r.ReaderAttribute, r.Role)), + Is.EquivalentTo( + new[] + { + ("LexicalEntry", "ruleFeatures", "MorphologicalInput", "excludedMPRFeatures", "PresentGatedForm"), + ("LexicalEntry", "ruleFeatures", "PhonologicalSubrule", "excludedMPRFeatures", "PresentGatedForm"), + ("LexicalEntry", "partOfSpeech", "MorphologicalRule", "requiredPartsOfSpeech", "AbsentGatedForm"), + ("LexicalEntry", "partOfSpeech", "PhonologicalSubrule", "requiredPartsOfSpeech", "AbsentGatedForm"), + ( + "MorphologicalOutput", + "MPRFeatures", + "MorphologicalInput", + "excludedMPRFeatures", + "PresentGatedForm" + ), + ( + "MorphologicalOutput", + "MPRFeatures", + "MorphologicalInput", + "requiredMPRFeatures", + "AbsentGatedForm" + ), + ( + "MorphologicalOutput", + "MPRFeatures", + "PhonologicalSubrule", + "excludedMPRFeatures", + "PresentGatedForm" + ), + ( + "MorphologicalOutput", + "MPRFeatures", + "PhonologicalSubrule", + "requiredMPRFeatures", + "AbsentGatedForm" + ), + ( + "CompoundingRule", + "outputPartOfSpeech", + "MorphologicalRule", + "requiredPartsOfSpeech", + "AbsentGatedForm" + ), + } + ) + ); + Assert.That(satisfied.All(r => r.Evidence.Contains("paired witness")), Is.True); + } + + // An unexercised chain (InteractionChainLedger.Row.Exercised false) cannot witness any of its cells + // -- every McDc and Mutator cell for such a chain must be NotSatisfied, unambiguously, never Unknown. + [Test] + public void UnexercisedChainsProduceOnlyNotSatisfiedCells() + { + string root = RepositoryRoot(); + IReadOnlyList chains = InteractionChainLedger.Compute(root); + IReadOnlyList rows = DataflowObligationLedger.Compute(root); + + InteractionChainLedger.Row unexercised = chains.First(c => !c.Exercised); + DataflowObligationLedger.Row[] cellsForChain = rows.Where(r => + r.WriterElement == unexercised.WriterElement + && r.WriterAttribute == unexercised.WriterAttribute + && r.ReaderElement == unexercised.ReaderElement + && r.ReaderAttribute == unexercised.ReaderAttribute + ) + .ToArray(); + + Assert.That(cellsForChain, Is.Not.Empty); + Assert.That(cellsForChain.All(r => r.Status == ObligationStatus.NotSatisfied), Is.True); + } + + // Cell ids are unique and deterministic from (payload type, writer, reader, cell kind, role, + // mutator class) alone -- none of which move when unrelated corpus content changes, only status + // does. Regenerating twice over an unchanged DTD/engine/corpus must agree byte for byte, and no two + // distinct cells may collide. + [Test] + public void CellIdsAreUniqueAndReproducible() + { + string root = RepositoryRoot(); + IReadOnlyList first = DataflowObligationLedger.Compute(root); + IReadOnlyList second = DataflowObligationLedger.Compute(root); + + Assert.That(first.Select(r => r.CellId).Distinct().Count(), Is.EqualTo(first.Count)); + Assert.That(DataflowObligationLedger.ToText(first), Is.EqualTo(DataflowObligationLedger.ToText(second))); + } + + // Mirrors InteractionChainLedgerTests.CheckedInInteractionChainLedgerIsUpToDate: regenerate the + // ledger and require the checked-in file to match byte for byte. + [Test] + public void CheckedInDataflowObligationLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList rows = DataflowObligationLedger.Compute(root); + + string fresh = DataflowObligationLedger.ToText(rows); + string checkedIn = File.ReadAllText( + Path.Combine(root, DataflowObligationLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + fresh.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-dataflow-obligations --repository-root ." + ); + } + + // ------------------------------------------------------------------------------------------ + // MutatorClassDetectors: unit-level pins for the three structural detectors directly, independent + // of which real fixtures currently exercise them. + // ------------------------------------------------------------------------------------------ + + private const string NoFamilyGrammar = """ + + S + + a + + + + """; + + private const string FamilySameStratumGrammar = """ + + fam + + S + + a + b + + + + + """; + + private const string FamilyDifferentStrataGrammar = """ + + fam + + S1 + + a + + + S2 + + b + + + + + """; + + [Test] + public void HasEligibleFamilyRequiresTwoSiblingsUnderTheSameStratum() + { + Assert.That(MutatorClassDetectors.HasEligibleFamily(XDocument.Parse(NoFamilyGrammar)), Is.False); + Assert.That(MutatorClassDetectors.HasEligibleFamily(XDocument.Parse(FamilySameStratumGrammar)), Is.True); + Assert.That(MutatorClassDetectors.HasEligibleFamily(XDocument.Parse(FamilyDifferentStrataGrammar)), Is.False); + } + + private const string NoPosWritingRuleGrammar = """ + + S + + rA + + + + """; + + private const string TwoPosWritingRulesGrammar = """ + + S + + rA + rB + + + + """; + + [Test] + public void CountPosWritingRuleElementsCountsOnlyNonEmptyOutputPartOfSpeech() + { + Assert.That( + MutatorClassDetectors.CountPosWritingRuleElements(XDocument.Parse(NoPosWritingRuleGrammar)), + Is.EqualTo(0) + ); + Assert.That( + MutatorClassDetectors.CountPosWritingRuleElements(XDocument.Parse(TwoPosWritingRulesGrammar)), + Is.EqualTo(2) + ); + } + + private const string NoCompoundingRuleGrammar = """ + + S + + """; + + private const string HasCompoundingRuleGrammar = """ + + S + + rC + + + + """; + + [Test] + public void HasCompoundingRuleDetectsPresence() + { + Assert.That(MutatorClassDetectors.HasCompoundingRule(XDocument.Parse(NoCompoundingRuleGrammar)), Is.False); + Assert.That(MutatorClassDetectors.HasCompoundingRule(XDocument.Parse(HasCompoundingRuleGrammar)), Is.True); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DotnetMsbuildCompilationGraphLoaderTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DotnetMsbuildCompilationGraphLoaderTests.cs new file mode 100644 index 000000000..a349d6f0a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DotnetMsbuildCompilationGraphLoaderTests.cs @@ -0,0 +1,1213 @@ +using System.Collections.Immutable; +using System.Diagnostics; +using System.Text; +using System.Text.Json; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class DotnetMsbuildCompilationGraphLoaderTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // The census analyses this repository with the same Roslyn that builds it, so the compiler comes + // from the SDK rather than a NuGet package. The SDK version is a floor with latestFeature, not an + // exact patch: the graph hash it feeds is recomputed every run and compared against nothing + // checked in, so any .NET 10 SDK is self-consistent, and an exact patch is not installable + // everywhere. + [Test] + public void RepositoryPinsTheCompilerSdkAndRoslynPackage() + { + string root = RepositoryRoot(); + using JsonDocument global = JsonDocument.Parse(File.ReadAllBytes(Path.Combine(root, "global.json"))); + string project = File.ReadAllText( + Path.Combine( + root, + "src", + "SIL.Machine.Morphology.HermitCrab.Conformance", + "SIL.Machine.Morphology.HermitCrab.Conformance.csproj" + ) + ); + string references = File.ReadAllText(Path.Combine(root, "eng", "HcRoslynCompilerReferences.props")); + + Assert.Multiple(() => + { + Assert.That( + global.RootElement.GetProperty("sdk").GetProperty("version").GetString(), + Is.EqualTo("10.0.100") + ); + Assert.That( + global.RootElement.GetProperty("sdk").GetProperty("rollForward").GetString(), + Is.EqualTo("latestFeature") + ); + Assert.That(global.RootElement.GetProperty("sdk").GetProperty("allowPrerelease").GetBoolean(), Is.False); + Assert.That(project, Does.Not.Contain("PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\"")); + Assert.That(project, Does.Contain("HcRoslynCompilerReferences.props")); + Assert.That( + references, + Does.Contain("$(MSBuildToolsPath)/Roslyn/bincore/Microsoft.CodeAnalysis.CSharp.dll") + ); + }); + } + + [Test] + public void CaptureTargetDeclaresTheNativeProtocolWithoutSerializationTasks() + { + string target = File.ReadAllText(Path.Combine(RepositoryRoot(), "eng", "HcSemanticCompilerInputs.targets")); + + Assert.Multiple(() => + { + Assert.That(target, Does.Contain("_PanGlossCaptureCompilerInputs")); + Assert.That(target, Does.Contain("PanGlossCompilerInputProtocol")); + Assert.That(target, Does.Contain("hc-semantic-msbuild/v1")); + Assert.That( + target, + Does.Contain( + "ResolveReferences;ResolveKeySource;SetWin32ManifestProperties;FindReferenceAssembliesForReferences;BeforeCompile;CoreCompile" + ) + ); + Assert.That(target, Does.Not.Contain("WriteLinesToFile")); + }); + } + + [Test] + public void ProtocolParserAcceptsTheNativeEnvelopeAndPreservesItemOrder() + { + byte[] json = Encoding.UTF8.GetBytes( + """ + { + "Properties": { + "PanGlossCompilerInputProtocol": "hc-semantic-msbuild/v1", + "MSBuildAllProjects": "repo:/Machine.sln", + "AssemblyName": "hc", + "TargetFramework": "netstandard2.0", + "LangVersion": "latest", + "Nullable": "enable", + "DefineConstants": "TRACE;A", + "AllowUnsafeBlocks": "false", + "CheckForOverflowUnderflow": "false", + "OutputType": "Library", + "NETCoreSdkVersion": "10.0.303", + "MSBuildVersion": "17.0.0", + "CscToolPath": "", + "RoslynAssembliesPath": "sdk:/Roslyn", + "GeneratedAssemblyInfoFile": "tmp:/Project.AssemblyInfo.cs", + "TargetFrameworkMonikerAssemblyAttributesPath": "tmp:/.NETStandard,Version=v2.0.AssemblyAttributes.cs" + }, + "Items": { + "Compile": [ + { "Identity": "repo:/b.cs", "FullPath": "repo:/b.cs" }, + { "Identity": "repo:/a.cs", "FullPath": "repo:/a.cs" } + ], + "CscCommandLineArgs": [], + "ProjectReference": [], + "ReferencePathWithRefAssemblies": [], + "Analyzer": [], + "AdditionalFiles": [], + "EditorConfigFiles": [], + "Using": [] + } + } + """ + ); + + CapturedCompilerInputs captured = MsBuildCaptureProtocol.Parse(json); + + Assert.That( + captured.Items["Compile"].Select(item => item.Identity), + Is.EqualTo(new[] { "repo:/b.cs", "repo:/a.cs" }) + ); + Assert.That(captured.Items["Compile"][0].Metadata["FullPath"], Is.EqualTo("repo:/b.cs")); + } + + [TestCase("{}")] + [TestCase("{\"Properties\":{},\"Items\":{}}")] + [TestCase("{\"Properties\":{\"PanGlossCompilerInputProtocol\":\"wrong\"},\"Items\":{}}")] + [TestCase( + "{\"Properties\":{\"PanGlossCompilerInputProtocol\":\"hc-semantic-msbuild/v1\",\"MSBuildAllProjects\":\"x\",\"AssemblyName\":\"x\",\"TargetFramework\":\"net10.0\",\"LangVersion\":\"latest\",\"Nullable\":\"enable\",\"DefineConstants\":\"\",\"AllowUnsafeBlocks\":\"false\",\"CheckForOverflowUnderflow\":\"false\",\"OutputType\":\"Exe\",\"NETCoreSdkVersion\":\"10.0.303\",\"MSBuildVersion\":\"17\",\"CscToolPath\":\"\",\"RoslynAssembliesPath\":\"sdk:/Roslyn\",\"GeneratedAssemblyInfoFile\":\"tmp:/x.AssemblyInfo.cs\",\"TargetFrameworkMonikerAssemblyAttributesPath\":\"tmp:/.NETCoreApp,Version=v10.0.AssemblyAttributes.cs\"},\"Items\":{\"CscCommandLineArgs\":[],\"Compile\":[],\"ProjectReference\":[],\"ReferencePathWithRefAssemblies\":[],\"Analyzer\":[],\"AdditionalFiles\":[],\"EditorConfigFiles\":[],\"Using\":[],\"Mystery\":[]}}" + )] + public void ProtocolParserRejectsIncompleteOrUnknownEnvelopes(string json) + { + Assert.That( + () => MsBuildCaptureProtocol.Parse(Encoding.UTF8.GetBytes(json)), + Throws.InstanceOf() + ); + } + + [Test] + public void ProtocolParserRejectsDuplicateRequestedPropertiesAndNullItemIdentities() + { + string duplicate = + "{\"Properties\":{\"PanGlossCompilerInputProtocol\":\"hc-semantic-msbuild/v1\",\"PanGlossCompilerInputProtocol\":\"hc-semantic-msbuild/v1\"},\"Items\":{}}"; + string nullIdentity = CompleteEnvelope("[{\"Identity\":null}]"); + + Assert.Multiple(() => + { + Assert.That( + () => MsBuildCaptureProtocol.Parse(Encoding.UTF8.GetBytes(duplicate)), + Throws.InstanceOf() + ); + Assert.That( + () => MsBuildCaptureProtocol.Parse(Encoding.UTF8.GetBytes(nullIdentity)), + Throws.InstanceOf() + ); + }); + } + + [TestCase("{")] + [TestCase("{\"Properties\": null}")] + public void ProtocolParserRejectsMalformedJson(string json) + { + Assert.That( + () => MsBuildCaptureProtocol.Parse(Encoding.UTF8.GetBytes(json)), + Throws.InstanceOf() + ); + } + + [Test] + public void ProtocolParserRejectsInvalidUtf8() + { + Assert.That( + () => MsBuildCaptureProtocol.Parse(new byte[] { 0xFF, 0xFE }), + Throws.InstanceOf() + ); + } + + [Test] + public async Task LoaderUsesBoundedShellFreeQueriesAndBuildsTheSixteenNodeMatrix() + { + string root = RepositoryRoot(); + var runner = new RecordingMsBuildRunner(); + var loader = new RepositoryCompilationGraphLoader(runner, hashInputBuilder: SyntheticHashInputs); + + RepositoryCompilationGraph graph = await loader.LoadAsync(new RepositoryRoot(root), CancellationToken.None); + + Assert.That(graph.Nodes, Has.Count.EqualTo(16)); + Assert.That(graph.Captures, Has.Count.EqualTo(16)); + Assert.That( + runner.Calls, + Has.Count.EqualTo(20), + "Four base-property evaluations plus sixteen profile queries are required." + ); + Assert.Multiple(() => + { + Assert.That(runner.Calls.All(call => !call.StartInfo.UseShellExecute), Is.True); + Assert.That(runner.Calls.All(call => call.StartInfo.WorkingDirectory == Path.GetFullPath(root)), Is.True); + Assert.That(runner.Calls.All(call => call.Timeout == TimeSpan.FromSeconds(120)), Is.True); + Assert.That(runner.Calls.All(call => call.MaxOutputBytes == 64 * 1024 * 1024), Is.True); + Assert.That( + runner + .Calls.Where(call => call.StartInfo.ArgumentList.Contains("/t:_PanGlossCaptureCompilerInputs")) + .All(call => + !call.StartInfo.ArgumentList.Contains("/restore") + && !call.StartInfo.ArgumentList.Contains("--restore") + && call.StartInfo.ArgumentList.Contains("/nr:false") + && call.StartInfo.ArgumentList.Contains("/p:BuildProjectReferences=false") + && call.StartInfo.ArgumentList.Any(argument => + argument.StartsWith("/p:ProjectAssetsFile=", StringComparison.Ordinal) + ) + ), + Is.True + ); + Assert.That( + runner + .Calls.Where(call => call.StartInfo.ArgumentList.Contains("/t:_PanGlossCaptureCompilerInputs")) + .All(call => + call.StartInfo.ArgumentList.Any(argument => + argument.StartsWith("/p:IntermediateOutputPath=", StringComparison.Ordinal) + ) + ), + Is.True + ); + Assert.That( + runner + .Calls.SelectMany(call => call.StartInfo.ArgumentList) + .Any(argument => argument == "/p:DefineConstants=OUTPUT_ANALYSES%3BSINGLE_THREADED%3BTRACE"), + Is.True + ); + }); + } + + private static CompilationGraphHashInputs SyntheticHashInputs(CompilationGraphHashEnvironment environment) + { + RepositoryCompilationGraph graph = environment.Graph; + GraphHashFile captureTarget = HashFile("repo:/eng/HcSemanticCompilerInputs.targets", "synthetic-target"); + return new CompilationGraphHashInputs( + "hc-compilation-graph/v1", + graph + .Projects.Select(project => new ProjectHashInput( + project.Id, + $"repo:/{project.RelativePath}", + project.TargetFramework + )) + .ToArray(), + graph.Profiles.Select(profile => new ProfileHashInput(profile.Id, profile.AdditionalSymbols)).ToArray(), + graph + .Nodes.Select( + (node, ordinal) => + new NodeHashInput( + node.Key, + new Dictionary { ["synthetic"] = "true" }, + Array.Empty(), + new[] + { + new OrderedGraphHashFile( + 0, + HashFile( + $"generated:/{node.ProjectId}/{node.Profile.Id}/source.cs", + $"// {ordinal}" + ) + ), + }, + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty(), + Array.Empty() + ) + ) + .ToArray(), + graph.ProjectEdges, + new ToolchainHashInput( + "synthetic-sdk", + "synthetic-msbuild", + "synthetic-roslyn", + "synthetic-compiler", + "synthetic-loader", + new[] { HashFile("sdk:/synthetic/compiler.dll", "synthetic-toolchain", GraphHashFileKind.Binary) } + ), + captureTarget, + new OptionalGraphHashFile(false, null) + ); + } + + private static GraphHashFile HashFile( + string logicalPath, + string content, + GraphHashFileKind kind = GraphHashFileKind.Text + ) => new(logicalPath, ImmutableArray.CreateRange(Encoding.UTF8.GetBytes(content)), kind); + + [TestCase(7, "", TestName = "LoaderRejectsNonzeroExit")] + [TestCase(0, "warning", TestName = "LoaderRejectsStandardError")] + public void LoaderRejectsUncleanProcessResults(int exitCode, string standardError) + { + var runner = new RecordingMsBuildRunner( + (_, _) => + new ProcessCapture( + exitCode, + Encoding.UTF8.GetBytes( + "{\"Properties\":{\"DefineConstants\":\"TRACE\",\"TargetFramework\":\"netstandard2.0\"}}" + ), + standardError + ) + ); + var loader = new RepositoryCompilationGraphLoader(runner); + + Assert.That( + async () => await loader.LoadAsync(new RepositoryRoot(RepositoryRoot()), CancellationToken.None), + Throws.TypeOf() + ); + } + + [Test] + public void LoaderRejectsOversizedOutputAndProtocolMismatch() + { + var oversized = new RecordingMsBuildRunner( + (_, _) => + new ProcessCapture(0, new byte[RepositoryCompilationGraphLoader.MaximumStandardOutputBytes + 1], "") + ); + var mismatched = new RecordingMsBuildRunner( + (start, call) => + { + if (call < 4) + { + return new ProcessCapture( + 0, + Encoding.UTF8.GetBytes( + $"{{\"Properties\":{{\"DefineConstants\":\"TRACE\",\"TargetFramework\":\"{ArgumentValue(start, "/p:TargetFramework=")}\"}}}}" + ), + "" + ); + } + string target = ArgumentValue(start, "/p:TargetFramework="); + return new ProcessCapture( + 0, + Encoding.UTF8.GetBytes( + CompleteEnvelope("[]", target) + .Replace("hc-semantic-msbuild/v1", "hc-semantic-msbuild/v2", StringComparison.Ordinal) + ), + "" + ); + } + ); + + Assert.Multiple(() => + { + Assert.That( + async () => + await new RepositoryCompilationGraphLoader(oversized).LoadAsync( + new RepositoryRoot(RepositoryRoot()), + CancellationToken.None + ), + Throws.TypeOf() + ); + Assert.That( + async () => + await new RepositoryCompilationGraphLoader(mismatched).LoadAsync( + new RepositoryRoot(RepositoryRoot()), + CancellationToken.None + ), + Throws.TypeOf() + ); + }); + } + + [Test] + public void LoaderPropagatesTimeoutAndTerminationFailures() + { + var timeout = new RecordingMsBuildRunner((_, _) => throw new InvalidDataException("timeout")); + var termination = new RecordingMsBuildRunner( + (_, _) => throw new InvalidDataException("termination unconfirmed") + ); + + Assert.Multiple(() => + { + Assert.That( + async () => + await new RepositoryCompilationGraphLoader(timeout).LoadAsync( + new RepositoryRoot(RepositoryRoot()), + CancellationToken.None + ), + Throws.TypeOf() + ); + Assert.That( + async () => + await new RepositoryCompilationGraphLoader(termination).LoadAsync( + new RepositoryRoot(RepositoryRoot()), + CancellationToken.None + ), + Throws.TypeOf() + ); + }); + } + + [Test] + public void LoaderFailsBeforeProcessExecutionWhenRestoredAssetsAreMissing() + { + string scratch = Path.Combine(Path.GetTempPath(), "hc-missing-assets", Guid.NewGuid().ToString("N")); + try + { + Directory.CreateDirectory(Path.Combine(scratch, "eng")); + Directory.CreateDirectory(Path.Combine(scratch, "src", "SIL.Machine")); + File.WriteAllText(Path.Combine(scratch, "eng", "HcSemanticCompilerInputs.targets"), ""); + File.WriteAllText( + Path.Combine(scratch, "src", "SIL.Machine", "SIL.Machine.csproj"), + "" + ); + var runner = new RecordingMsBuildRunner(); + + Assert.That( + async () => + await new RepositoryCompilationGraphLoader(runner).LoadAsync( + new RepositoryRoot(scratch), + CancellationToken.None + ), + Throws.TypeOf() + ); + Assert.That(runner.Calls, Is.Empty); + } + finally + { + if (Directory.Exists(scratch)) + Directory.Delete(scratch, recursive: true); + } + } + + [Test] + public void ProcessRunnerEnforcesTheOutputLimitWithoutUsingAShell() + { + var start = new ProcessStartInfo + { + FileName = "dotnet", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }; + start.ArgumentList.Add("--info"); + + Assert.That( + async () => + await new MsBuildProcessRunner().RunAsync( + start, + TimeSpan.FromSeconds(30), + maxStandardOutputBytes: 1, + CancellationToken.None + ), + Throws.TypeOf() + ); + } + + // cancellationToken must be threaded all the way into LoadAsync: MsBuildProcessRunner already kills + // its child's whole process tree on cancellation (see TryTerminate), but only for the token it is + // actually given -- passing CancellationToken.None here would silently disconnect [CancelAfter] from + // that kill path and leave a live `dotnet msbuild` running past a cancelled or timed-out test. + [Test] + [CancelAfter(120_000)] + public async Task LiveLoaderCapturesEveryRestoredNodeWithoutRepositoryWrites(CancellationToken cancellationToken) + { + string root = RepositoryRoot(); + IReadOnlyDictionary before = RepositoryFileStamps(root); + + RepositoryCompilationGraph graph = await new RepositoryCompilationGraphLoader( + new MsBuildProcessRunner() + ).LoadAsync(new RepositoryRoot(root), cancellationToken); + + CapturedCompilerInputs firstCapture = graph + .Captures.OrderBy(pair => pair.Key.ProjectId, StringComparer.Ordinal) + .First() + .Value; + string compatibilitySource = Path.Combine(root, "src", "SIL.Machine", "Utils", "StringExtensions.cs"); + Assert.That(File.Exists(compatibilitySource), Is.True); + Assert.DoesNotThrow(() => + CSharpCommandLineInputParser.Parse( + new[] { "/out:compatibility.dll", compatibilitySource }, + Path.GetDirectoryName(compatibilitySource)!, + queriedToolchain: new CompilerToolchainIdentity(firstCapture.Properties["RoslynAssembliesPath"]) + ) + ); + + IReadOnlyDictionary after = RepositoryFileStamps(root); + Assert.Multiple(() => + { + Assert.That(graph.Captures, Has.Count.EqualTo(16)); + Assert.That(graph.CompilerInputs, Has.Count.EqualTo(16)); + Assert.That(graph.CompilerInputs.All(pair => pair.Value.Sources.Count > 0), Is.True); + Assert.That( + graph.CompilerInputs.All(pair => pair.Value.Sources.All(source => source.Content.Length > 0)), + Is.True + ); + Assert.That(graph.CompilerInputs.All(pair => pair.Value.AnalyzerConfigs.Count > 0), Is.True); + Assert.That( + graph.CompilerInputs.All(pair => pair.Value.AnalyzerConfigs.All(config => config.Content.Length > 0)), + Is.True + ); + Assert.That( + graph.CompilerInputs.All(pair => pair.Value.AnalyzerConfigs.Any(config => !File.Exists(config.Path))), + Is.True, + "Each node must retain its private generated analyzer configuration after capture cleanup." + ); + Assert.That( + graph + .CompilerInputs.Where(pair => pair.Key.TargetFramework == "net10.0") + .All(pair => + pair.Value.Analyzers.Count(analyzer => + analyzer.Disposition == AnalyzerDisposition.SdkOwnedSourceGeneratorPendingProbe + ) == 5 + ), + Is.True + ); + Assert.That( + graph + .CompilerInputs.Where(pair => pair.Key.TargetFramework == "netstandard2.0") + .All(pair => + pair.Value.Analyzers.All(analyzer => analyzer.Disposition == AnalyzerDisposition.Ordinary) + ), + Is.True + ); + Assert.That( + graph.Captures.All(pair => + pair.Value.Properties["PanGlossCompilerInputProtocol"] == MsBuildCaptureProtocol.Version + ), + Is.True + ); + Assert.That( + graph.Captures.All(pair => pair.Value.Properties["TargetFramework"] == pair.Key.TargetFramework), + Is.True + ); + Assert.That(graph.Captures.All(pair => pair.Value.Items["CscCommandLineArgs"].Count > 0), Is.True); + Assert.That(graph.HashInputs.SchemaVersion, Is.EqualTo("hc-compilation-graph/v1")); + Assert.That(graph.HashInputs.Nodes, Has.Length.EqualTo(16)); + Assert.That(graph.HashInputs.Nodes.All(node => node.Sources.Length > 0), Is.True); + Assert.That( + graph.HashInputs.Nodes.All(node => node.Assets.Length >= 3), + Is.True, + "Assets JSON and generated NuGet props/targets must be retained before hashing." + ); + Assert.That(graph.HashInputs.Nodes.All(node => node.Imports.Length > 0), Is.True); + Assert.That( + graph + .HashInputs.Nodes.Where(node => node.Key.ProjectId != "machine") + .All(node => node.ProjectReferences.Length > 0), + Is.True + ); + Assert.That(graph.HashInputs.Nodes.All(node => node.References.Length > 0), Is.True); + Assert.That(graph.HashInputs.Toolchain.Files, Is.Not.Empty); + Assert.That(graph.HashInputs.Toolchain.LoaderIdentity, Is.Not.Empty); + Assert.That(graph.Hashes, Is.EqualTo(CompilationGraphHashing.Compute(graph.HashInputs))); + Assert.That( + new[] { graph.Hashes.GraphInputHash, graph.Hashes.ToolchainHash, graph.Hashes.GraphHash }.All(hash => + hash.Length == 64 && hash.All(character => char.IsAsciiHexDigitLower(character)) + ), + Is.True + ); + Assert.That(CanonicalJson.Serialize(graph.HashInputs), Does.Not.Contain(Path.GetFullPath(root))); + Assert.That(after, Is.EqualTo(before), "Compiler-input capture must not write inside the repository."); + }); + } + + [Test] + public void CommandLineParserPreservesRoslynOptionsReferencesAndAuxiliaryInputs() + { + string root = RepositoryRoot(); + string source = Path.Combine(root, "src", "SIL.Machine", "Utils", "StringExtensions.cs"); + string additionalFile = Path.Combine(root, "conformance", "constructs.txt"); + string reference = typeof(object).Assembly.Location; + string analyzer = typeof(CSharpCompilation).Assembly.Location; + var args = new[] + { + $"/define:TRACE;BASE;SINGLE_THREADED;OUTPUT_ANALYSES", + "/langversion:preview", + "/nullable:enable", + "/unsafe+", + "/checked+", + "/reference:Alias=" + reference, + "/link:" + reference, + "/analyzer:" + analyzer, + "/additionalfile:" + additionalFile, + "/analyzerconfig:.editorconfig", + "/out:out.dll", + source, + }; + + CompilerInputModel model = CSharpCommandLineInputParser.Parse( + args, + root, + new[] { "OUTPUT_ANALYSES" }, + new CompilerToolchainIdentity(Path.GetDirectoryName(typeof(CSharpCommandLineParser).Assembly.Location)!) + ); + + Assert.Multiple(() => + { + Assert.That( + ((CSharpParseOptions)model.Arguments.ParseOptions).LanguageVersion, + Is.EqualTo(LanguageVersion.Preview) + ); + Assert.That( + ((CSharpCompilationOptions)model.Arguments.CompilationOptions).NullableContextOptions, + Is.EqualTo(NullableContextOptions.Enable) + ); + Assert.That(((CSharpCompilationOptions)model.Arguments.CompilationOptions).AllowUnsafe, Is.True); + Assert.That(model.Arguments.CompilationOptions.CheckOverflow, Is.True); + Assert.That(model.Arguments.MetadataReferences, Has.Length.EqualTo(2)); + Assert.That(model.Arguments.MetadataReferences[0].Properties.Aliases, Does.Contain("Alias")); + Assert.That( + model + .Arguments.MetadataReferences.Single(item => item.Properties.EmbedInteropTypes) + .Properties.EmbedInteropTypes, + Is.True + ); + Assert.That(model.Arguments.SourceFiles.Select(file => file.Path), Is.EqualTo(new[] { source })); + Assert.That(model.Arguments.AnalyzerReferences, Has.Length.EqualTo(1)); + Assert.That( + model.Arguments.AdditionalFiles.Select(file => file.Path), + Is.EqualTo(new[] { additionalFile }) + ); + Assert.That(model.Arguments.AnalyzerConfigPaths, Is.EqualTo(new[] { Path.Combine(root, ".editorconfig") })); + Assert.That(model.AdditionalFiles.Single().Path, Is.EqualTo(additionalFile)); + Assert.That(model.AdditionalFiles.Single().Content, Is.Not.Empty); + Assert.That(model.AnalyzerConfigs.Single().Path, Is.EqualTo(Path.Combine(root, ".editorconfig"))); + Assert.That(model.AnalyzerConfigs.Single().Content, Is.Not.Empty); + Assert.That(model.Symbols, Is.EqualTo(new[] { "BASE", "OUTPUT_ANALYSES", "SINGLE_THREADED", "TRACE" })); + Assert.That( + ((CSharpParseOptions)model.Arguments.ParseOptions).PreprocessorSymbolNames, + Is.SupersetOf(new[] { "OUTPUT_ANALYSES", "SINGLE_THREADED" }) + ); + }); + } + + [TestCase("/unknown-switch", "unknown-compiler-switch")] + [TestCase("/reference:a,b=missing.dll", "reference-parser-diagnostic")] + public void CommandLineParserFailsClosedOnDiagnostics(string argument, string code) + { + CompilerInputException exception = Assert.Throws(() => + CSharpCommandLineInputParser.Parse(new[] { argument }, RepositoryRoot()) + )!; + + Assert.That(exception.Code, Is.EqualTo(code), exception.Message); + } + + [Test] + public void CommandLineParserRejectsProfileSymbolsMissingFromFinalParseOptions() + { + CompilerInputException exception = Assert.Throws(() => + CSharpCommandLineInputParser.Parse( + new[] + { + "/define:TRACE", + "/out:test.dll", + Path.Combine(RepositoryRoot(), "src", "SIL.Machine", "Utils", "StringExtensions.cs"), + }, + RepositoryRoot(), + new[] { "OUTPUT_ANALYSES" } + ) + )!; + + Assert.That(exception.Code, Is.EqualTo("compiler-profile-symbol-mismatch")); + } + + [Test] + public void SourceClassifierAdmitsOnlyOwnedAndKnownSdkGeneratedSupport() + { + string root = RepositoryRoot(); + string project = Path.Combine(root, "src", "Project"); + string intermediate = Path.Combine(project, "obj", "Debug", "net10.0"); + string assemblyInfo = Path.Combine(intermediate, "Project.AssemblyInfo.cs"); + string net10Attributes = Path.Combine(intermediate, ".NETCoreApp,Version=v10.0.AssemblyAttributes.cs"); + string netstandardAttributes = Path.Combine(intermediate, ".NETStandard,Version=v2.0.AssemblyAttributes.cs"); + var classifier = new CompilerSourceClassifier(root, project, intermediate, assemblyInfo, net10Attributes); + var netstandardClassifier = new CompilerSourceClassifier( + root, + project, + intermediate, + assemblyInfo, + netstandardAttributes + ); + + Assert.Multiple(() => + { + Assert.That(classifier.Classify(Path.Combine(project, "Owned.cs")), Is.EqualTo(CompilerSourceKind.Owned)); + Assert.That(classifier.Classify(assemblyInfo), Is.EqualTo(CompilerSourceKind.GeneratedSupport)); + Assert.That(classifier.Classify(net10Attributes), Is.EqualTo(CompilerSourceKind.GeneratedSupport)); + Assert.That( + netstandardClassifier.Classify(netstandardAttributes), + Is.EqualTo(CompilerSourceKind.GeneratedSupport) + ); + Assert.That( + () => classifier.Classify(Path.Combine(intermediate, "Evil.AssemblyInfo.cs")), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-compiler-source") + ); + Assert.That( + () => classifier.Classify(Path.Combine(intermediate, ".Spoof,Version=v999.AssemblyAttributes.cs")), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-compiler-source") + ); + Assert.That( + () => classifier.Classify(Path.Combine(intermediate, "Custom.Generated.cs")), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-compiler-source") + ); + Assert.That( + () => + classifier.Classify( + Path.Combine(project, "Generated.cs"), + new Dictionary { ["AutoGen"] = "true" } + ), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-compiler-source") + ); + Assert.That( + () => classifier.Classify(Path.Combine(project, "obj", "Generated.cs")), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-compiler-source") + ); + Assert.That( + () => classifier.Classify(Path.Combine(project, "GlobalUsings.g.cs")), + Throws + .TypeOf() + .With.Property("Code") + .EqualTo("unsupported-implicit-global-using") + ); + Assert.That( + () => classifier.Classify(Path.Combine(root, "outside.cs")), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-compiler-source") + ); + }); + } + + [Test] + public void AnalyzerInspectorRecordsProvenanceAndRejectsUnownedSourceGenerators() + { + string path = typeof(CSharpCompilation).Assembly.Location; + AnalyzerMetadataInspection inspection = AnalyzerMetadataInspector.Inspect(path); + Assert.That(inspection.IsSourceGenerator, Is.False); + Assert.That(inspection.LoadedAssembly, Is.False); + Assert.That(inspection.Disposition, Is.EqualTo(AnalyzerDisposition.Ordinary)); + Assert.That(inspection.AssemblyIdentity, Does.Contain("Microsoft.CodeAnalysis")); + Assert.That(inspection.Sha256, Has.Length.EqualTo(64)); + Assert.That(inspection.ReferencePackVersion, Is.Null); + + string generatorPath = EmitSyntheticGenerator(); + try + { + AnalyzerMetadataInspection generator = AnalyzerMetadataInspector.Inspect(generatorPath); + Assert.That(generator.IsSourceGenerator, Is.True); + Assert.That(generator.LoadedAssembly, Is.False); + Assert.That(generator.Disposition, Is.EqualTo(AnalyzerDisposition.Ordinary)); + Assert.That(generator.ReferencePackVersion, Is.Null); + Assert.That(generator.Sha256, Has.Length.EqualTo(64)); + + CompilerInputException parserException = Assert.Throws(() => + CSharpCommandLineInputParser.Parse( + new[] + { + $"/analyzer:{generatorPath}", + "/out:test.dll", + Path.Combine(RepositoryRoot(), "src", "SIL.Machine", "Utils", "StringExtensions.cs"), + }, + RepositoryRoot() + ) + )!; + Assert.That(parserException.Code, Is.EqualTo("unsupported-source-generator")); + + string spoofPath = Path.Combine( + Path.GetTempPath(), + "packs", + "Microsoft.NETCore.App.Ref", + "10.0.11", + "analyzers", + "dotnet", + "cs-spoof", + "Microsoft.Interop.LibraryImportGenerator.dll" + ); + Directory.CreateDirectory(Path.GetDirectoryName(spoofPath)!); + try + { + File.Copy(generatorPath, spoofPath, overwrite: true); + AnalyzerMetadataInspection spoof = AnalyzerMetadataInspector.Inspect(spoofPath); + Assert.That(spoof.IsSourceGenerator, Is.True); + Assert.That(spoof.Disposition, Is.EqualTo(AnalyzerDisposition.Ordinary)); + Assert.That(spoof.ReferencePackVersion, Is.Null); + Assert.That( + () => + CSharpCommandLineInputParser.Parse( + new[] + { + $"/analyzer:{spoofPath}", + "/out:test.dll", + Path.Combine(RepositoryRoot(), "src", "SIL.Machine", "Utils", "StringExtensions.cs"), + }, + RepositoryRoot() + ), + Throws + .TypeOf() + .With.Property("Code") + .EqualTo("unsupported-source-generator") + ); + } + finally + { + if (File.Exists(spoofPath)) + File.Delete(spoofPath); + } + + string admittedDirectory = Path.Combine( + Path.GetTempPath(), + "admitted-sdk", + "packs", + "Microsoft.NETCore.App.Ref", + "10.0.11", + "analyzers", + "dotnet", + "cs" + ); + string admittedPath = Path.Combine(admittedDirectory, "Microsoft.Interop.LibraryImportGenerator.dll"); + string admittedGenerator = EmitSyntheticGenerator("Microsoft.Interop.LibraryImportGenerator"); + Directory.CreateDirectory(admittedDirectory); + try + { + File.Copy(admittedGenerator, admittedPath, overwrite: true); + AnalyzerMetadataInspection admitted = AnalyzerMetadataInspector.Inspect( + admittedPath, + new[] { admittedDirectory } + ); + Assert.That(admitted.Disposition, Is.EqualTo(AnalyzerDisposition.SdkOwnedSourceGeneratorPendingProbe)); + Assert.That(admitted.ReferencePackVersion, Is.EqualTo("10.0.11")); + Assert.That(admitted.Sha256, Does.Match("^[0-9a-f]{64}$")); + } + finally + { + File.Delete(admittedGenerator); + if (File.Exists(admittedPath)) + File.Delete(admittedPath); + } + + string helperPath = Path.Combine( + Path.GetTempPath(), + "packs", + "Microsoft.NETCore.App.Ref", + "10.0.11", + "analyzers", + "dotnet", + "cs", + "Microsoft.Interop.SourceGeneration.dll" + ); + try + { + Directory.CreateDirectory(Path.GetDirectoryName(helperPath)!); + File.Copy(path, helperPath, overwrite: true); + AnalyzerMetadataInspection helper = AnalyzerMetadataInspector.Inspect(helperPath); + Assert.That(helper.IsSourceGenerator, Is.False); + Assert.That(helper.Disposition, Is.EqualTo(AnalyzerDisposition.Ordinary)); + Assert.That(helper.ReferencePackVersion, Is.EqualTo("10.0.11")); + } + finally + { + if (File.Exists(helperPath)) + File.Delete(helperPath); + } + } + finally + { + File.Delete(generatorPath); + } + + string inheritedGeneratorPath = EmitInheritedRegisteredGenerator(); + try + { + AnalyzerMetadataInspection inherited = AnalyzerMetadataInspector.Inspect(inheritedGeneratorPath); + Assert.That(inherited.IsSourceGenerator, Is.True); + Assert.That( + () => + CSharpCommandLineInputParser.Parse( + new[] + { + $"/analyzer:{inheritedGeneratorPath}", + "/out:test.dll", + Path.Combine(RepositoryRoot(), "src", "SIL.Machine", "Utils", "StringExtensions.cs"), + }, + RepositoryRoot() + ), + Throws.TypeOf().With.Property("Code").EqualTo("unsupported-source-generator") + ); + } + finally + { + File.Delete(inheritedGeneratorPath); + } + + Assert.That( + () => AnalyzerMetadataInspector.Inspect(Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".dll")), + Throws.TypeOf().With.Property("Code").EqualTo("analyzer-metadata-diagnostic") + ); + } + + [Test] + public void CompilerIdentityMismatchIsReportedBeforeParsing() + { + string parser = typeof(CSharpCommandLineParser).Assembly.Location; + string other = Path.GetDirectoryName(typeof(object).Assembly.Location)!; + + CompilerInputException exception = Assert.Throws(() => + CSharpCommandLineInputParser.Parse( + new[] { "/unknown-switch" }, + RepositoryRoot(), + Array.Empty(), + new CompilerToolchainIdentity(other) + ) + )!; + + Assert.That(exception.Code, Is.EqualTo("incompatible-compiler-toolchain")); + Assert.That(exception.Message, Does.Contain(parser)); + } + + [Test] + public void CompilerIdentityRequiresAnAbsoluteCompilerDirectory() + { + CompilerInputException exception = Assert.Throws(() => + CSharpCommandLineInputParser.Parse( + Array.Empty(), + RepositoryRoot(), + queriedToolchain: new CompilerToolchainIdentity("relative") + ) + )!; + + Assert.That(exception.Code, Is.EqualTo("incompatible-compiler-toolchain")); + } + + [Test] + public void PrivateGeneratedSourceRejectsAFileSymlink() + { + string privateRoot = Path.Combine(Path.GetTempPath(), "hc-generated-source-test", Guid.NewGuid().ToString("N")); + string intermediate = Path.Combine(privateRoot, "node"); + string external = Path.Combine(Path.GetTempPath(), $"hc-generated-external-{Guid.NewGuid():N}.cs"); + string link = Path.Combine(intermediate, "Project.AssemblyInfo.cs"); + Directory.CreateDirectory(intermediate); + File.WriteAllText(external, "// external"); + try + { + try + { + File.CreateSymbolicLink(link, external); + } + catch (Exception exception) + when (exception is UnauthorizedAccessException or IOException or PlatformNotSupportedException) + { + Assert.Ignore($"This host cannot create a file symlink: {exception.Message}"); + } + + Assert.That( + () => RepositoryCompilationGraphLoader.ValidatePrivateGeneratedFile(privateRoot, intermediate, link), + Throws.TypeOf() + ); + } + finally + { + if (File.Exists(link)) + File.Delete(link); + if (File.Exists(external)) + File.Delete(external); + if (Directory.Exists(intermediate)) + Directory.Delete(intermediate); + if (Directory.Exists(privateRoot)) + Directory.Delete(privateRoot); + } + } + + private sealed class RecordingMsBuildRunner : IMsBuildProcessRunner + { + private readonly Func? _result; + + internal RecordingMsBuildRunner(Func? result = null) + { + _result = result; + } + + internal List Calls { get; } = new(); + + public ValueTask RunAsync( + ProcessStartInfo startInfo, + TimeSpan timeout, + int maxStandardOutputBytes, + CancellationToken cancellationToken + ) + { + Calls.Add(new MsBuildCall(startInfo, timeout, maxStandardOutputBytes)); + if (_result is not null) + return ValueTask.FromResult(_result(startInfo, Calls.Count - 1)); + if ( + startInfo.ArgumentList.Any(argument => + argument.StartsWith("-getProperty:DefineConstants", StringComparison.Ordinal) + ) + ) + { + string evaluatedTarget = ArgumentValue(startInfo, "/p:TargetFramework="); + return ValueTask.FromResult( + new ProcessCapture( + 0, + Encoding.UTF8.GetBytes( + $"{{\"Properties\":{{\"DefineConstants\":\"TRACE\",\"TargetFramework\":\"{evaluatedTarget}\"}}}}" + ), + "" + ) + ); + } + + string target = ArgumentValue(startInfo, "/p:TargetFramework="); + string roslynDirectory = Path.GetDirectoryName(typeof(CSharpCommandLineParser).Assembly.Location)!; + string projectFile = startInfo.ArgumentList.Single(argument => + argument.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) + ); + string projectDirectory = Path.GetDirectoryName(projectFile)!; + string source = Directory + .EnumerateFiles(projectDirectory, "*.cs", SearchOption.AllDirectories) + .First(path => + !path.Contains( + $"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", + StringComparison.OrdinalIgnoreCase + ) + && !path.Contains( + $"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", + StringComparison.OrdinalIgnoreCase + ) + ); + string compileItems = JsonSerializer.Serialize(new[] { new { Identity = source, FullPath = source } }); + string commandLineItems = JsonSerializer.Serialize( + new[] + { + new + { + Identity = "/define:" + + ArgumentValue(startInfo, "/p:DefineConstants=") + .Replace("%3B", ";", StringComparison.Ordinal), + }, + new { Identity = "/out:test.dll" }, + new { Identity = source }, + } + ); + string intermediate = ArgumentValue(startInfo, "/p:IntermediateOutputPath="); + string generatedAssemblyInfo = Path.Combine( + intermediate, + $"{Path.GetFileNameWithoutExtension(projectFile)}.AssemblyInfo.cs" + ); + string frameworkAttributes = Path.Combine( + intermediate, + target == "net10.0" + ? ".NETCoreApp,Version=v10.0.AssemblyAttributes.cs" + : ".NETStandard,Version=v2.0.AssemblyAttributes.cs" + ); + File.WriteAllText(generatedAssemblyInfo, "// generated assembly info"); + File.WriteAllText(frameworkAttributes, "// generated framework attributes"); + return ValueTask.FromResult( + new ProcessCapture( + 0, + Encoding.UTF8.GetBytes( + CompleteEnvelope( + compileItems, + target, + roslynDirectory, + commandLineItems, + generatedAssemblyInfo, + frameworkAttributes + ) + ), + "" + ) + ); + } + } + + private static string EmitSyntheticGenerator(string assemblyName = "SyntheticGenerator") + { + const string Source = """ + using Microsoft.CodeAnalysis; + [Generator] + public sealed class SyntheticGenerator : ISourceGenerator + { + public void Initialize(GeneratorInitializationContext context) { } + public void Execute(GeneratorExecutionContext context) { } + } + """; + string path = Path.Combine(Path.GetTempPath(), $"synthetic-generator-{Guid.NewGuid():N}.dll"); + CSharpCompilation compilation = CSharpCompilation.Create( + assemblyName, + new[] { CSharpSyntaxTree.ParseText(Source) }, + CSharpCompilationProfile.Create().CreateMetadataReferences(), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + using FileStream output = File.Create(path); + var result = compilation.Emit(output); + Assert.That(result.Success, Is.True, string.Join(Environment.NewLine, result.Diagnostics)); + return path; + } + + private static string EmitInheritedRegisteredGenerator() + { + const string Source = """ + using Microsoft.CodeAnalysis; + public abstract class GeneratorBase : ISourceGenerator + { + public void Initialize(GeneratorInitializationContext context) { } + public void Execute(GeneratorExecutionContext context) { } + } + [Generator] + public sealed class InheritedGenerator : GeneratorBase { } + """; + string path = Path.Combine(Path.GetTempPath(), $"inherited-generator-{Guid.NewGuid():N}.dll"); + CSharpCompilation compilation = CSharpCompilation.Create( + "InheritedGenerator", + new[] { CSharpSyntaxTree.ParseText(Source) }, + CSharpCompilationProfile.Create().CreateMetadataReferences(), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + using FileStream output = File.Create(path); + var result = compilation.Emit(output); + Assert.That(result.Success, Is.True, string.Join(Environment.NewLine, result.Diagnostics)); + return path; + } + + private sealed record MsBuildCall(ProcessStartInfo StartInfo, TimeSpan Timeout, int MaxOutputBytes); + + private sealed record FileStamp(long Length, DateTime LastWriteTimeUtc); + + private static IReadOnlyDictionary RepositoryFileStamps(string root) + { + string[] projectRoots = + { + "src/SIL.Machine", + "src/SIL.Machine.Morphology.HermitCrab", + "src/SIL.Machine.Morphology.HermitCrab.Tool", + "src/SIL.Machine.Morphology.HermitCrab.Conformance", + }; + return projectRoots + .SelectMany(relative => + Directory.EnumerateFiles(Path.Combine(root, relative), "*", SearchOption.AllDirectories) + ) + .ToDictionary( + path => Path.GetRelativePath(root, path).Replace('\\', '/'), + path => + { + var info = new FileInfo(path); + return new FileStamp(info.Length, info.LastWriteTimeUtc); + }, + StringComparer.Ordinal + ); + } + + private static string ArgumentValue(ProcessStartInfo startInfo, string prefix) => + startInfo.ArgumentList.Single(argument => argument.StartsWith(prefix, StringComparison.Ordinal))[ + prefix.Length.. + ]; + + private static string CompleteEnvelope( + string compileItems, + string targetFramework = "netstandard2.0", + string? roslynAssembliesPath = null, + string cscCommandLineArgs = "[]", + string? generatedAssemblyInfoFile = null, + string? targetFrameworkAttributesPath = null + ) + { + return $$""" + { + "Properties": { + "PanGlossCompilerInputProtocol": "hc-semantic-msbuild/v1", + "MSBuildAllProjects": "repo:/Machine.sln", + "AssemblyName": "hc", + "TargetFramework": "{{targetFramework}}", + "LangVersion": "latest", + "Nullable": "enable", + "DefineConstants": "TRACE;A", + "AllowUnsafeBlocks": "false", + "CheckForOverflowUnderflow": "false", + "OutputType": "Library", + "NETCoreSdkVersion": "10.0.303", + "MSBuildVersion": "17.0.0", + "CscToolPath": "", + "RoslynAssembliesPath": {{JsonSerializer.Serialize(roslynAssembliesPath ?? "sdk:/Roslyn")}}, + "GeneratedAssemblyInfoFile": {{JsonSerializer.Serialize( + generatedAssemblyInfoFile ?? "tmp:/Project.AssemblyInfo.cs" + )}}, + "TargetFrameworkMonikerAssemblyAttributesPath": {{JsonSerializer.Serialize( + targetFrameworkAttributesPath ?? "tmp:/.NETStandard,Version=v2.0.AssemblyAttributes.cs" + )}} + }, + "Items": { + "CscCommandLineArgs": {{cscCommandLineArgs}}, + "Compile": {{compileItems}}, + "ProjectReference": [], + "ReferencePathWithRefAssemblies": [], + "Analyzer": [], + "AdditionalFiles": [], + "EditorConfigFiles": [], + "Using": [] + } + } + """; + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DtdInventoryReaderTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DtdInventoryReaderTests.cs new file mode 100644 index 000000000..9d77b6155 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/DtdInventoryReaderTests.cs @@ -0,0 +1,538 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class DtdInventoryReaderTests +{ + [Test] + public void TinyDtdProducesCompleteDeterministicManifest() + { + const string Dtd = """ + + + + + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("fixture.dtd", Dtd) + ); + + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Is.EqualTo( + new[] + { + "dtd:attribute-default/Root/mode/default/one", + "dtd:attribute-default/Root/target/implied", + "dtd:attribute-type/Root/mode/enumeration", + "dtd:attribute-type/Root/target/IDREF", + "dtd:attribute/Root/mode", + "dtd:attribute/Root/target", + "dtd:content/Child/r.pcdata@one", + "dtd:content/Root/r.sequence@one", + "dtd:default/Root/mode/one", + "dtd:element/Child", + "dtd:element/Root", + "dtd:enum/Root/mode/one", + "dtd:enum/Root/mode/two", + "dtd:placement/Root/r.0/Child/optional", + } + ) + ); + Assert.That( + inventory.Surfaces.Single(surface => surface.Id == "dtd:attribute/Root/target").Value, + Does.Contain("type=IDREF").And.Contain("default=#IMPLIED") + ); + Assert.That( + inventory.Surfaces.Single(surface => surface.Id == "dtd:placement/Root/r.0/Child/optional").Value, + Does.Contain("group=dtd:content/Root/r.sequence@one") + ); + Assert.That(inventory.SourceHash, Does.Match("^[0-9a-f]{64}$")); + } + + [Test] + public void NestedAlternationAndRepeatedPlacementsPreserveGroupTopology() + { + const string Dtd = """ + + + + + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("nested.dtd", Dtd) + ); + + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Is.EqualTo( + new[] + { + "dtd:content/A/r.empty@one", + "dtd:content/B/r.pcdata@one", + "dtd:content/C/r.pcdata@one", + "dtd:content/Root/r.1.choice@one-or-more", + "dtd:content/Root/r.sequence@one", + "dtd:element/A", + "dtd:element/B", + "dtd:element/C", + "dtd:element/Root", + "dtd:placement/Root/r.0/A/one", + "dtd:placement/Root/r.1.0/B/one", + "dtd:placement/Root/r.1.1/C/one", + "dtd:placement/Root/r.2/B/optional", + } + ) + ); + Assert.That( + inventory.Surfaces.Single(surface => surface.Id == "dtd:placement/Root/r.1.0/B/one").Value, + Does.Contain("group=dtd:content/Root/r.1.choice@one-or-more").And.Contain("groupMax=unbounded") + ); + Assert.That( + inventory.Surfaces.Single(surface => surface.Id == "dtd:placement/Root/r.2/B/optional").Value, + Does.Contain("group=dtd:content/Root/r.sequence@one") + ); + } + + [Test] + public void CommentsWhitespaceFixedAndMultilineAttributesAreParsed() + { + const string Dtd = """ + + + + + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("comments.dtd", Dtd) + ); + + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:attribute/Root/id")); + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:enum/Root/status/ready")); + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:enum/Root/status/done")); + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:default/Root/status/ready")); + Assert.That( + inventory.Surfaces.Single(surface => surface.Id == "dtd:attribute/Root/status").Value, + Does.Contain("fixed=true").And.Contain("type=enumeration") + ); + } + + [Test] + public void StructuralPathsDistinguishEquivalentOrdinalShapes() + { + const string LeftNested = """ + + + + + """; + const string RightNested = """ + + + + + """; + + SemanticInventory left = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("left.dtd", LeftNested) + ); + SemanticInventory right = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("right.dtd", RightNested) + ); + + Assert.That( + left.Surfaces.Select(surface => surface.Id), + Is.Not.EqualTo(right.Surfaces.Select(surface => surface.Id)) + ); + Assert.That(left.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:content/Root/r.1.sequence@one")); + Assert.That(right.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:content/Root/r.0.sequence@one")); + Assert.That(left.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:placement/Root/r.1.0/B/one")); + Assert.That(right.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:placement/Root/r.0.1/B/one")); + } + + [Test] + public void GroupCardinalityIsPartOfTheAddressableIdentity() + { + const string OneOrMore = """ + + + + """; + const string ZeroOrMore = """ + + + + """; + + SemanticInventory oneOrMore = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("one-or-more.dtd", OneOrMore) + ); + SemanticInventory zeroOrMore = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("zero-or-more.dtd", ZeroOrMore) + ); + + Assert.That( + oneOrMore.Surfaces.Select(surface => surface.Id), + Does.Contain("dtd:content/Root/r.sequence@one-or-more") + ); + Assert.That( + zeroOrMore.Surfaces.Select(surface => surface.Id), + Does.Contain("dtd:content/Root/r.sequence@zero-or-more") + ); + Assert.That( + oneOrMore.Surfaces.Select(surface => surface.Id), + Is.Not.EqualTo(zeroOrMore.Surfaces.Select(surface => surface.Id)) + ); + } + + [Test] + public void AttributeTypePresenceAndAuthoredValuesHaveExactEncodedSurfaces() + { + const string Dtd = """ + + + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("attributes.dtd", Dtd) + ); + var ids = inventory.Surfaces.Select(surface => surface.Id).ToArray(); + + Assert.That(ids, Does.Contain("dtd:attribute-type/Root/required/IDREF")); + Assert.That(ids, Does.Contain("dtd:attribute-type/Root/implied/IDREFS")); + Assert.That(ids, Does.Contain("dtd:attribute-type/Root/ordinary/CDATA")); + Assert.That(ids, Does.Contain("dtd:attribute-type/Root/fixed/CDATA")); + Assert.That(ids, Does.Contain("dtd:attribute-type/Root/colon%3Aname/IDREFS")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/required/required")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/implied/implied")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/ordinary/default/a%2Fb%3B%20c")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/fixed/fixed/a%2Fb%3B%20c")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/quotedRequired/default/%23REQUIRED")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/quotedImplied/default/%23IMPLIED")); + Assert.That(ids, Does.Contain("dtd:default/Root/quotedRequired/%23REQUIRED")); + Assert.That(ids, Does.Contain("dtd:default/Root/quotedImplied/%23IMPLIED")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/fixedRequired/fixed/%23REQUIRED")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/fixedImplied/fixed/%23IMPLIED")); + Assert.That(ids, Does.Contain("dtd:default/Root/fixedRequired/%23REQUIRED")); + Assert.That(ids, Does.Contain("dtd:default/Root/fixedImplied/%23IMPLIED")); + Assert.That(ids, Does.Contain("dtd:attribute-default/Root/colon%3Aname/fixed/x%3Ay")); + Assert.That(ids, Does.Contain("dtd:default/Root/ordinary/a%2Fb%3B%20c")); + Assert.That(ids, Does.Contain("dtd:default/Root/fixed/a%2Fb%3B%20c")); + Assert.That(ids, Does.Contain("dtd:default/Root/colon%3Aname/x%3Ay")); + Assert.That(ids, Does.Contain("dtd:attribute/Root/colon%3Aname")); + } + + [TestCase("", "ELEMENT")] + [TestCase("", "ATTLIST")] + [TestCase("", "DOCTYPE")] + public void DeclarationKeywordsRequireXmlWhitespace(string dtd, string keyword) + { + string path = $"boundary-{keyword}.dtd"; + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd(path, dtd)) + ); + + Assert.That(error!.Message, Does.Contain("unsupported DTD declaration").And.Contain(path + ":1:")); + } + + [Test] + public void DeclarationSeparatorsUseOnlyXmlDtdWhitespace() + { + const string Dtd = ""; + + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("separator.dtd", Dtd)) + ); + + Assert.That(error!.Message, Does.Contain("unsupported DTD declaration").And.Contain("separator.dtd:1:")); + } + + [TestCase("")] + [TestCase("")] + [TestCase("")] + [TestCase(" ]>")] + public void EveryDoctypeDeclarationIsRejectedAtTheDtdSeam(string dtd) + { + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("doctype.dtd", dtd)) + ); + + Assert.That( + error!.Message, + Does.Contain("DOCTYPE declarations are unsupported").And.Contain("not loaded").And.Contain("doctype.dtd:1:") + ); + } + + [TestCase("(#PCDATA | Child)")] + [TestCase("(#PCDATA, Child)")] + [TestCase("(Child | #PCDATA)*")] + [TestCase("(#PCDATA)*")] + [TestCase("((#PCDATA | Child)*)")] + [TestCase("(#PCDATA | Child+)*")] + [TestCase("(#PCDATA | Child | Child)*")] + public void InvalidMixedContentShapesAreRejected(string model) + { + string dtd = $""" + + + """; + + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("mixed.dtd", dtd)) + ); + + Assert.That(error!.Message, Does.Contain("mixed content model").And.Contain("mixed.dtd:1:")); + } + + [Test] + public void ValidMixedContentShapeIsEnumerated() + { + const string Dtd = """ + + + + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("valid-mixed.dtd", Dtd) + ); + var ids = inventory.Surfaces.Select(surface => surface.Id); + + Assert.That(ids, Does.Contain("dtd:content/Root/r.choice@zero-or-more")); + Assert.That(ids, Does.Contain("dtd:content/Root/r.0.pcdata@one")); + Assert.That(ids, Does.Contain("dtd:placement/Root/r.1/Child/one")); + Assert.That(ids, Does.Contain("dtd:placement/Root/r.2/Other/one")); + } + + [TestCase("\"three\"")] + [TestCase("#FIXED \"three\"")] + public void EnumerationDefaultsMustBeExactMembers(string defaultDeclaration) + { + string dtd = $""" + + + """; + + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("enum-default.dtd", dtd)) + ); + + Assert.That(error!.Message, Does.Contain("not an enumeration member").And.Contain("enum-default.dtd:2:")); + } + + [TestCase("")] + [TestCase("")] + [TestCase("")] + [TestCase("")] + [TestCase("")] + [TestCase("")] + [TestCase("")] + public void MissingDtdTokenSeparatorsAreRejected(string dtd) + { + Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("separator-boundary.dtd", dtd)) + ); + } + + [TestCase("")] + [TestCase("")] + [TestCase("")] + [TestCase("")] + public void MissingAttributeSeparatorsHaveExplicitDiagnostics(string dtd) + { + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("attribute-separator.dtd", dtd)) + ); + + Assert.That( + error!.Message, + Does.Contain("expected XML DTD whitespace").And.Contain("attribute-separator.dtd:1:") + ); + } + + [TestCase("")] + [TestCase("")] + [TestCase("")] + public void MalformedCommentsAreRejectedBeforeTheyCanHideDeclarations(string dtd) + { + var error = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("comment.dtd", dtd)) + ); + + Assert.That(error!.Message, Does.Contain("invalid DTD comment").And.Contain("comment.dtd:1:")); + } + + [Test] + public void ValidCommentsDoNotHideFollowingDeclarations() + { + const string Dtd = """ + + + """; + + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("valid-comment.dtd", Dtd) + ); + + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:element/Root")); + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:content/Root/r.empty@one")); + } + + [Test] + public void UnsupportedNotationAndInvalidPublicInputsFailDeterministically() + { + const string NotationDtd = """ + + + """; + + var notationError = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("notation.dtd", NotationDtd)) + ); + Assert.That(notationError!.Message, Does.Contain("unsupported attribute type").And.Contain("notation.dtd:2:")); + + Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("", "")) + ); + Assert.Throws(() => SemanticCoverageInventory.Generate(null!)); + } + + [Test] + public void DuplicatesAndMalformedDeclarationsFailWithSourceSpan() + { + const string Duplicate = """ + + + """; + const string Unterminated = "(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("duplicate.dtd", Duplicate)) + ); + Assert.That(duplicateError!.Message, Does.Contain("duplicate").And.Contain("duplicate.dtd:2:")); + + var malformedError = Assert.Throws(() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("broken.dtd", Unterminated)) + ); + Assert.That(malformedError!.Message, Does.Contain("unterminated").And.Contain("broken.dtd:1:")); + } + + [Test] + public void AuthoritativeHermitCrabDtdCanBeEnumerated() + { + string dtdPath = Path.GetFullPath( + Path.Combine( + TestContext.CurrentContext.TestDirectory, + "..", + "..", + "..", + "..", + "..", + "src", + "SIL.Machine.Morphology.HermitCrab", + "HermitCrabInput.dtd" + ) + ); + string dtd = File.ReadAllText(dtdPath); + SemanticInventory inventory = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("HermitCrabInput.dtd", dtd) + ); + + var kindCounts = inventory + .Surfaces.GroupBy(surface => surface.Kind) + .ToDictionary(group => group.Key, group => group.Count()); + Assert.That(inventory.Surfaces.Count, Is.EqualTo(1059)); + Assert.That(kindCounts["element"], Is.EqualTo(108)); + Assert.That(kindCounts["attribute"], Is.EqualTo(149)); + Assert.That(kindCounts["attribute-type"], Is.EqualTo(149)); + Assert.That(kindCounts["attribute-default"], Is.EqualTo(149)); + Assert.That(kindCounts["enum"], Is.EqualTo(156)); + Assert.That(kindCounts["default"], Is.EqualTo(54)); + Assert.That(kindCounts["content-group"], Is.EqualTo(91)); + Assert.That(kindCounts["special-content"], Is.EqualTo(19)); + Assert.That(kindCounts["placement"], Is.EqualTo(184)); + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:element/HermitCrabInput")); + Assert.That(inventory.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:attribute/Language/isActive")); + } + + [Test] + public void CarrierCardinalityAndEnumMutationsChangeGeneratedDenominator() + { + const string BaseDtd = """ + + + + """; + const string CarrierMutation = """ + + + + + """; + const string CardinalityMutation = """ + + + + """; + const string EnumMutation = """ + + + + """; + + var baseline = SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("base.dtd", BaseDtd)); + var carrier = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("carrier.dtd", CarrierMutation) + ); + var cardinality = SemanticCoverageInventory.Generate( + SemanticCoverageSourceSet.FromDtd("cardinality.dtd", CardinalityMutation) + ); + var @enum = SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("enum.dtd", EnumMutation)); + + Assert.That( + carrier.Surfaces.Select(surface => surface.Id), + Is.Not.EqualTo(baseline.Surfaces.Select(surface => surface.Id)) + ); + Assert.That( + cardinality.Surfaces.Select(surface => surface.Id), + Is.Not.EqualTo(baseline.Surfaces.Select(surface => surface.Id)) + ); + Assert.That( + @enum.Surfaces.Select(surface => surface.Id), + Is.Not.EqualTo(baseline.Surfaces.Select(surface => surface.Id)) + ); + Assert.That(@enum.Surfaces.Select(surface => surface.Id), Does.Contain("dtd:enum/Root/mode/three")); + Assert.That( + cardinality.Surfaces.Select(surface => surface.Id), + Does.Contain("dtd:placement/Root/r.0/Child/one-or-more") + ); + Assert.That( + cardinality.Surfaces.Single(surface => surface.Id == "dtd:placement/Root/r.0/Child/one-or-more").Value, + Does.Contain("min=1").And.Contain("max=unbounded") + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EngineGateInventoryLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EngineGateInventoryLedgerTests.cs new file mode 100644 index 000000000..8e75e4f23 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EngineGateInventoryLedgerTests.cs @@ -0,0 +1,161 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class EngineGateInventoryLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Pins the headline counts. 23 is FailureReason's own member count minus None (the enum this + // ledger is keyed to, SIL.Machine.Morphology.HermitCrab/ITraceManager.cs); it moves only if that + // enum itself gains or loses a member, never as a side effect of corpus changes. witnessed/ + // unreached come from EngineGateWitnessSweep's real traced run over every non-pathological, + // non-crash fixture -- see UnreachedGatesAreTheKnownCorpusGaps below for why each of the 7 is + // unreached. noDtdAttribute pins EngineGateInventoryLedger.DtdAttributes' six deliberate "-" + // entries (three Pattern-family gates driven by PhoneticSequence element content, Environments and + // DisjunctiveAllomorph driven by child elements/allomorph order rather than an attribute, and + // SurfaceFormMismatch's pure engine-internal reconstruction check). + [Test] + public void RealCorpusProducesTheDeclaredGateCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = EngineGateInventoryLedger.Read(root); + + int witnessed = rows.Count(r => r.Status == EngineGateStatus.Witnessed); + int unreached = rows.Count(r => r.Status == EngineGateStatus.Unreached); + int noDtdAttribute = rows.Count(r => r.DtdAttributes == "-"); + + TestContext.Out.WriteLine( + $"gates={rows.Count} witnessed={witnessed} unreached={unreached} noDtdAttribute={noDtdAttribute}" + ); + + Assert.That(rows, Has.Count.EqualTo(23)); + Assert.That(witnessed, Is.EqualTo(17)); + Assert.That(unreached, Is.EqualTo(6)); + Assert.That(noDtdAttribute, Is.EqualTo(6)); + Assert.That(witnessed + unreached, Is.EqualTo(rows.Count)); + } + + // Every gate is a real enum member with at least one live TraceManager call site + // (RaiseSiteScanner.Scan is mechanical, not hand-curated), so none can ever show "-" here -- + // unlike dtd_attributes and the witness columns, an empty raise_sites would mean the scanner + // itself is broken, not a corpus gap. + [Test] + public void EveryGateHasAtLeastOneRaiseSite() + { + string root = RepositoryRoot(); + IReadOnlyList rows = EngineGateInventoryLedger.Read(root); + + Assert.That(rows.All(r => r.RaiseSites != "-" && r.RaiseSites.Length > 0), Is.True); + } + + // The exact 7 gates the current corpus never fires, each for a distinct, verified reason -- not + // "the corpus is thin" but a specific missing shape: HeadPattern/NonHeadPattern need a compounding + // candidate whose head/non-head phonetic shape is tried and fails to match (every compounding + // fixture's candidates match by construction); MaxApplicationCount needs a rule re-applied to its + // own multipleApplication cap within one derivation (no fixture repeats a rule that many times); + // NonHeadProdRestrictMprFeatures needs analysis-direction compounding with a candidate root that + // fails CompoundingRule.nonHeadProdRestrictionsMprFeatures (no fixture pairs that attribute with a + // failing candidate); NonHeadRequiredSyntacticFeatureStruct needs a non-head candidate that fails + // CompoundingRule.nonHeadPartsOfSpeech (the corpus's compounding fixtures exercise the head-side + // gate -- HeadRequiredSyntacticFeatureStruct is Witnessed -- but never the non-head one failing); + // NonPartialRuleRequiredAfterNonFinalTemplate needs a partial="true" rule tried right after an + // AffixTemplate final="false" template (no fixture combines the two); ObligatorySyntacticFeatures + // needs a rule's own outputObligatoryFeatures promise to go unmet by the time IsWordValid checks it + // (no fixture's obligatory-feature rule ever produces a candidate missing that feature). + [Test] + public void UnreachedGatesAreTheKnownCorpusGaps() + { + string root = RepositoryRoot(); + IReadOnlyList rows = EngineGateInventoryLedger.Read(root); + string[] unreached = rows.Where(r => r.Status == EngineGateStatus.Unreached).Select(r => r.Gate).ToArray(); + + Assert.That( + unreached, + Is.EquivalentTo( + new[] + { + "HeadPattern", + "NonHeadPattern", + "NonHeadProdRestrictMprFeatures", + "NonHeadRequiredSyntacticFeatureStruct", + "NonPartialRuleRequiredAfterNonFinalTemplate", + "ObligatorySyntacticFeatures", + } + ) + ); + } + + // Mirrors DataflowObligationLedgerTests.CheckedInDataflowObligationLedgerIsUpToDate: regenerate and + // require the checked-in file to match byte for byte. + [Explicit("Runs a traced sweep of every fixture word; the checked-in ledger is what the other tests read.")] + [Test] + public void CheckedInEngineGateInventoryLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList rows = EngineGateInventoryLedger.Compute(root); + + string fresh = EngineGateInventoryLedger.ToText(rows); + string checkedIn = File.ReadAllText( + Path.Combine(root, EngineGateInventoryLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + fresh.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-engine-gate-inventory --repository-root ." + ); + } + + // ------------------------------------------------------------------------------------------ + // RaiseSiteScanner: unit-level pins for the mechanical scan directly, independent of the real + // corpus/engine, proving the "mechanical, not hand-curated" claim -- a real comparison + // (`== FailureReason.None`) and a commented-out raise must never be counted, and a genuine raise + // must always be found regardless of which of the 23 members it names. + // ------------------------------------------------------------------------------------------ + + [Test] + public void ScanFindsARaiseSiteButSkipsComparisonsAndComments() + { + string root = Path.Combine(Path.GetTempPath(), "engine-gate-scanner-test-" + Path.GetRandomFileName()); + string engineDir = Path.Combine(root, "src", "SIL.Machine.Morphology.HermitCrab"); + Directory.CreateDirectory(engineDir); + File.WriteAllLines( + Path.Combine(engineDir, "Sample.cs"), + new[] + { + "// a commented-out raise: FailureReason.BoundRoot,", + "if (trace.FailureReason == FailureReason.None) return;", + "if (reason == FailureReason.MaxApplicationCount) { }", + "morpher.TraceManager.Failed(lang, word, FailureReason.BoundRoot, this, null);", + } + ); + + try + { + IReadOnlyDictionary> sites = RaiseSiteScanner.Scan(root); + + Assert.That(sites.ContainsKey("None"), Is.False); + Assert.That(sites.ContainsKey("MaxApplicationCount"), Is.False); + Assert.That(sites["BoundRoot"], Is.EqualTo(new[] { "Sample.cs:4" })); + } + finally + { + Directory.Delete(root, recursive: true); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceCardGeneratorTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceCardGeneratorTests.cs new file mode 100644 index 000000000..3cbab7200 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceCardGeneratorTests.cs @@ -0,0 +1,244 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class EvidenceCardGeneratorTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // The two cell ids DataflowClaimGateTests already seeds/pins as real, currently-Satisfied, + // currently-claimed cells. Deliberately does NOT pin the ledger's total cell count or per-status + // breakdown -- both move as the obligation-fill work lands. + private const string VokadanCellId = + "MorphologicalPhonologicalRuleFeature::LexicalEntry.ruleFeatures->MorphologicalInput.excludedMPRFeatures::McDc:PresentGatedForm"; + private const string NunavuqCellId = + "PartOfSpeech::LexicalEntry.partOfSpeech->MorphologicalRule.requiredPartsOfSpeech::McDc:AbsentGatedForm"; + + // One card per ledger row, and every card gets a distinct file name (Compute itself throws on a + // collision, so reaching this assertion at all is already load-bearing). + [Test] + public void OneCardPerLedgerRowWithDistinctFileNames() + { + string root = RepositoryRoot(); + IReadOnlyList ledgerRows = DataflowObligationLedger.Read(root); + IReadOnlyList cards = EvidenceCardGenerator.Compute(root); + + Assert.That(cards, Has.Count.EqualTo(ledgerRows.Count)); + Assert.That( + cards.Select(c => c.CellId).ToHashSet(), + Is.EquivalentTo(ledgerRows.Select(r => r.CellId).ToHashSet()) + ); + Assert.That(cards.Select(c => c.FileName).Distinct().Count(), Is.EqualTo(cards.Count)); + } + + // The vokadan cell is used elsewhere in this suite as the canonical worked example: this asserts + // its card actually carries everything the reviewer's four checks (predict, cite lines, check + // counterpart, read prose against values) need in one screen, not spread across four files. + [Test] + public void VokadanCardCarriesEveryReviewerIngredient() + { + string root = RepositoryRoot(); + EvidenceCard card = EvidenceCardGenerator.Compute(root).Single(c => c.CellId == VokadanCellId); + + Assert.That(card.Markdown, Does.Contain("the payload IS present and the gated form IS blocked.")); + Assert.That(card.Markdown, Does.Contain("**Satisfied**")); + Assert.That(card.Markdown, Does.Contain("Claimed by word **'vokadan'** in `edge-cases/mpr-gated-exception`")); + // Grammar citations: the writer's payload and the reader's gate, each at a real line number + // (not merely "present somewhere"). + Assert.That( + card.Markdown, + Does.Match( + @"Writer \(payload declared here\) `LexicalEntry\.ruleFeatures`: `grammar\.xml:\d+` = ""mprException""" + ) + ); + Assert.That( + card.Markdown, + Does.Match( + @"Reader \(gate declared here\) `MorphologicalInput\.excludedMPRFeatures`: `grammar\.xml:\d+` = ""mprException""" + ) + ); + // Before/after, both from the author's own claim and independently from the machine witness + // ledger -- two separate facts, never collapsed into one. + Assert.That(card.Markdown, Does.Contain("Before: `ok::-`")); + Assert.That(card.Markdown, Does.Contain("After: `ok::VOKAD+SUF|vokadan`")); + Assert.That(card.Markdown, Does.Contain("verdict=Evidenced")); + Assert.That(card.Markdown, Does.Contain("'vokadan': ok::- -> ok::VOKAD+SUF|vokadan")); + // The author's proof prose, verbatim. + Assert.That(card.Markdown, Does.Contain("the PresentGatedForm arm: the feature is PRESENT on the root")); + // distinct_from, with BOTH outcomes shown so a reviewer can see they differ without opening + // words.yaml. + Assert.That( + card.Markdown, + Does.Contain("`distinct_from` **'sanitan'** (expect_fail=False) vs. this word (expect_fail=True)") + ); + } + + [Test] + public void NunavuqCardIdentifiesItsOwnFixtureAndWord() + { + string root = RepositoryRoot(); + EvidenceCard card = EvidenceCardGenerator.Compute(root).Single(c => c.CellId == NunavuqCellId); + + Assert.That(card.Markdown, Does.Contain("'nunavuq'")); + Assert.That(card.Markdown, Does.Contain("languages/polysynthetic-stratal-derivation-chain")); + Assert.That(card.Markdown, Does.Contain("the payload is ABSENT and the gated form IS blocked.")); + } + + // Falsification (constraint #2 of the task): a cell with none of claim/prose/counterpart must say + // so explicitly in every section, never leave a section blank -- checked across every card in the + // real corpus, not just one cherry-picked example. + [Test] + public void EveryCardRendersEverySectionNeverBlank() + { + string root = RepositoryRoot(); + IReadOnlyList cards = EvidenceCardGenerator.Compute(root); + string[] requiredHeaders = + { + "## Role, in plain English", + "## Chain", + "## Machine status", + "## Fixture and word", + "## Exact mutation and before/after parse", + "## Grammar citations", + "## Author's prose", + "## `distinct_from` counterpart", + }; + + foreach (EvidenceCard card in cards) + { + string[] lines = card.Markdown.ReplaceLineEndings("\n").Split('\n'); + foreach (string header in requiredHeaders) + { + int headerIndex = Array.IndexOf(lines, header); + Assert.That(headerIndex, Is.GreaterThanOrEqualTo(0), $"{card.CellId}: missing header '{header}'"); + + // The next non-blank line after a header is the section's content; a section is never + // immediately followed by another "## " header (that would mean nothing was rendered). + int i = headerIndex + 1; + while (i < lines.Length && lines[i].Length == 0) + i++; + Assert.That( + i < lines.Length && !lines[i].StartsWith("## ", StringComparison.Ordinal), + $"{card.CellId}: section '{header}' has no content before the next header" + ); + } + } + } + + // At least one real cell has no claimed_cells entry naming it and no extractable witnessing word + // (every NotSatisfied cell qualifies, since an unexercised chain's evidence names no fixture at + // all) -- confirms that specific, common case renders the explicit "no claim / no word" prose + // rather than something that merely happens to look non-blank. + [Test] + public void UnclaimedCellWithNoIdentifiableWordRendersAbsenceExplicitly() + { + string root = RepositoryRoot(); + IReadOnlyList ledgerRows = DataflowObligationLedger.Read(root); + DataflowObligationLedger.Row unexercised = ledgerRows.First(r => r.Status == ObligationStatus.NotSatisfied); + EvidenceCard card = EvidenceCardGenerator.Compute(root).Single(c => c.CellId == unexercised.CellId); + + Assert.That(card.Markdown, Does.Contain("No fixture or word is identified for this cell")); + Assert.That( + card.Markdown, + Does.Contain("No `claimed_cells` entry recorded an author-reviewed severing/before/after") + ); + Assert.That( + card.Markdown, + Does.Contain("No prose recorded: no claim, and no word is identified for this cell.") + ); + Assert.That( + card.Markdown, + Does.Contain("No claim exists for this cell, so no `distinct_from` counterpart is recorded.") + ); + } + + // Falsification (task's own requirement): the drift gate must catch a hand-edit. Isolated from the + // real corpus and from Compute() entirely -- this exercises Write()/Check() directly against a + // throwaway directory with two synthetic cards, so it neither depends on nor perturbs the checked-in + // conformance/evidence-cards/ directory. + [Test] + public void DriftCheckCatchesAHandEditAMissingFileAndAnExtraFile() + { + string tempRoot = Path.Combine(Path.GetTempPath(), $"hc-evidence-card-drift-{Guid.NewGuid():N}"); + Directory.CreateDirectory(tempRoot); + try + { + var cards = new[] + { + new EvidenceCard("cell-one", "cell-one__aaaa.md", "# cell one\ncontent\n"), + new EvidenceCard("cell-two", "cell-two__bbbb.md", "# cell two\ncontent\n"), + }; + + EvidenceCardGenerator.Write(tempRoot, cards); + Assert.That( + EvidenceCardGenerator.Check(tempRoot, cards).IsCurrent, + Is.True, + "a freshly written set must check as current" + ); + + string cardDir = Path.Combine(tempRoot, "conformance", "evidence-cards"); + + // Hand-edit. + string editedPath = Path.Combine(cardDir, "cell-one__aaaa.md"); + File.WriteAllText(editedPath, "# cell one\nHAND-EDITED, NOT REGENERATED\n"); + EvidenceCardDiff editedDiff = EvidenceCardGenerator.Check(tempRoot, cards); + Assert.That(editedDiff.IsCurrent, Is.False); + Assert.That(editedDiff.Details, Has.Some.Contains("STALE cell-one")); + + // Restore, then delete a file outright. + File.WriteAllText(editedPath, "# cell one\ncontent\n"); + Assert.That( + EvidenceCardGenerator.Check(tempRoot, cards).IsCurrent, + Is.True, + "restoring the hand-edit must check as current again" + ); + + File.Delete(editedPath); + EvidenceCardDiff missingDiff = EvidenceCardGenerator.Check(tempRoot, cards); + Assert.That(missingDiff.IsCurrent, Is.False); + Assert.That(missingDiff.Details, Has.Some.Contains("MISSING cell-one")); + + // Restore, then add a stray extra file. + EvidenceCardGenerator.Write(tempRoot, cards); + File.WriteAllText(Path.Combine(cardDir, "stray-leftover.md"), "not a generated card\n"); + EvidenceCardDiff extraDiff = EvidenceCardGenerator.Check(tempRoot, cards); + Assert.That(extraDiff.IsCurrent, Is.False); + Assert.That(extraDiff.Details, Has.Some.Contains("EXTRA FILE stray-leftover.md")); + + // Write() itself removes anything not in the fresh set. + EvidenceCardGenerator.Write(tempRoot, cards); + Assert.That(File.Exists(Path.Combine(cardDir, "stray-leftover.md")), Is.False); + Assert.That(EvidenceCardGenerator.Check(tempRoot, cards).IsCurrent, Is.True); + } + finally + { + Directory.Delete(tempRoot, recursive: true); + } + } + + // Sanity check that what is actually checked in right now is the fresh render -- i.e. this task's + // own generated conformance/evidence-cards/ directory is not stale relative to its own generator. + [Test] + public void CheckedInCardsAreCurrent() + { + string root = RepositoryRoot(); + IReadOnlyList cards = EvidenceCardGenerator.Compute(root); + EvidenceCardDiff diff = EvidenceCardGenerator.Check(root, cards); + + Assert.That(diff.IsCurrent, Is.True, string.Join("\n", diff.Details)); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceLedgerFreshnessTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceLedgerFreshnessTests.cs new file mode 100644 index 000000000..fcb44ef17 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceLedgerFreshnessTests.cs @@ -0,0 +1,87 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Recomputes the whole Surface+Ordering sweep and checks it against the checked-in +/// conformance/semantic-coverage-evidence.tsv, the same protection +/// already gives the +/// legacy Surface-only ledger. A stale evidence ledger silently understates the gap count +/// ratchets on. +/// +[TestFixture] +public sealed class EvidenceLedgerFreshnessTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Recomputes both sweeps end to end: re-parses every fixture once per Surface plus once per Ordering + // adjacent pair. Costs minutes, same order as the legacy Surface-only freshness test; run manually or + // by the coverage-evidence workflow, never on every push. + [Test] + [Explicit("re-parses every fixture once per Surface item plus once per Ordering adjacent pair")] + [Category("Counterfactual")] + public void TheCheckedInEvidenceLedgerMatchesAFreshRecomputeExactly() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + + IReadOnlyList freshSurface = CounterfactualLedger.Sweep(root, inventory); + IReadOnlyList freshOrdering = CounterfactualLedger.SweepOrdering(root); + IReadOnlyList items = CoverageEvidencePipeline.BuildItems(freshSurface, freshOrdering); + IReadOnlyList evidence = CoverageEvidencePipeline.BuildEvidence( + freshSurface.Concat(freshOrdering).ToArray() + ); + IReadOnlyList fresh = CoverageEvidencePipeline.BuildLedgerRows(items, evidence); + + IReadOnlyList checkedIn = EvidenceLedger.Read(root); + + var freshById = fresh.ToDictionary(row => row.ItemId, StringComparer.Ordinal); + var checkedInById = checkedIn.ToDictionary(row => row.ItemId, StringComparer.Ordinal); + + string[] added = freshById + .Keys.Except(checkedInById.Keys, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] removed = checkedInById + .Keys.Except(freshById.Keys, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] changed = freshById + .Keys.Intersect(checkedInById.Keys, StringComparer.Ordinal) + .Where(id => freshById[id] != checkedInById[id]) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That( + added, + Is.Empty, + $"newly evidenced items; regenerate with --write-coverage-evidence:\n {string.Join("\n ", added)}" + ); + Assert.That( + removed, + Is.Empty, + $"stale rows; delete from {EvidenceLedger.RelativePath}:\n {string.Join("\n ", removed)}" + ); + Assert.That( + changed, + Is.Empty, + $"changed evidence; regenerate with --write-coverage-evidence after checking why:\n {string.Join("\n ", changed)}" + ); + }); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceLedgerTests.cs new file mode 100644 index 000000000..8cb364c90 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/EvidenceLedgerTests.cs @@ -0,0 +1,144 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class EvidenceLedgerTests +{ + private string _repositoryRoot = string.Empty; + + [SetUp] + public void SetUp() + { + _repositoryRoot = Path.Combine(Path.GetTempPath(), "hc-evidence-ledger-tests", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(Path.Combine(_repositoryRoot, "conformance")); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_repositoryRoot)) + Directory.Delete(_repositoryRoot, recursive: true); + } + + [Test] + public void WritingThenReadingReturnsIdenticalRecords() + { + var rows = new[] + { + new EvidenceLedger.Row( + "dtd:element/AffixTemplates", + CoverageItemKind.Surface, + "edge-cases/loader-isactive-breadth", + "takul", + "ok::TA+KUL|takul", + CounterexampleKind.Word, + "ok::-", + "removed 1 element(s)", + CounterfactualVerdict.Evidenced + ), + new EvidenceLedger.Row( + "dtd:element/AffixTemplate", + CoverageItemKind.Surface, + "edge-cases/diacritic-segments", + "some-word", + "ok::SIGNATURE", + CounterexampleKind.LoadFailure, + "InvalidOperationException: the mutant would not load", + "removed 1 element(s)", + CounterfactualVerdict.RequiredByDtd + ), + new EvidenceLedger.Row( + "ordering:edge-cases/feature-system-breadth/phonologicalRules/prAlpha~prHighTrigger", + CoverageItemKind.Ordering, + "edge-cases/feature-system-breadth", + null, + null, + CounterexampleKind.None, + null, + "swapped adjacent order", + CounterfactualVerdict.Unobservable + ), + }; + + EvidenceLedger.Write(_repositoryRoot, rows); + IReadOnlyList readBack = EvidenceLedger.Read(_repositoryRoot); + + Assert.That(readBack, Is.EqualTo(rows.OrderBy(r => r.ItemId, StringComparer.Ordinal).ToArray())); + } + + [Test] + public void ReadingAnAbsentLedgerReturnsEmpty() + { + Assert.That(EvidenceLedger.Read(_repositoryRoot), Is.Empty); + } + + [Test] + public void RowsAreWrittenInDeterministicOrder() + { + var rows = new[] + { + new EvidenceLedger.Row( + "z-item", + CoverageItemKind.Surface, + "fx", + "w", + "before", + CounterexampleKind.Word, + "after", + "mutation", + CounterfactualVerdict.Evidenced + ), + new EvidenceLedger.Row( + "a-item", + CoverageItemKind.Surface, + "fx", + "w", + "before", + CounterexampleKind.Word, + "after", + "mutation", + CounterfactualVerdict.Evidenced + ), + }; + + EvidenceLedger.Write(_repositoryRoot, rows); + IReadOnlyList readBack = EvidenceLedger.Read(_repositoryRoot); + + Assert.That(readBack.Select(r => r.ItemId), Is.EqualTo(new[] { "a-item", "z-item" })); + } + + [Test] + public void AMalformedLineIsRefused() + { + string path = Path.Combine(_repositoryRoot, "conformance", "semantic-coverage-evidence.tsv"); + File.WriteAllText( + path, + "item_id\tkind\tfixture\texample_word\texample_outcome\tcounterexample_kind\tcounterexample_outcome\tmutation\tverdict\ntoo-few-fields\tSurface\n" + ); + + Assert.Throws(() => EvidenceLedger.Read(_repositoryRoot)); + } + + [TestCase("id")] + [TestCase("kind")] + [TestCase("fixture")] + public void ARowMustMatchTheGeneratedItemBeforeItCanBecomeEvidence(string mismatch) + { + var item = new CoverageItem("item", CoverageItemKind.Surface, "dtd-element", "fixture"); + var row = new EvidenceLedger.Row( + mismatch == "id" ? "other" : "item", + mismatch == "kind" ? CoverageItemKind.Ordering : CoverageItemKind.Surface, + mismatch == "fixture" ? "other-fixture" : "fixture", + "w", + "before", + CounterexampleKind.Word, + "after", + "mutation", + CounterfactualVerdict.Evidenced + ); + + Assert.Throws(() => EvidenceLedger.ToEvidence(row, item)); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExceptionListTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExceptionListTests.cs new file mode 100644 index 000000000..3f3f32f40 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExceptionListTests.cs @@ -0,0 +1,155 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Pins conformance/README.md's "named asterisk" exception list against the two ledgers that actually +/// prove "no engine consumer": `no-consumer` rows in semantic-coverage-proofs.tsv (a surface a fixture +/// declares, but mutating it changes nothing) and `dead-schema` rows in semantic-coverage-baseline.txt +/// (a surface no fixture ever attempts, because the engine never reads the owning element at all). This +/// test checks both ledgers together against the README: checking only the one that historically fed +/// it would leave dead-schema surfaces of the same "no engine reads this" shape as the two named +/// exceptions unnamed. These tests fail closed the moment either ledger gains a surface the README +/// does not name, or the README's own count of eleven stops matching the ledgers. +/// +[TestFixture] +public sealed class ExceptionListTests +{ + private const string StartMarker = ""; + private const string EndMarker = ""; + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static string ReadExceptionListSection(string root) + { + string path = Path.Combine(root, "conformance", "README.md"); + string text = File.ReadAllText(path); + int start = text.IndexOf(StartMarker, StringComparison.Ordinal); + int end = text.IndexOf(EndMarker, StringComparison.Ordinal); + Assert.That(start, Is.GreaterThanOrEqualTo(0), $"{StartMarker} not found in conformance/README.md"); + Assert.That( + end, + Is.GreaterThan(start), + $"{EndMarker} not found after the start marker in conformance/README.md" + ); + return text[start..end]; + } + + /// The words a reader would need to see to recognize this surface was named: the DTD + /// element for an element surface, or the attribute and value for an enumerated surface. + private static IReadOnlyList SurfaceKeywords(string surfaceId) + { + if (surfaceId.StartsWith(GrammarFeatureUsage.ElementPrefix, StringComparison.Ordinal)) + return new[] { surfaceId[GrammarFeatureUsage.ElementPrefix.Length..] }; + + if (surfaceId.StartsWith(GrammarFeatureUsage.EnumPrefix, StringComparison.Ordinal)) + { + string[] parts = surfaceId[GrammarFeatureUsage.EnumPrefix.Length..].Split('/'); + Assert.That(parts, Has.Length.EqualTo(3), $"unexpected enum surface shape: {surfaceId}"); + return new[] { parts[1], parts[2] }; + } + + Assert.Fail($"unrecognized surface id shape: {surfaceId}"); + return Array.Empty(); + } + + [Test] + public void EveryNoConsumerProofIsNamedInTheReadmeExceptionList() + { + string root = RepositoryRoot(); + string section = ReadExceptionListSection(root); + IReadOnlyList noConsumerProofs = ImpossibilityProofs + .Read(root) + .Where(proof => proof.Kind == ImpossibilityProofs.NoConsumer) + .ToArray(); + + Assert.That(noConsumerProofs, Is.Not.Empty, "the no-consumer ledger should not be empty"); + + string[] missing = noConsumerProofs + .Where(proof => + SurfaceKeywords(proof.SurfaceId).Any(keyword => !section.Contains(keyword, StringComparison.Ordinal)) + ) + .Select(proof => proof.SurfaceId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + Assert.That( + missing, + Is.Empty, + $"these no-consumer proofs are not named in conformance/README.md's exception list:\n {string.Join("\n ", missing)}" + ); + } + + [Test] + public void EveryDeadSchemaSurfaceIsNamedInTheReadmeExceptionList() + { + string root = RepositoryRoot(); + string section = ReadExceptionListSection(root); + IReadOnlyList deadSchemaEntries = GrammarCoverageGate + .ReadBaseline(root) + .Where(entry => entry.Classification == GrammarCoverageGate.DeadSchema) + .ToArray(); + + Assert.That(deadSchemaEntries, Is.Not.Empty, "the dead-schema ledger should not be empty"); + + string[] missingElements = deadSchemaEntries + .Select(entry => DeadSchemaDetector.OwningElement(entry.SurfaceId)) + .Where(name => name is not null) + .Select(name => name!) + .Distinct(StringComparer.Ordinal) + .Where(name => !section.Contains(name, StringComparison.Ordinal)) + .OrderBy(name => name, StringComparer.Ordinal) + .ToArray(); + + Assert.That( + missingElements, + Is.Empty, + $"these dead-schema elements are not named in conformance/README.md's exception list:\n {string.Join("\n ", missingElements)}" + ); + } + + // Both surface counts are recomputed, not hand-copied, so a future proof or a future dead-schema + // finding changes this number the moment it lands -- exactly the drift the defect exploited: a + // mechanically true fact that only one of the two ledgers surfaced to the README's headline claim. + [Test] + public void TheReadmeClaimsExactlyAsManySurfacesAsBothLedgersRecord() + { + string root = RepositoryRoot(); + int noConsumerCount = ImpossibilityProofs + .Read(root) + .Count(proof => proof.Kind == ImpossibilityProofs.NoConsumer); + int deadSchemaCount = GrammarCoverageGate + .ReadBaseline(root) + .Count(entry => entry.Classification == GrammarCoverageGate.DeadSchema); + int total = noConsumerCount + deadSchemaCount; + + string readmePath = Path.Combine(root, "conformance", "README.md"); + string readme = File.ReadAllText(readmePath); + + Assert.That( + readme, + Does.Contain($"{ToWords(total)} surfaces across three feature areas"), + $"conformance/README.md must claim exactly {total} surfaces ({noConsumerCount} no-consumer + {deadSchemaCount} dead-schema); update its wording if this count changed" + ); + } + + private static string ToWords(int count) => + count switch + { + 11 => "Eleven", + _ => count.ToString(), + }; +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExecutionClosureTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExecutionClosureTests.cs new file mode 100644 index 000000000..5a77acc97 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ExecutionClosureTests.cs @@ -0,0 +1,1062 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class ExecutionClosureTests +{ + private const string Dtd = ""; + + private static SemanticInventory Inventory(string source, params string[] roots) => + SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] { new CSharpInventoryInput("fixture.cs", source, roots) } + ) + ); + + [Test] + public void ExactMethodRootFollowsDirectConstructorAccessorAndLocalCallsButExcludesDeadBodies() + { + const string Source = """ + using System.Xml.Linq; + using SIL.Machine.Morphology.HermitCrab; + namespace Fixture; + public sealed class Root + { + public void Run(bool value) + { + Helper(value); + _ = new Built(value); + _ = Value; + void Local() { if (value) { } } + Local(); + } + + private static void Helper(bool value) + { + if (value) { } + _ = new XElement("root").Element("reachable"); + } + + private int Value { get { if (true) { } return 1; } } + private void Dead(bool value) + { + if (value) { } + _ = new XElement("root").Element("dead"); + } + } + public sealed class Built + { + public Built(bool value) { if (value) { } } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)) + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .OrderBy(parent => parent, StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Root.Helper(System.Boolean)")); + Assert.That(parents, Does.Contain("Fixture.Built..ctor(System.Boolean)")); + Assert.That(parents, Does.Contain("Fixture.Root.Value/get")); + Assert.That(parents, Has.Some.Contains("/local/Local()")); + Assert.That(parents, Does.Not.Contain("Fixture.Root.Dead(System.Boolean)")); + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "xml-read").Select(surface => surface.Name), + Does.Contain("reachable") + ); + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "xml-read").Select(surface => surface.Name), + Does.Not.Contain("dead") + ); + }); + } + + [Test] + public void FiniteSourceInterfaceDispatchExpandsEveryImplementationDeterministically() + { + const string Source = """ + namespace Fixture; + public interface IWorker { void Work(bool value); } + public sealed class First : IWorker { public void Work(bool value) { if (value) { } } } + public sealed class Second : IWorker { public void Work(bool value) { if (!value) { } } } + public sealed class Root + { + public void Run(IWorker worker, bool value) { worker.Work(value); } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.IWorker,System.Boolean)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .OrderBy(parent => parent, StringComparer.Ordinal) + .ToArray(); + + Assert.That( + parents, + Is.EqualTo(new[] { "Fixture.First.Work(System.Boolean)", "Fixture.Second.Work(System.Boolean)" }) + ); + Assert.That(inventory.Diagnostics, Is.Empty); + } + + [Test] + public void RecursiveStronglyConnectedComponentTerminatesAndIncludesEveryReachableBodyOnce() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public void First(bool value) { if (value) Second(value); } + private void Second(bool value) { if (value) First(value); } + private void Dead(bool value) { if (value) { } } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.First(System.Boolean)"); + + Assert.That( + inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent) + .Distinct(StringComparer.Ordinal), + Is.EquivalentTo(new[] { "Fixture.Root.First(System.Boolean)", "Fixture.Root.Second(System.Boolean)" }) + ); + } + + [Test] + public void MutableDelegateDispatchIsRetainedAsRedInventoryDiagnostic() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public Func Selector { get; set; } = value => value; + public bool Run(bool value) => Selector(value); + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + + Assert.That( + inventory.Diagnostics.Select(diagnostic => diagnostic.Code), + Does.Contain("unresolved-delegate-dispatch") + ); + Assert.That( + inventory.Diagnostics.Single(diagnostic => diagnostic.Code == "unresolved-delegate-dispatch").SubjectId, + Is.EqualTo("Fixture.Root.Run(System.Boolean)") + ); + } + + [Test] + public void DynamicAndOpenExternalDispatchAreRetainedAsCallsiteSpecificDiagnostics() + { + const string Source = """ + using System; + using System.IO; + namespace Fixture; + public sealed class Root + { + public int Run(dynamic target, Stream stream, byte[] buffer) + { + target.Execute(); + return stream.Read(buffer, 0, Math.Abs(buffer.Length)); + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(dynamic,System.IO.Stream,System.Byte[])"); + + Assert.Multiple(() => + { + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("unresolved-call-dispatch")); + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("external-virtual-dispatch")); + Assert.That( + inventory.Diagnostics, + Has.None.Matches(item => + item.Message.Contains("System.Math.Abs", StringComparison.Ordinal) + ) + ); + Assert.That(inventory.Diagnostics.All(item => item.Location.Length != 0), Is.True); + Assert.That( + inventory.Diagnostics.Select(item => item.Location).Distinct(StringComparer.Ordinal).Count(), + Is.EqualTo(inventory.Diagnostics.Count) + ); + }); + } + + [Test] + public void InterfaceDispatchWithoutConcreteSourceImplementationFailsClosed() + { + const string Source = """ + namespace Fixture; + public interface IWorker { void Work(); } + public abstract class Worker : IWorker { public abstract void Work(); } + public sealed class Root { public void Run(IWorker worker) { worker.Work(); } } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.IWorker)"); + + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("unresolved-interface-dispatch")); + } + + [Test] + public void SourceBoundLambdaAndMethodGroupBodiesAreFollowedButUnusedClosuresAreExcluded() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public bool Run(bool value) + { + Func lambda = flag => { if (flag) { } return flag; }; + Func method = Helper; + Func unused = flag => { if (!flag) { } return flag; }; + void UnusedLocal() { if (value) { } } + return lambda(value) && method(value); + } + private static bool Helper(bool value) { if (value) { } return value; } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Root.Helper(System.Boolean)")); + Assert.That(parents, Has.Some.Contains("lambda")); + Assert.That(parents, Has.None.Contains("UnusedLocal")); + Assert.That(parents.Count(parent => parent.Contains("lambda", StringComparison.Ordinal)), Is.EqualTo(1)); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void StaticCallbackPassedThroughExternalApiIsFollowedAndMutableCallbackFailsClosed() + { + const string Source = """ + using System; + using System.Collections.Generic; + using System.Linq; + namespace Fixture; + public sealed class Root + { + public Func Selector { get; set; } = value => true; + public int Run(IEnumerable values) + { + _ = values.Where(IsPositive).ToArray(); + return values.Where(Selector).Count(); + } + private static bool IsPositive(int value) { if (value > 0) { } return value > 0; } + } + """; + + SemanticInventory inventory = Inventory( + Source, + "Fixture.Root.Run(System.Collections.Generic.IEnumerable`1)" + ); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "decision-if").Select(surface => surface.Parent), + Does.Contain("Fixture.Root.IsPositive(System.Int32)") + ); + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("unresolved-delegate-dispatch")); + }); + } + + [Test] + public void TypeReferencesDoNotExpandDeadMembersAndDeadUnresolvedCallsAreIgnored() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public Type Run() => typeof(Dead); + private void DeadCall(string value) { Missing.Telemetry.Record(value); } + } + public sealed class Dead { public void Body(bool value) { if (value) { } } } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()"); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "decision-if").Select(surface => surface.Parent), + Does.Not.Contain("Fixture.Dead.Body(System.Boolean)") + ); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void InterfacePropertyDispatchFollowsConcreteGettersWithoutIncludingSetters() + { + const string Source = """ + namespace Fixture; + public interface IWorker { bool Value { get; } } + public sealed class First : IWorker { public bool Value { get { if (true) { } return true; } } } + public sealed class Second : IWorker { public bool Value { get { if (false) { } return false; } } } + public sealed class Root + { + public bool Local { get { return true; } set { if (value) { } } } + public bool Run(IWorker worker) => worker.Value && Local; + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.IWorker)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.First.Value/get")); + Assert.That(parents, Does.Contain("Fixture.Second.Value/get")); + Assert.That(parents, Does.Not.Contain("Fixture.Root.Local/set")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void SeparateUnresolvedDelegateCallsitesRemainSeparateDiagnostics() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public Func Selector { get; set; } = value => value; + public bool Run(bool value) + { + bool first = Selector(value); + bool second = Selector(!value); + return first && second; + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + InventoryDiagnostic[] diagnostics = inventory + .Diagnostics.Where(item => item.Code == "unresolved-delegate-dispatch") + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(diagnostics, Has.Length.EqualTo(2)); + Assert.That( + diagnostics.Select(item => item.Location).Distinct(StringComparer.Ordinal).Count(), + Is.EqualTo(2) + ); + }); + } + + [Test] + public void SemanticCompilationErrorsFailClosedBeforeClosure() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public bool Run(string value) + { + Missing.Execute(); + return value.Equals("ok"); + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.String)"); + + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("compilation-error")); + } + + [Test] + public void ExactSealedMetadataDispatchIsNotAnOpenBoundary() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public bool Run(string value) => value.Equals("ok"); + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.String)"); + + Assert.That(inventory.Diagnostics, Is.Empty); + } + + [Test] + public void ConstructionFollowsInstanceInitializersImplicitBaseConstructorAndExactBaseCall() + { + const string Source = """ + namespace Fixture; + public class Base + { + public Base() { if (true) { } } + public virtual bool Value(bool value) { if (value) { } return value; } + } + public sealed class Built : Base + { + private readonly bool _initialized = Initialize(); + public Built() { } + public override bool Value(bool value) { if (!value) { } return base.Value(value); } + public bool Run(bool value) => base.Value(value) && _initialized; + private static bool Initialize() { if (true) { } return true; } + } + public sealed class Root { public Built Run() => new Built(); } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()", "Fixture.Built.Run(System.Boolean)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Base..ctor()")); + Assert.That(parents, Does.Contain("Fixture.Built.Initialize()")); + Assert.That(parents, Does.Contain("Fixture.Base.Value(System.Boolean)")); + Assert.That(parents, Does.Not.Contain("Fixture.Built.Value(System.Boolean)")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void OverrideChainsExpandPastAnIntermediateOverride() + { + const string Source = """ + namespace Fixture; + public class Base { public virtual void Work(bool value) { if (value) { } } } + public class Middle : Base { public override void Work(bool value) { if (!value) { } } } + public sealed class Leaf : Middle { public override void Work(bool value) { if (value) { } } } + public sealed class Root { public void Run(Middle worker, bool value) { worker.Work(value); } } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.Middle,System.Boolean)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Middle.Work(System.Boolean)")); + Assert.That(parents, Does.Contain("Fixture.Leaf.Work(System.Boolean)")); + Assert.That(parents, Does.Not.Contain("Fixture.Base.Work(System.Boolean)")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void ImplicitConstructionAndConstructorArgumentsExecuteInitializersAndBaseEdges() + { + const string Source = """ + namespace Fixture; + public class Base + { + public Base(int value) { if (value > 0) { } } + } + public sealed class Built : Base + { + private readonly bool _value = Initialize(); + public Built() : base(Choose()) { } + private static int Choose() { if (true) { } return 1; } + private static bool Initialize() { if (true) { } return true; } + } + public sealed class Implicit + { + private readonly bool _value = Initialize(); + private readonly bool _direct = true ? true : false; + private static bool Initialize() { if (true) { } return true; } + } + public sealed class Root + { + public void Run() { _ = new Built(); _ = new Implicit(); } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Base..ctor(System.Int32)")); + Assert.That(parents, Does.Contain("Fixture.Built.Choose()")); + Assert.That(parents, Does.Contain("Fixture.Built.Initialize()")); + Assert.That(parents, Does.Contain("Fixture.Implicit.Initialize()")); + Assert.That( + inventory + .Surfaces.Where(surface => surface.Kind == "decision-conditional") + .Select(surface => surface.Parent), + Does.Contain("Fixture.Implicit._direct") + ); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void CompoundAndBasePropertyAccessUseEveryExactAccessor() + { + const string Source = """ + namespace Fixture; + public class Base + { + private int _value; + public virtual int Value + { + get { if (_value > 0) { } return _value; } + set { if (value > 0) { } _value = value; } + } + } + public sealed class Derived : Base + { + public override int Value + { + get { if (true) { } return 1; } + set { if (value < 0) { } } + } + public void Run() { base.Value += 1; } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Derived.Run()"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Base.Value/get")); + Assert.That(parents, Does.Contain("Fixture.Base.Value/set")); + Assert.That(parents, Does.Not.Contain("Fixture.Derived.Value/get")); + Assert.That(parents, Does.Not.Contain("Fixture.Derived.Value/set")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void OperatorsConversionsAndExpressionBodiedAccessorsAreExecutionEdges() + { + const string Source = """ + namespace Fixture; + public readonly struct Number + { + public int Value => true ? 1 : 0; + public static Number operator +(Number left, Number right) + { + if (left.Value > 0) { } + return left; + } + public static explicit operator bool(Number value) + { + if (value.Value > 0) { } + return true; + } + } + public sealed class Root + { + public bool Run(Number left, Number right) => (bool)(left + right); + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.Number,Fixture.Number)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind.StartsWith("decision-", StringComparison.Ordinal)) + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Number.operator-op_Addition(Fixture.Number,Fixture.Number)")); + Assert.That(parents, Does.Contain("Fixture.Number.conversion-op_Explicit(Fixture.Number)")); + Assert.That(parents, Does.Contain("Fixture.Number.Value/get")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void DelegateFactoryExecutionIsFollowedBeforeTheReturnedDelegateIsDiagnosed() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public bool Run(bool value) + { + Func callback = Make(value); + return callback(); + } + private static Func Make(bool value) + { + if (value) { } + return () => value; + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "decision-if").Select(surface => surface.Parent), + Does.Contain("Fixture.Root.Make(System.Boolean)") + ); + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("unresolved-delegate-dispatch")); + }); + } + + [Test] + public void CompileTimeDeadBranchesDoNotReachCallees() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public void Run() { if (false) Dead(); } + private static void Dead() { if (true) { } } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()"); + + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "decision-if").Select(surface => surface.Parent), + Does.Not.Contain("Fixture.Root.Dead()") + ); + } + + [Test] + public void DiagnosticRecordPreservesFourValueDeconstructionCompatibility() + { + var diagnostic = new InventoryDiagnostic("code", "subject", "message", "configuration", "location"); + + (string code, string subject, string message, string configurations) = diagnostic; + + Assert.That( + new[] { code, subject, message, configurations }, + Is.EqualTo(new[] { "code", "subject", "message", "configuration" }) + ); + Assert.That(diagnostic.Location, Is.EqualTo("location")); + } + + [Test] + public void LambdaIdentityIsStableAcrossPreprocessorConfigurations() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public bool Run(bool value) + { + #if OUTPUT_ANALYSES + Func gated = flag => flag; + _ = gated(value); + #endif + Func shared = flag => { if (flag) { } return flag; }; + return shared(value); + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + InventorySurface[] shared = inventory.Surfaces.Where(surface => surface.Kind == "decision-if").ToArray(); + + Assert.Multiple(() => + { + Assert.That( + shared.Select(surface => surface.Parent).Distinct(StringComparer.Ordinal).Count(), + Is.EqualTo(1) + ); + Assert.That( + shared.Select(surface => surface.Configurations).Distinct(StringComparer.Ordinal), + Is.EqualTo(new[] { "OUTPUT_ANALYSES,OUTPUT_ANALYSES+SINGLE_THREADED,SINGLE_THREADED,base" }) + ); + }); + } + + [Test] + public void StaticInitializationIsAnExecutionEdgeOfConstructionAndStaticUse() + { + const string Source = """ + namespace Fixture; + public sealed class Built + { + private static readonly bool Initialized = Initialize(); + static Built() { if (Initialized) { } } + private static bool Initialize() { if (true) { } return true; } + public static bool Value => Initialized; + } + public sealed class Root { public bool Run() { _ = new Built(); return Built.Value; } } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Built..cctor()")); + Assert.That(parents, Does.Contain("Fixture.Built.Initialize()")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void DynamicMemberAndGenericConstructionRemainExplicitOpenEdges() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public object Read(dynamic value) { _ = value.Member; return value[0]; } + public T Build() where T : new() => new T(); + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Read(dynamic)", "Fixture.Root.Build`1()"); + + Assert.Multiple(() => + { + Assert.That(inventory.Diagnostics.Count(item => item.Code == "unresolved-dynamic-member"), Is.EqualTo(2)); + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("open-construction-dispatch")); + Assert.That( + inventory.Diagnostics.Select(item => item.Location).Distinct(StringComparer.Ordinal).Count(), + Is.EqualTo(inventory.Diagnostics.Count) + ); + }); + } + + [Test] + public void ConditionalAccessAndCoalescingAreInventoriedAsExecutionDecisions() + { + const string Source = """ + namespace Fixture; + public sealed class Item { public string Value => "value"; } + public sealed class Root + { + public string Run(Item item, string fallback) => item?.Value ?? fallback; + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.Item,System.String)"); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces.Count(surface => surface.Kind == "decision-conditional-access"), + Is.EqualTo(2) + ); + Assert.That(inventory.Surfaces.Count(surface => surface.Kind == "decision-coalesce"), Is.EqualTo(2)); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void SourceDelegateParametersBindToConsumedCallbacksButIgnoreUnusedCallbacks() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public bool Run(bool value) + { + Consume(() => { if (value) { } return value; }); + Ignore(() => { if (!value) { } return value; }); + return value; + } + private static void Consume(Func callback) { if (true) { } _ = callback(); } + private static void Ignore(Func callback) { } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Root.Consume(System.Func`1)")); + Assert.That(parents.Count(parent => parent.Contains("/lambda@", StringComparison.Ordinal)), Is.EqualTo(1)); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void InheritedInterfaceImplementationMarksConcreteRuleTypeReachable() + { + const string Source = """ + using SIL.Machine.Annotations; + using SIL.Machine.Morphology.HermitCrab; + using SIL.Machine.Rules; + namespace Fixture; + public abstract class BaseRule : IHCRule + { + public string Name { get; set; } + public IRule CompileAnalysisRule(Morpher morpher) + { + if (morpher is null) { } + return null; + } + public IRule CompileSynthesisRule(Morpher morpher) => null; + } + public sealed class ConcreteRule : BaseRule { } + public sealed class Root + { + public void Run(IHCRule rule, Morpher morpher) { _ = rule.CompileAnalysisRule(morpher); } + } + """; + + SemanticInventory inventory = Inventory( + Source, + "Fixture.Root.Run(SIL.Machine.Morphology.HermitCrab.IHCRule,SIL.Machine.Morphology.HermitCrab.Morpher)" + ); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces.Select(surface => surface.Id), + Does.Contain("model:rule/Fixture.ConcreteRule/IHCRule") + ); + Assert.That( + inventory.Surfaces.Where(surface => surface.Kind == "decision-if").Select(surface => surface.Parent), + Does.Contain("Fixture.BaseRule.CompileAnalysisRule(SIL.Machine.Morphology.HermitCrab.Morpher)") + ); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void EverySemanticCompilationErrorFailsClosedBeforeClosure() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public int Run() + { + string invalid = 1; + return Helper(); + } + private static int Helper() { if (true) { } return 1; } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root"); + + Assert.Multiple(() => + { + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("compilation-error")); + Assert.That( + inventory.Surfaces, + Has.None.Matches(surface => surface.Parent == "Fixture.Root.Helper()") + ); + }); + } + + [Test] + public void RepositorySourcePathCannotBypassSemanticCompilationFailure() + { + const string Source = """ + namespace Fixture; + public sealed class Root + { + public int Run(string value) + { + int invalid = value; + return invalid; + } + } + """; + SemanticInventory inventory = SemanticCoverageInventory.Generate( + new SemanticCoverageSourceSet( + "fixture.dtd", + Dtd, + new[] + { + new CSharpInventoryInput( + "src/Fixture/Root.cs", + Source, + new[] { "Fixture.Root.Run(System.String)" } + ), + } + ) + ); + + Assert.That(inventory.Diagnostics.Select(item => item.Code), Does.Contain("compilation-error")); + } + + [Test] + public void ImplicitStaticInitializationWalksEveryInitializerFromStaticUse() + { + const string Source = """ + namespace Fixture; + public sealed class Built + { + private static readonly bool First = InitializeFirst(); + private static readonly bool Second = InitializeSecond(); + private static bool InitializeFirst() { if (true) { } return true; } + private static bool InitializeSecond() { if (false) { } return false; } + public static bool Value => First || Second; + } + public sealed class Root { public bool Run() => Built.Value; } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Built.InitializeFirst()")); + Assert.That(parents, Does.Contain("Fixture.Built.InitializeSecond()")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void InterfaceDispatchBindsCallbackToTheConsumingImplementation() + { + const string Source = """ + using System; + namespace Fixture; + public interface IConsumer { void Consume(Func callback); } + public sealed class Consumer : IConsumer + { + public void Consume(Func callback) { _ = callback(); } + } + public sealed class Root + { + public bool Run(IConsumer consumer, bool value) + { + consumer.Consume(() => { if (value) { } return value; }); + return value; + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(Fixture.IConsumer,System.Boolean)"); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces.Count(surface => + surface.Kind == "decision-if" && surface.Parent!.Contains("/lambda@", StringComparison.Ordinal) + ), + Is.EqualTo(2) + ); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void IgnoredDelegateStillEvaluatesItsFactoryWithoutInvokingTheReturnedCallback() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public void Run() { Ignore(MakeCallback()); } + private static void Ignore(Func callback) { } + private static Func MakeCallback() + { + if (true) { } + return () => { if (false) { } return false; }; + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run()"); + string[] parents = inventory + .Surfaces.Where(surface => surface.Kind == "decision-if") + .Select(surface => surface.Parent!) + .Distinct(StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(parents, Does.Contain("Fixture.Root.MakeCallback()")); + Assert.That(parents, Has.None.Contains("/lambda@")); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } + + [Test] + public void DelegateReferenceInsideDeadNestedFunctionDoesNotConsumeCallback() + { + const string Source = """ + using System; + namespace Fixture; + public sealed class Root + { + public void Run(bool value) + { + Ignore(() => { if (value) { } return value; }); + } + private static void Ignore(Func callback) + { + void Dead() { _ = callback(); } + } + } + """; + + SemanticInventory inventory = Inventory(Source, "Fixture.Root.Run(System.Boolean)"); + + Assert.Multiple(() => + { + Assert.That( + inventory.Surfaces, + Has.None.Matches(surface => + surface.Parent?.Contains("/lambda@", StringComparison.Ordinal) == true + ) + ); + Assert.That(inventory.Diagnostics, Is.Empty); + }); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FeatureSystemBreadthJointCounterfactualTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FeatureSystemBreadthJointCounterfactualTests.cs new file mode 100644 index 000000000..063825097 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FeatureSystemBreadthJointCounterfactualTests.cs @@ -0,0 +1,76 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Pins the four catch-22 isActive="no" surfaces in edge-cases/feature-system-breadth +/// (ComplexFeature, SymbolicFeature, SegmentNaturalClass, FeatureNaturalClass) to +/// , each via its dedicated inactive partner. +/// +[TestFixture] +public sealed class FeatureSystemBreadthJointCounterfactualTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static Fixture LoadFixture() + { + string root = RepositoryRoot(); + return Fixture + .DiscoverAll(Path.Combine(root, "conformance")) + .Single(f => f.Id == "edge-cases/feature-system-breadth"); + } + + private string _scratchDirectory = string.Empty; + + [SetUp] + public void SetUp() + { + _scratchDirectory = Path.Combine( + Path.GetTempPath(), + "hc-feature-system-breadth-joint-tests", + Guid.NewGuid().ToString("N") + ); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_scratchDirectory)) + Directory.Delete(_scratchDirectory, recursive: true); + } + + [TestCase("dtd:enum/SymbolicFeature/isActive/no")] + [TestCase("dtd:enum/ComplexFeature/isActive/no")] + [TestCase("dtd:enum/SegmentNaturalClass/isActive/no")] + [TestCase("dtd:enum/FeatureNaturalClass/isActive/no")] + public void TheSurfaceIsEvidencedOnlyJointly(string surfaceId) + { + Fixture fixture = LoadFixture(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(RepositoryRoot()); + IReadOnlyList baseline = CounterfactualGate.ComputeBaseline(fixture); + + CounterfactualResult result = CounterfactualGate.EvaluateJointly( + fixture, + surfaceId, + inventory, + baseline, + _scratchDirectory + ); + + Assert.That(result.Verdict, Is.EqualTo(CounterfactualVerdict.EvidencedJointly), $"{surfaceId}: {result.Delta}"); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FeatureValueDisjointProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FeatureValueDisjointProofsTests.cs new file mode 100644 index 000000000..39d0756f0 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FeatureValueDisjointProofsTests.cs @@ -0,0 +1,259 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class FeatureValueDisjointProofsTests +{ + // Mirrors edge-cases/mpr-gated-exception's prNasalAssimBilabial~prNasalAssimAlveolar shape: a shared + // placeholder input (cN), each rule gated by a disjoint featPlace value, and outputs (cM/cAlv) that + // belong to neither the other's environment nor its input class. + private const string DisjointGrammar = """ + + + place + otherbilabialalveolar + + + Main + N + m + n + + + placeholder + bilabial + alveolar + + + bilabialAssim + + + + + + + alveolarAssim + + + + + + + + S + + """; + + // ncAlveolar now also admits pBilabial, so it shares cM with ncBilabial -- the environment classes + // overlap and the pair must be refused. + private const string OverlappingEnvironmentGrammar = """ + + + place + otherbilabialalveolar + + + Main + N + m + n + + + placeholder + bilabial + alveolar + + + bilabialAssim + + + + + + + alveolarAssim + + + + + + + + S + + """; + + // prA's output is changed to cAlv, which IS a member of prB's own environment class ncAlveolar: firing + // prA could create a brand-new site for prB, so the pair must be refused. + private const string OutputInOtherEnvironmentGrammar = """ + + + place + otherbilabialalveolar + + + Main + N + m + n + + + placeholder + bilabial + alveolar + + + bilabialAssim + + + + + + + alveolarAssim + + + + + + + + S + + """; + + private const string NoEnvironmentGrammar = """ + + Main + N + m + + + a + + + + + + b + + + + + + + S + + """; + + [Test] + public void BuildsAProofForDisjointPlaceEnvironmentsWithNoFeedingChannel() + { + XDocument grammar = XDocument.Parse(DisjointGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = FeatureValueDisjointProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(FeatureValueDisjointProofs.Kind)); + Assert.That(FeatureValueDisjointProofs.Verify(grammar, "fx", proof), Is.True); + } + + // Core rejection: overlapping environment classes must never license this proof kind. + [Test] + public void RefusesWhenTheEnvironmentClassesOverlap() + { + XDocument grammar = XDocument.Parse(OverlappingEnvironmentGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(FeatureValueDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Core rejection: an output that IS a member of the other rule's environment class must never license + // this proof kind, even when the environment classes themselves are disjoint. + [Test] + public void RefusesWhenOneRulesOutputIsAMemberOfTheOthersEnvironmentClass() + { + XDocument grammar = XDocument.Parse(OutputInOtherEnvironmentGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(FeatureValueDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: a rule with no Environment at all fires unconditionally, so the mutual-exclusion argument + // this kind depends on does not apply. + [Test] + public void RefusesWhenNeitherRuleDeclaresAnEnvironment() + { + XDocument grammar = XDocument.Parse(NoEnvironmentGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(FeatureValueDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: this kind is scoped to Stratum phonologicalRules pairs between two PhonologicalRule elements. + [Test] + public void RefusesAPairInvolvingAMetathesisRule() + { + XDocument grammar = XDocument.Parse( + """ + + + a + + + + + + + m + + S + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(FeatureValueDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // The core rejection the task asks for: a proof built while the environment classes were disjoint must + // be REJECTED once one class is widened to overlap the other. + [Test] + public void VerifyRejectsAProofOnceTheEnvironmentClassesAreWidenedToOverlap() + { + XDocument original = XDocument.Parse(DisjointGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(original, "fx").Single(); + Proof proof = FeatureValueDisjointProofs.TryBuild(original, item)!; + + XDocument widened = XDocument.Parse(OverlappingEnvironmentGrammar); + + Assert.That(FeatureValueDisjointProofs.Verify(widened, "fx", proof), Is.False); + } + + // The second stale-proof scenario: a proof built while outputs stayed clear of each other's + // environment must be REJECTED once one rule's output is changed to land inside the other's. + [Test] + public void VerifyRejectsAProofOnceAnOutputIsChangedToLandInTheOthersEnvironment() + { + XDocument original = XDocument.Parse(DisjointGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(original, "fx").Single(); + Proof proof = FeatureValueDisjointProofs.TryBuild(original, item)!; + + XDocument changedOutput = XDocument.Parse(OutputInOtherEnvironmentGrammar); + + Assert.That(FeatureValueDisjointProofs.Verify(changedOutput, "fx", proof), Is.False); + } + + [Test] + public void VerifyRejectsAStaleProofWhoseItemNoLongerExists() + { + XDocument grammar = XDocument.Parse(DisjointGrammar); + var stale = new Proof("ordering:fx/phonologicalRules/gone~alsoGone", FeatureValueDisjointProofs.Kind, "stale"); + + Assert.That(FeatureValueDisjointProofs.Verify(grammar, "fx", stale), Is.False); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FieldworksProducibilityLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FieldworksProducibilityLedgerTests.cs new file mode 100644 index 000000000..27ebffd24 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FieldworksProducibilityLedgerTests.cs @@ -0,0 +1,193 @@ +using System.Text.RegularExpressions; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +// conformance/fieldworks-producibility.tsv records whether FieldWorks' HCLoader (a component that +// lives in the separate FieldWorks repo, not this one) can ever produce each construct this suite's +// other ledgers measure. That repo is not a dependency of this one, so nothing here may open it or +// fail when its content drifts -- a deliberate, permanent limitation, not an oversight. What these +// tests DO check is the file's own internal shape: well-formed, and every subject named by two sources +// already inside this repo (the FailureReason enum and interface-inventory.tsv) appears exactly +// once. That is exactly what conformance/tools/generate-fieldworks-producibility.ps1 already +// enforces at generation time; these tests pin the same guarantee against the checked-in file so a +// hand-edit that bypasses the generator is also caught. +[TestFixture] +public sealed class FieldworksProducibilityLedgerTests +{ + private const string RelativePath = "conformance/fieldworks-producibility.tsv"; + private const string TraceManagerRelativePath = "src/SIL.Machine.Morphology.HermitCrab/ITraceManager.cs"; + private static readonly string[] ExpectedHeader = + { + "subject_kind", + "subject", + "producible", + "hcloader_sites", + "notes", + }; + private static readonly HashSet AllowedProducible = new() { "Yes", "No", "Conditional" }; + private static readonly HashSet AllowedKinds = new() { "failure-reason", "interface-attribute" }; + + private sealed record Row( + string SubjectKind, + string Subject, + string Producible, + string HcloaderSites, + string Notes + ); + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static IReadOnlyList LoadRows(string root) + { + string path = Path.Combine(root, RelativePath.Replace('/', Path.DirectorySeparatorChar)); + Assert.That(File.Exists(path), Is.True, $"{RelativePath} does not exist"); + + string[] dataLines = File.ReadAllLines(path).Where(line => line.Length > 0 && !line.StartsWith("#")).ToArray(); + + Assert.That(dataLines, Is.Not.Empty, $"{RelativePath} has no data"); + string[] header = dataLines[0].Split('\t'); + Assert.That(header, Is.EqualTo(ExpectedHeader), $"{RelativePath} header does not match the expected columns"); + + var rows = new List(); + foreach (string line in dataLines.Skip(1)) + { + string[] cols = line.Split('\t'); + Assert.That(cols, Has.Length.EqualTo(ExpectedHeader.Length), $"malformed row (wrong column count): {line}"); + rows.Add(new Row(cols[0], cols[1], cols[2], cols[3], cols[4])); + } + + return rows; + } + + // Mirrors what generate-fieldworks-producibility.ps1 extracts mechanically from ITraceManager.cs, + // so a FailureReason added or removed there is caught here too, independent of the generator. + private static IReadOnlyList ExpectedFailureReasons(string root) + { + string path = Path.Combine(root, TraceManagerRelativePath.Replace('/', Path.DirectorySeparatorChar)); + string text = File.ReadAllText(path); + Match match = Regex.Match(text, @"public enum FailureReason\s*\{(?[^}]*)\}"); + Assert.That(match.Success, Is.True, "Could not locate FailureReason enum in ITraceManager.cs"); + return match + .Groups["body"] + .Value.Split(',') + .Select(s => s.Trim()) + .Where(s => s.Length > 0 && s != "None") + .ToArray(); + } + + private static IReadOnlyList ExpectedInterfaceAttributes(string root) + { + IReadOnlyList rows = InterfaceInventoryLedger.Compute(root); + return rows.Select(r => $"{r.Element}.{r.Attribute}").ToArray(); + } + + [Test] + public void FileIsWellFormedAndEveryProducibleValueIsRecognized() + { + IReadOnlyList rows = LoadRows(RepositoryRoot()); + + Assert.Multiple(() => + { + foreach (Row row in rows) + { + Assert.That( + AllowedKinds, + Does.Contain(row.SubjectKind), + $"unrecognized subject_kind for {row.Subject}" + ); + Assert.That( + AllowedProducible, + Does.Contain(row.Producible), + $"unrecognized producible value for {row.Subject}" + ); + Assert.That(row.Subject, Is.Not.Empty, "subject must not be empty"); + + if (row.Producible == "Yes") + { + Assert.That(row.HcloaderSites, Is.Not.Empty, $"{row.Subject} is Yes but cites no hcloader_sites"); + } + + if (row.Producible == "No") + { + Assert.That( + row.Notes, + Is.Not.Empty, + $"{row.Subject} is No but has no notes explaining what was searched" + ); + } + } + }); + } + + [Test] + public void EverySubjectAppearsExactlyOnce() + { + IReadOnlyList rows = LoadRows(RepositoryRoot()); + + var seen = new HashSet<(string Kind, string Subject)>(); + var duplicates = new List(); + foreach (Row row in rows) + { + if (!seen.Add((row.SubjectKind, row.Subject))) + duplicates.Add($"{row.SubjectKind}/{row.Subject}"); + } + + Assert.That(duplicates, Is.Empty, $"duplicate subjects: {string.Join(", ", duplicates)}"); + } + + // The completeness guarantee: every FailureReason and every interface-inventory attribute + // ALREADY IN THIS REPO must be covered, and nothing else. This can drift only when this repo's + // own sources change -- never when the separate FieldWorks repo changes underneath the verdicts. + [Test] + public void CoversExactlyEveryFailureReasonAndEveryInterfaceAttributeInThisRepo() + { + string root = RepositoryRoot(); + IReadOnlyList rows = LoadRows(root); + + IReadOnlyList expectedFailureReasons = ExpectedFailureReasons(root); + IReadOnlyList expectedInterfaceAttributes = ExpectedInterfaceAttributes(root); + + var actualFailureReasons = rows.Where(r => r.SubjectKind == "failure-reason").Select(r => r.Subject).ToArray(); + var actualInterfaceAttributes = rows.Where(r => r.SubjectKind == "interface-attribute") + .Select(r => r.Subject) + .ToArray(); + + Assert.That(actualFailureReasons, Is.EquivalentTo(expectedFailureReasons)); + Assert.That(actualInterfaceAttributes, Is.EquivalentTo(expectedInterfaceAttributes)); + Assert.That(rows, Has.Count.EqualTo(expectedFailureReasons.Count + expectedInterfaceAttributes.Count)); + } + + // Pins the headline counts reported alongside this ledger, so a silent hand-edit that flips a + // verdict without updating the report is caught the same way OrderingGeneratorTests pins other + // ledgers' checked-in numbers. + [Test] + public void PinsTheHeadlineProducibleCounts() + { + IReadOnlyList rows = LoadRows(RepositoryRoot()); + + int yes = rows.Count(r => r.Producible == "Yes"); + int no = rows.Count(r => r.Producible == "No"); + int conditional = rows.Count(r => r.Producible == "Conditional"); + + TestContext.Out.WriteLine($"producible: Yes={yes} No={no} Conditional={conditional}"); + + Assert.That(rows, Has.Count.EqualTo(83)); + Assert.That(yes, Is.EqualTo(61)); + Assert.That(no, Is.EqualTo(22)); + Assert.That(conditional, Is.EqualTo(0)); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FoldInCandidateLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FoldInCandidateLedgerTests.cs new file mode 100644 index 000000000..6e302c9c9 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/FoldInCandidateLedgerTests.cs @@ -0,0 +1,109 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class FoldInCandidateLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // The primary deliverable this whole traceability build was for. Interface layer: WITNESS-based + // analysis finds only 1 interface (MorphologicalInput.excludedMPRFeatures) witnessed only by a + // fabricated edge case -- down from the presence-based count of 2 the original brief cited + // (SymbolicFeature.defaultSymbol drops out entirely: DefaultSymbolIsPresentButNeverWitnessed in + // InterfaceWitnessLedgerTests shows it is never witnessed ANYWHERE, so it was never a genuine + // "edge-case-only" case, just an artifact of counting presence as coverage). 27 more interfaces are + // present somewhere but witnessed nowhere -- not fold-in candidates, but a named gap. Surface + // layer: 57 unit surfaces are clean fold-in candidates (witnessed only by an edge case, and no + // language grammar even structurally contains them). + // + // surfacePresentElsewhere dropped 30 -> 8: CounterfactualLedger.Sweep used to keep only the + // first-discovered fixture per surface on a verdict tie, and Fixture.DiscoverAll sorts + // edge-cases/* before languages/*, so a languages/* fixture that merely TIED for the same verdict + // was invisible -- 22 of the 30 were actually already witnessed by a language grammar, just masked + // by the tie-break. Fixed by recording every tied fixture (CounterfactualResult.WitnessingFixtures, + // the ledger's witnessed_by column) and having FoldInCandidateLedger check that full set instead of + // the single recorded fixture. + [Test] + public void CheckedInLedgerHasTheMeasuredCategoryCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = FoldInCandidateLedger.Read(root); + + int interfaceEdgeCaseOnly = rows.Count(r => + r.Layer == ObligationLayer.Interface && r.Category == FoldInCategory.EdgeCaseOnly + ); + int interfaceNeverWitnessed = rows.Count(r => + r.Layer == ObligationLayer.Interface && r.Category == FoldInCategory.NeverWitnessed + ); + int surfaceEdgeCaseOnly = rows.Count(r => + r.Layer == ObligationLayer.Surface && r.Category == FoldInCategory.EdgeCaseOnly + ); + int surfacePresentElsewhere = rows.Count(r => + r.Layer == ObligationLayer.Surface && r.Category == FoldInCategory.PresentInLanguageGrammarAlready + ); + + TestContext.Out.WriteLine( + $"rows={rows.Count} interfaceEdgeCaseOnly={interfaceEdgeCaseOnly} " + + $"interfaceNeverWitnessed={interfaceNeverWitnessed} surfaceEdgeCaseOnly={surfaceEdgeCaseOnly} " + + $"surfacePresentElsewhere={surfacePresentElsewhere}" + ); + + Assert.That(rows, Has.Count.EqualTo(92)); + Assert.That(interfaceEdgeCaseOnly, Is.EqualTo(2)); + Assert.That(interfaceNeverWitnessed, Is.EqualTo(25)); + Assert.That(surfaceEdgeCaseOnly, Is.EqualTo(57)); + Assert.That(surfacePresentElsewhere, Is.EqualTo(8)); + } + + [Test] + public void InterfaceFoldInCandidatesAreTheEdgeCaseOnlyMprAndCompoundOutput() + { + string root = RepositoryRoot(); + IReadOnlyList rows = FoldInCandidateLedger.Read(root); + + FoldInCandidateLedger.Row[] candidates = rows.Where(r => + r.Layer == ObligationLayer.Interface && r.Category == FoldInCategory.EdgeCaseOnly + ) + .ToArray(); + + Assert.That(candidates, Has.Length.EqualTo(2)); + Assert.That( + candidates.Select(r => r.Obligation), + Is.EquivalentTo(new[] { "CompoundingRule.outputPartOfSpeech", "MorphologicalInput.excludedMPRFeatures" }) + ); + } + + // Cheap: reads InterfaceInventoryLedger/InterfaceWitnessLedger/EvidenceLedger back off disk plus a + // structural (no-reparse) GrammarFeatureUsage scan of every languages/* grammar -- no severance + // sweep of its own, so no [Explicit] needed. + [Test] + public void CheckedInFoldInCandidateLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList fresh = FoldInCandidateLedger.Compute(root); + string freshText = FoldInCandidateLedger.ToText(fresh); + string checkedIn = File.ReadAllText( + Path.Combine(root, FoldInCandidateLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + freshText.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-coverage-traceability --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GateObligationLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GateObligationLedgerTests.cs new file mode 100644 index 000000000..3ae7ddf3a --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GateObligationLedgerTests.cs @@ -0,0 +1,272 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class GateObligationLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Pins the headline counts against the CHECKED-IN ledger (GateObligationLedger.Compute runs a real + // traced engine sweep plus severance re-parses -- exactly the cost EngineGateInventoryLedger.Compute + // already pays -- so every assertion test here reads the checked-in file, per this directory's own + // cost convention; only CheckedInGateObligationLedgerIsUpToDate below recomputes, and it is + // [Explicit]). 23 gates x 2 arms (Blocked, Control) = 46. worth_covering is Yes for both arms of the + // same 21 gates (SurfaceFormMismatch fails xml_reachable, ObligatorySyntacticFeatures fails + // flex_producible -- see GateObligationLedger's own doc comment) = 42. Evidenced counts come from a + // real severance + trace-attribution sweep over the current corpus (see gate-obligations.tsv itself + // for exactly which word/fixture backs each one). + [Test] + public void CheckedInLedgerHasTheDeclaredCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + + int gates = rows.Select(r => r.Gate).Distinct().Count(); + int worthCovering = rows.Count(r => r.WorthCovering == "Yes"); + int evidenced = rows.Count(r => r.Status == GateArmStatus.Evidenced); + int notEvidenced = rows.Count(r => r.Status == GateArmStatus.NotEvidenced); + int blockedEvidenced = rows.Count(r => r.Arm == "Blocked" && r.Status == GateArmStatus.Evidenced); + int controlEvidenced = rows.Count(r => r.Arm == "Control" && r.Status == GateArmStatus.Evidenced); + + TestContext.Out.WriteLine( + $"gates={gates} rows={rows.Count} worthCovering={worthCovering} evidenced={evidenced} " + + $"notEvidenced={notEvidenced} blockedEvidenced={blockedEvidenced} controlEvidenced={controlEvidenced}" + ); + + Assert.That(rows, Has.Count.EqualTo(46)); + Assert.That(gates, Is.EqualTo(23)); + Assert.That(worthCovering, Is.EqualTo(42)); + Assert.That(evidenced + notEvidenced, Is.EqualTo(rows.Count)); + // 11 -> 14 (2026-08-19): GrammarRuleIndex.ResolveAncestorRuleId taught the index to walk up + // from MorphologicalInput and PhonologicalSubrule to their rule-element ancestor (always + // MorphologicalRule/RealizationalRule and PhonologicalRule respectively, per the DTD), so the + // Control arms of ExcludedMprFeatures, RequiredMprFeatures and RequiredSyntacticFeatureStruct + // are now attributable to a rule id that fires in a successful parse elsewhere in the same + // fixture. Allomorph and AffixTemplate still resolve to nothing: an Allomorph is always a + // child of LexicalEntry, never of a rule, and an AffixTemplate has no id of its own (the DTD + // never declares one) and is never nested under a rule either -- both are genuinely + // unattributable, not merely unimplemented, so BoundRoot/ExcludedStemName/PartialParse/ + // RequiredStemName's Control arms remain NotEvidenced. blockedEvidenced is unchanged: this + // fix only ever changes how a Control arm's rule id is resolved. + Assert.That(evidenced, Is.EqualTo(14)); + Assert.That(blockedEvidenced, Is.EqualTo(9)); + Assert.That(controlEvidenced, Is.EqualTo(5)); + } + + // Every gate contributes exactly one Blocked row and one Control row -- the denominator is gate x + // arm, never a variable number of arms per gate the way the old chain-cell ledger has McDc vs + // ConditionExtension vs Mutator counts that differ per chain. + [Test] + public void EveryGateHasExactlyOneBlockedAndOneControlRow() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + + foreach (var byGate in rows.GroupBy(r => r.Gate)) + { + Assert.That(byGate.Count(), Is.EqualTo(2), $"{byGate.Key} must have exactly 2 rows"); + Assert.That(byGate.Select(r => r.Arm), Is.EquivalentTo(new[] { "Blocked", "Control" }), byGate.Key); + } + } + + // worth_covering is a pure function of the other two layer verdicts, never an independent judgment + // call -- if this ever drifts, the funnel this ledger reports stops meaning what its own doc + // comment says it means. + [Test] + public void WorthCoveringIsExactlyXmlReachableAndFlexProducible() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + + foreach (GateObligationLedger.Row row in rows) + { + string expected = row.XmlReachable == "Yes" && row.FlexProducible == "Yes" ? "Yes" : "No"; + Assert.That(row.WorthCovering, Is.EqualTo(expected), row.Gate + "/" + row.Arm); + } + } + + // The two known, documented layer blocks, pinned by name so a silent change in either upstream + // ledger (engine-gate-inventory.tsv's DtdAttributes, fieldworks-producibility.tsv) is caught here + // rather than only showing up as a funnel-count drift with no explanation. + [Test] + public void TheTwoNotWorthCoveringGatesFailTheDocumentedLayer() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + + GateObligationLedger.Row surfaceFormMismatch = rows.First(r => + r.Gate == "SurfaceFormMismatch" && r.Arm == "Blocked" + ); + Assert.That(surfaceFormMismatch.XmlReachable, Is.EqualTo("No")); + Assert.That(surfaceFormMismatch.FlexProducible, Is.EqualTo("Yes")); + Assert.That(surfaceFormMismatch.WorthCovering, Is.EqualTo("No")); + + GateObligationLedger.Row obligatorySyntacticFeatures = rows.First(r => + r.Gate == "ObligatorySyntacticFeatures" && r.Arm == "Blocked" + ); + Assert.That(obligatorySyntacticFeatures.XmlReachable, Is.EqualTo("Yes")); + Assert.That(obligatorySyntacticFeatures.FlexProducible, Is.EqualTo("No")); + Assert.That(obligatorySyntacticFeatures.WorthCovering, Is.EqualTo("No")); + + GateObligationLedger.Row[] notWorthCovering = rows.Where(r => r.WorthCovering == "No").ToArray(); + Assert.That( + notWorthCovering.Select(r => r.Gate).Distinct(), + Is.EquivalentTo(new[] { "SurfaceFormMismatch", "ObligatorySyntacticFeatures" }) + ); + } + + // Every NotEvidenced row still names a real, non-empty reason -- the whole point of this ledger over + // a bare "Unknown" collapse. A blank or placeholder evidence string here would silently defeat the + // honesty requirement this ledger exists to satisfy. + [Test] + public void EveryRowCarriesNonEmptyEvidence() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + + Assert.That(rows.All(r => !string.IsNullOrWhiteSpace(r.Evidence)), Is.True); + Assert.That(rows.Any(r => r.Evidence.Trim() == "-"), Is.False); + } + + // Pins exactly which (gate, arm) pairs are Evidenced today, and that each Evidenced row carries a + // real fixture/word rather than the "-" placeholder reserved for NotEvidenced rows. This is the + // regression net: if a future corpus/engine change makes one of these silently stop being + // evidenced, this fails loudly instead of the funnel count quietly drifting. + [Test] + public void EvidencedRowsAreExactlyTheseFourteenAndEachCarriesAFixtureAndWord() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + GateObligationLedger.Row[] evidenced = rows.Where(r => r.Status == GateArmStatus.Evidenced).ToArray(); + + Assert.That( + evidenced.Select(r => (r.Gate, r.Arm)), + Is.EquivalentTo( + new[] + { + ("BoundRoot", "Blocked"), + ("ExcludedMprFeatures", "Blocked"), + ("ExcludedMprFeatures", "Control"), + ("ExcludedStemName", "Blocked"), + ("HeadProdRestrictMprFeatures", "Blocked"), + ("HeadProdRestrictMprFeatures", "Control"), + ("HeadRequiredSyntacticFeatureStruct", "Blocked"), + ("HeadRequiredSyntacticFeatureStruct", "Control"), + ("PartialParse", "Blocked"), + ("RequiredMprFeatures", "Blocked"), + ("RequiredMprFeatures", "Control"), + ("RequiredStemName", "Blocked"), + ("RequiredSyntacticFeatureStruct", "Blocked"), + ("RequiredSyntacticFeatureStruct", "Control"), + } + ) + ); + Assert.That(evidenced.All(r => r.Fixture != "-" && r.Word != "-"), Is.True); + } + + // The five gates with BOTH arms evidenced today. HeadProdRestrictMprFeatures's blocking attribute + // (CompoundingRule.headProdRestrictionsMprFeatures) and HeadRequiredSyntacticFeatureStruct's + // (CompoundingRule.headPartsOfSpeech) sit directly on a CompoundingRule element, which carries its + // own id. ExcludedMprFeatures/RequiredMprFeatures (MorphologicalInput.*MPRFeatures) and + // RequiredSyntacticFeatureStruct (PhonologicalSubrule.requiredPartsOfSpeech) resolve one level up: + // GrammarRuleIndex.ResolveAncestorRuleId walks from the writer element to its nearest rule-element + // ancestor (always MorphologicalRule/RealizationalRule for MorphologicalInput, always + // PhonologicalRule for PhonologicalSubrule, per the DTD). BoundRoot/ExcludedStemName/PartialParse/ + // RequiredStemName still cannot: their writer element is Allomorph (always a child of + // LexicalEntry, never of a rule) or AffixTemplate (no id of its own, and never nested under a + // rule either) -- see GrammarRuleIndex.ResolveAncestorRuleId's own doc comment. This is the "test + // the impossibility argument against already-satisfied ones" check: the SAME ancestor-resolution + // mechanism that fails for BoundRoot (Allomorph) succeeds for the other five -- proving the + // Control arm's remaining limitation is about the ELEMENT KIND, not a broken mechanism. + [Test] + public void FiveGatesHaveBothArmsEvidenced() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Read(root); + + string[] gatesWithBothArmsEvidenced = rows.Where(r => r.Status == GateArmStatus.Evidenced) + .GroupBy(r => r.Gate) + .Where(g => g.Count() == 2) + .Select(g => g.Key) + .ToArray(); + + Assert.That( + gatesWithBothArmsEvidenced, + Is.EquivalentTo( + new[] + { + "ExcludedMprFeatures", + "HeadProdRestrictMprFeatures", + "HeadRequiredSyntacticFeatureStruct", + "RequiredMprFeatures", + "RequiredSyntacticFeatureStruct", + } + ) + ); + + GateObligationLedger.Row boundRootControl = rows.First(r => r.Gate == "BoundRoot" && r.Arm == "Control"); + Assert.That(boundRootControl.Status, Is.EqualTo(GateArmStatus.NotEvidenced)); + Assert.That(boundRootControl.Evidence, Does.Contain("no rule-element ancestor")); + + GateObligationLedger.Row headProdControl = rows.First(r => + r.Gate == "HeadProdRestrictMprFeatures" && r.Arm == "Control" + ); + Assert.That(headProdControl.Status, Is.EqualTo(GateArmStatus.Evidenced)); + Assert.That(headProdControl.Evidence, Does.Contain("CompoundingRule")); + + GateObligationLedger.Row headRequiredControl = rows.First(r => + r.Gate == "HeadRequiredSyntacticFeatureStruct" && r.Arm == "Control" + ); + Assert.That(headRequiredControl.Status, Is.EqualTo(GateArmStatus.Evidenced)); + Assert.That(headRequiredControl.Evidence, Does.Contain("CompoundingRule")); + + GateObligationLedger.Row excludedMprControl = rows.First(r => + r.Gate == "ExcludedMprFeatures" && r.Arm == "Control" + ); + Assert.That(excludedMprControl.Status, Is.EqualTo(GateArmStatus.Evidenced)); + Assert.That(excludedMprControl.Evidence, Does.Contain("MorphologicalInput")); + + GateObligationLedger.Row requiredSyntacticControl = rows.First(r => + r.Gate == "RequiredSyntacticFeatureStruct" && r.Arm == "Control" + ); + Assert.That(requiredSyntacticControl.Status, Is.EqualTo(GateArmStatus.Evidenced)); + Assert.That(requiredSyntacticControl.Evidence, Does.Contain("PhonologicalSubrule")); + } + + // Mirrors EngineGateInventoryLedgerTests.CheckedInEngineGateInventoryLedgerIsUpToDate: recomputing + // this ledger re-runs a traced engine sweep (one parse per word per triggering fixture) plus a + // severance re-parse per candidate -- real engine cost, not something the default suite should pay + // more than once. Every other test in this file reads the checked-in ledger; only this one recomputes. + [Explicit("Runs a traced engine sweep plus severance re-parses across every gate's triggering fixtures.")] + [Test] + public void CheckedInGateObligationLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GateObligationLedger.Compute(root); + + string fresh = GateObligationLedger.ToText(rows); + string checkedIn = File.ReadAllText( + Path.Combine(root, GateObligationLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + fresh.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-gate-obligations --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarCoverageGateTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarCoverageGateTests.cs new file mode 100644 index 000000000..4faaf1485 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarCoverageGateTests.cs @@ -0,0 +1,437 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class GrammarCoverageGateTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + [Test] + public void UncoveredSurfacesMatchTheBaselineExactly() + { + string root = RepositoryRoot(); + GrammarCoverageResult result = GrammarCoverageGate.Compute(root, GrammarCoverageGate.ReadInventory(root)); + string[] baseline = GrammarCoverageGate.ReadBaseline(root).Select(entry => entry.SurfaceId).ToArray(); + + string[] newGaps = result + .Uncovered.Except(baseline, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + string[] stale = baseline + .Except(result.Uncovered, StringComparer.Ordinal) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That( + newGaps, + Is.Empty, + $"new grammar-coverage gaps; add a fixture that exercises them:\n {string.Join("\n ", newGaps)}" + ); + Assert.That( + stale, + Is.Empty, + $"these are now covered; delete them from {GrammarCoverageGate.BaselineRelativePath}:\n {string.Join("\n ", stale)}" + ); + }); + } + + [Test] + public void EveryFixtureContributesAtLeastOneObservableSurface() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + var empty = new List(); + foreach ((string fixtureId, string grammarPath) in GrammarCoverageGate.DiscoverGrammars(root)) + { + if (GrammarFeatureUsage.Read(XDocument.Load(grammarPath), inventory).Count == 0) + empty.Add(fixtureId); + } + + Assert.That( + empty, + Is.Empty, + "a fixture whose grammar exercises no declared surface cannot contribute coverage" + ); + } + + // Compute only creates a fixture list while appending to it, so asserting the list is non-empty + // is a tautology. What is worth pinning is that the named fixture really contains the surface. + [Test] + public void EveryCoveredSurfaceIsReproducibleFromTheFixtureItNames() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + GrammarCoverageResult result = GrammarCoverageGate.Compute(root, inventory); + var grammarsById = GrammarCoverageGate + .DiscoverGrammars(root) + .ToDictionary(item => item.FixtureId, item => item.GrammarPath, StringComparer.Ordinal); + + Assert.That(result.Covered, Is.Not.Empty); + var unreproducible = new List(); + foreach (string surfaceId in result.Covered) + { + foreach (string fixtureId in result.FixturesBySurface[surfaceId]) + { + var reread = GrammarFeatureUsage.Read(XDocument.Load(grammarsById[fixtureId]), inventory); + if (!reread.Contains(surfaceId)) + unreproducible.Add($"{surfaceId} attributed to {fixtureId}, which does not contain it"); + } + } + + Assert.That(unreproducible, Is.Empty, string.Join("\n ", unreproducible)); + } + + [Test] + public void ObservableSurfacesAreOnlyElementsAndEnumeratedValues() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + var byId = inventory.Surfaces.ToDictionary( + surface => surface.Id, + surface => surface.Kind, + StringComparer.Ordinal + ); + + Assert.That( + GrammarFeatureUsage + .Observable(inventory) + .Select(id => byId[id]) + .Distinct(StringComparer.Ordinal) + .OrderBy(k => k, StringComparer.Ordinal), + Is.EqualTo(new[] { "element", "enum" }) + ); + } + + [Test] + public void NoCoveredSurfaceRestsOnPresenceAloneOutsideTheWaiverFile() + { + string root = RepositoryRoot(); + IReadOnlyList evidence = GrammarCoverageGate.GradeEvidence( + root, + GrammarCoverageGate.ReadInventory(root) + ); + + string[] presenceOnly = evidence + .Where(item => item.Strength == EvidenceStrength.Presence) + .Select(item => item.SurfaceId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + IReadOnlyList waived = GrammarCoverageGate.ReadPresenceWaivers(root); + + Assert.Multiple(() => + { + Assert.That( + presenceOnly.Except(waived, StringComparer.Ordinal), + Is.Empty, + "a surface counted as covered must have trace, negative-control, or structural evidence" + ); + Assert.That( + waived.Except(presenceOnly, StringComparer.Ordinal), + Is.Empty, + $"these now have real evidence; delete them from {GrammarCoverageGate.PresenceWaiverRelativePath}" + ); + }); + } + + /// Ratchet floors. Raise them when coverage improves; never lower them silently. + private const int ObservableSurfaces = 264; + private const int GeneratedSurfaces = 1059; + private const int TraceFloor = 71; + + [Test] + public void TheMeasuredDenominatorIsPinned() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + + // Without this, editing the DTD (an enumerated attribute to NMTOKEN, say) shrinks the + // denominator, turns the vanished lines stale, and the ratchet REQUIRES deleting them. + Assert.Multiple(() => + { + Assert.That(inventory.Surfaces, Has.Count.EqualTo(GeneratedSurfaces), "generated surface count changed"); + Assert.That( + GrammarFeatureUsage.Observable(inventory), + Has.Count.EqualTo(ObservableSurfaces), + "observable surface count changed" + ); + }); + } + + [Test] + public void TraceEvidenceIsAchievedAndDoesNotRegress() + { + string root = RepositoryRoot(); + IReadOnlyList evidence = GrammarCoverageGate.GradeEvidence( + root, + GrammarCoverageGate.ReadInventory(root) + ); + + Assert.That(evidence, Is.Not.Empty, "an empty evidence set would make every evidence gate vacuous"); + Assert.That( + evidence.Count(item => item.Strength == EvidenceStrength.Trace), + Is.GreaterThanOrEqualTo(TraceFloor), + "trace-verified coverage regressed" + ); + foreach (SurfaceEvidence item in evidence.Where(item => item.Strength == EvidenceStrength.Trace)) + { + // The Presence detail also ends in "fired", so match the prefix, not the word. + Assert.That(item.Detail, Does.StartWith("rule '"), $"{item.SurfaceId} must name the firing rule"); + Assert.That(item.Detail, Does.EndWith("fired in a verified parse")); + Assert.That(item.FixtureId, Is.Not.Empty); + } + } + + // A value equal to its attribute's DTD default is supplied by the validating parser for every + // grammar, so no fixture can discriminate writing it from omitting it. Counting those as work + // items inflates the worklist with certified no-ops. + [Test] + public void DtdDefaultValuesAreDetectedFromTheInventoryNotTheLedger() + { + string root = RepositoryRoot(); + var declared = GrammarCoverageGate + .ReadInventory(root) + .Surfaces.Select(s => s.Id) + .ToHashSet(StringComparer.Ordinal); + + Assert.Multiple(() => + { + Assert.That(GrammarCoverageGate.IsDtdDefault("dtd:enum/AffixTemplate/isActive/yes", declared), Is.True); + Assert.That(GrammarCoverageGate.IsDtdDefault("dtd:enum/AffixTemplate/isActive/no", declared), Is.False); + Assert.That(GrammarCoverageGate.IsDtdDefault("dtd:enum/Stratum/cyclicity/noncyclic", declared), Is.True); + Assert.That(GrammarCoverageGate.IsDtdDefault("dtd:enum/Stratum/cyclicity/cyclic", declared), Is.False); + Assert.That( + GrammarCoverageGate.IsDtdDefault("dtd:element/AffixTemplate", declared), + Is.False, + "only enumerated values have defaults" + ); + }); + } + + [Test] + public void EveryDtdDefaultLedgerLineIsGenuinelyTheDefault() + { + string root = RepositoryRoot(); + var declared = GrammarCoverageGate + .ReadInventory(root) + .Surfaces.Select(s => s.Id) + .ToHashSet(StringComparer.Ordinal); + + string[] wrong = GrammarCoverageGate + .ReadBaseline(root) + .Where(entry => entry.Classification == GrammarCoverageGate.DtdDefault) + .Where(entry => !GrammarCoverageGate.IsDtdDefault(entry.SurfaceId, declared)) + .Select(entry => entry.SurfaceId) + .OrderBy(id => id, StringComparer.Ordinal) + .ToArray(); + + Assert.That(wrong, Is.Empty, $"these are not their attribute's default:\n {string.Join("\n ", wrong)}"); + } + + [Test] + public void AQuotientNeedsACoveredSiblingToStand() + { + var ledger = new[] + { + new GrammarCoverageGate.LedgerEntry("dtd:enum/E/a/x", GrammarCoverageGate.AlphabetQuotient), + new GrammarCoverageGate.LedgerEntry("dtd:enum/F/b/x", GrammarCoverageGate.AlphabetQuotient), + new GrammarCoverageGate.LedgerEntry("dtd:enum/G/c/x", GrammarCoverageGate.Todo), + }; + + Assert.That( + GrammarCoverageGate.UnbackedQuotients(ledger, new[] { "dtd:enum/E/a/y" }), + Is.EqualTo(new[] { "dtd:enum/F/b/x" }), + "a quotient whose attribute has no covered sibling claims a mechanism nothing exercises" + ); + Assert.That( + GrammarCoverageGate.UnbackedQuotients(ledger, Array.Empty()), + Is.EqualTo(new[] { "dtd:enum/E/a/x", "dtd:enum/F/b/x" }) + ); + } + + [Test] + public void UnclassifiedCatalogFeaturesCanOnlyShrink() + { + const int UnclassifiedCeiling = 108; + SemanticCatalog catalog = CatalogBootstrap.Load(RepositoryRoot()); + + Assert.That( + catalog.Features.Count(feature => feature.Disposition == FeatureDisposition.Unclassified), + Is.LessThanOrEqualTo(UnclassifiedCeiling), + "the bootstrap's unclassified backlog must not grow; classify the new surfaces" + ); + } + + // The audit is only worth anything if it runs against the real inventory. Before the catalog was + // checked in it ran only over literals inside its own tests, so nothing failed closed. + [Test] + public void TheCheckedInCatalogMapsEveryRealSurfaceExactlyOnce() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + SemanticCatalog catalog = CatalogBootstrap.Load(root); + + AuditResult audit = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(audit.IsComplete, Is.False, "the checked-in catalog is intentionally still a proposal backlog"); + Assert.That( + audit.Diagnostics.Select(item => item.Code).Distinct(StringComparer.Ordinal), + Is.EquivalentTo(new[] { SemanticCoverageAudit.UnclassifiedMapping }) + ); + Assert.That( + audit.Diagnostics, + Has.None.Matches(item => + item.Code + is SemanticCoverageAudit.UnmappedSurface + or SemanticCoverageAudit.DuplicateSurfaceMapping + or SemanticCoverageAudit.StaleSurfaceMapping + or SemanticCoverageAudit.UnknownFeature + ) + ); + Assert.That(catalog.SurfaceMappings, Has.Count.EqualTo(inventory.Surfaces.Count)); + Assert.That( + catalog.SurfaceMappings.Select(mapping => mapping.SurfaceId).Distinct(StringComparer.Ordinal).ToArray(), + Has.Length.EqualTo(inventory.Surfaces.Count), + "the checked-in catalog must retain exact-once surface mapping rows" + ); + Assert.That( + inventory.Surfaces, + Has.Count.GreaterThan(1000), + "the audit must cover the whole inventory, not a slice" + ); + + SemanticInventory live = GraphSemanticCensus.Read( + root, + new[] { "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader" }, + CancellationToken.None + ); + Assert.That( + live.Surfaces.Count, + Is.GreaterThan(inventory.Surfaces.Count), + "the live snapshot must add C# census surfaces beyond the legacy DTD inventory" + ); + } + + [Test] + public void ADroppedCatalogRowFailsTheAudit() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + SemanticCatalog catalog = CatalogBootstrap.Load(root); + var trimmed = catalog with { SurfaceMappings = catalog.SurfaceMappings.Skip(1).ToArray() }; + + AuditResult audit = SemanticCoverageAudit.Run(inventory, trimmed); + + Assert.That( + audit.Diagnostics.Select(item => item.Code), + Does.Contain(SemanticCoverageAudit.UnmappedSurface), + "removing a mapping row must fail closed" + ); + } + + [Test] + public void LedgerClassificationsAreRecomputedNotTrusted() + { + string root = RepositoryRoot(); + GrammarCoverageResult result = GrammarCoverageGate.Compute(root, GrammarCoverageGate.ReadInventory(root)); + + var recorded = GrammarCoverageGate + .ReadBaseline(root) + .ToDictionary(entry => entry.SurfaceId, entry => entry.Classification, StringComparer.Ordinal); + var recomputed = GrammarCoverageGate + .Classify(root, result.Uncovered, GrammarCoverageGate.ReadBaseline(root)) + .ToDictionary(entry => entry.SurfaceId, entry => entry.Classification, StringComparer.Ordinal); + + string[] wrong = recomputed + .Where(pair => recorded.TryGetValue(pair.Key, out string? was) && was != pair.Value) + .Select(pair => $"{pair.Key}: recorded '{recorded[pair.Key]}', recomputed '{pair.Value}'") + .OrderBy(line => line, StringComparer.Ordinal) + .ToArray(); + + Assert.That( + wrong, + Is.Empty, + $"a dead-schema claim is only true while the engine ignores the element:\n {string.Join("\n ", wrong)}" + ); + } + + [Test] + public void DeadSchemaElementsAreGenuinelyAbsentFromTheEngine() + { + string root = RepositoryRoot(); + string[] claimed = GrammarCoverageGate + .ReadBaseline(root) + .Where(entry => entry.Classification == GrammarCoverageGate.DeadSchema) + .Select(entry => DeadSchemaDetector.OwningElement(entry.SurfaceId)!) + .Distinct(StringComparer.Ordinal) + .OrderBy(name => name, StringComparer.Ordinal) + .ToArray(); + + Assert.That(claimed, Is.Not.Empty, "the ledger should record the schema the engine ignores"); + Assert.That( + DeadSchemaDetector.FindUnreferenced(root, claimed).OrderBy(name => name, StringComparer.Ordinal), + Is.EqualTo(claimed), + "every element classified dead-schema must have no quoted occurrence in the engine source" + ); + } + + [Test] + public void ReferencedElementsAreNotClassifiedDeadSchema() + { + string root = RepositoryRoot(); + + Assert.That( + DeadSchemaDetector.FindUnreferenced(root, new[] { "Stratum", "MorphologicalRule", "LexicalEntry" }), + Is.Empty, + "elements the loader plainly reads must never be detected as dead schema" + ); + } + + [Test] + public void OwningElementIsParsedFromBothObservableSurfaceShapes() + { + Assert.That(DeadSchemaDetector.OwningElement("dtd:element/AffixTemplate"), Is.EqualTo("AffixTemplate")); + Assert.That(DeadSchemaDetector.OwningElement("dtd:enum/AffixTemplate/final/true"), Is.EqualTo("AffixTemplate")); + Assert.That(DeadSchemaDetector.OwningElement("dtd:attribute/AffixTemplate/final"), Is.Null); + } + + // VariableFeature names are Greek letters; the inventory percent-encodes every ID component, so + // reading an attribute value raw silently reports 24 covered values as gaps. + [Test] + public void NonAsciiEnumeratedValuesAreMatchedThroughTheSameEncoding() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + var grammar = XDocument.Parse( + "" + ); + + Assert.That(GrammarFeatureUsage.Read(grammar, inventory), Does.Contain("dtd:enum/VariableFeature/name/%CE%B1")); + } + + [Test] + public void AFixtureCannotClaimASurfaceTheInventoryDoesNotDeclare() + { + string root = RepositoryRoot(); + SemanticInventory inventory = GrammarCoverageGate.ReadInventory(root); + var invented = XDocument.Parse(""); + + Assert.That(GrammarFeatureUsage.Read(invented, inventory), Is.Empty); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarCoverageLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarCoverageLedgerTests.cs new file mode 100644 index 000000000..df547ab02 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarCoverageLedgerTests.cs @@ -0,0 +1,72 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class GrammarCoverageLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Every one of the 33 fixtures appears at least once -- a fixture with zero rows here would mean + // the per-grammar view has nothing to say about it at all, which is exactly the gap this ledger + // exists to close. Layer totals are pinned so a source ledger drifting silently changes this file + // in a way CheckedInGrammarCoverageLedgerIsUpToDate below would also catch. + // + // Surface dropped 191 -> 189 (rows 641 -> 639) on a full --write-counterfactual + + // --write-coverage-evidence re-sweep: BoundaryMarker and Gloss no longer reach Evidenced in any + // fixture (their sole prior witness, since neither is checked in EvidenceLedger anymore). + [Test] + public void CheckedInLedgerCoversAllFixturesWithTheMeasuredLayerCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = GrammarCoverageLedger.Read(root); + + int distinctFixtures = rows.Select(r => r.Fixture).Distinct().Count(); + int surface = rows.Count(r => r.Layer == ObligationLayer.Surface); + int @interface = rows.Count(r => r.Layer == ObligationLayer.Interface); + int construct = rows.Count(r => r.Layer == ObligationLayer.Construct); + + TestContext.Out.WriteLine( + $"rows={rows.Count} fixtures={distinctFixtures} surface={surface} interface={@interface} construct={construct}" + ); + + Assert.That(rows, Has.Count.EqualTo(647)); + Assert.That(distinctFixtures, Is.EqualTo(33)); + Assert.That(surface, Is.EqualTo(189)); + Assert.That(@interface, Is.EqualTo(369)); + Assert.That(construct, Is.EqualTo(89)); + } + + // This is a JOIN over three already-checked-in ledgers (EvidenceLedger, InterfaceInventoryLedger + + // InterfaceWitnessLedger, ConstructClaimCorroboration) -- no reparse of its own, so unlike + // InterfaceWitnessLedgerTests's freshness test this one is cheap enough to run on every pass. + [Test] + public void CheckedInGrammarCoverageLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList fresh = GrammarCoverageLedger.Compute(root); + string freshText = GrammarCoverageLedger.ToText(fresh); + string checkedIn = File.ReadAllText( + Path.Combine(root, GrammarCoverageLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + freshText.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-coverage-traceability --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarMutatorTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarMutatorTests.cs new file mode 100644 index 000000000..254068b0b --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GrammarMutatorTests.cs @@ -0,0 +1,331 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class GrammarMutatorTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static SemanticInventory Inventory() => GrammarCoverageGate.ReadInventory(RepositoryRoot()); + + [Test] + public void DeletingAnElementRemovesEveryOccurrence() + { + var grammar = XDocument.Parse( + "a" + + "x" + + "y" + + "" + ); + + GrammarMutation? mutation = GrammarMutator.Mutate(grammar, "dtd:element/LexicalEntry", Inventory()); + + Assert.That(mutation, Is.Not.Null); + Assert.That(mutation!.Kind, Is.EqualTo(GrammarMutator.DeletedElements)); + Assert.That(mutation.Mutated.Descendants("LexicalEntry"), Is.Empty); + Assert.That(mutation.Detail, Does.Contain("2")); + // The mutation must not touch the original. + Assert.That(grammar.Descendants("LexicalEntry").Count(), Is.EqualTo(2)); + } + + [Test] + public void ANonDefaultEnumValueIsRewrittenToADeclaredSibling() + { + var grammar = XDocument.Parse("a"); + + GrammarMutation? mutation = GrammarMutator.Mutate(grammar, "dtd:enum/Stratum/cyclicity/cyclic", Inventory()); + + Assert.That(mutation, Is.Not.Null); + Assert.That(mutation!.Kind, Is.EqualTo(GrammarMutator.RewroteAttribute)); + Assert.That( + (string?)mutation.Mutated.Descendants("Stratum").Single().Attribute("cyclicity"), + Is.EqualTo("noncyclic"), + "the sibling must be a value the DTD actually declares" + ); + } + + [Test] + public void ASurfaceTheDocumentDoesNotContainYieldsNoMutation() + { + var grammar = XDocument.Parse("a"); + + Assert.That(GrammarMutator.Mutate(grammar, "dtd:element/CompoundingRule", Inventory()), Is.Null); + Assert.That(GrammarMutator.Mutate(grammar, "dtd:enum/Stratum/cyclicity/cyclic", Inventory()), Is.Null); + } + + // redupMorphType declares exactly three values (implicit/prefix/suffix), so mutating away from + // "suffix" has exactly two siblings to enumerate -- the shape of the proven false-negative this + // enumeration exists to fix (see CounterfactualGateTests for the end-to-end case). + [Test] + public void MutateEnumAgainstEverySiblingBuildsOneMutationPerDeclaredSiblingInOrdinalOrder() + { + var grammar = XDocument.Parse(""); + + IReadOnlyList candidates = GrammarMutator.MutateEnumAgainstEverySibling( + grammar, + "dtd:enum/MorphologicalOutput/redupMorphType/suffix", + Inventory() + ); + + Assert.That(candidates.Select(c => c.Sibling), Is.EqualTo(new[] { "implicit", "prefix" })); + foreach (GrammarMutator.EnumSiblingCandidate candidate in candidates) + { + Assert.That( + (string?) + candidate.Mutation.Mutated.Descendants("MorphologicalOutput").Single().Attribute("redupMorphType"), + Is.EqualTo(candidate.Sibling) + ); + } + // The original document must not be touched by building the candidates. + Assert.That( + (string?)grammar.Descendants("MorphologicalOutput").Single().Attribute("redupMorphType"), + Is.EqualTo("suffix") + ); + } + + [Test] + public void MutateEnumAgainstEverySiblingIsDeterministicAcrossRepeatedCalls() + { + var grammar = XDocument.Parse(""); + SemanticInventory inventory = Inventory(); + + string[] Siblings() => + GrammarMutator + .MutateEnumAgainstEverySibling(grammar, "dtd:enum/MorphologicalOutput/redupMorphType/suffix", inventory) + .Select(c => c.Sibling) + .ToArray(); + + string[] first = Siblings(); + string[] second = Siblings(); + Assert.That(second, Is.EqualTo(first), "repeated calls must agree on both the set and the order"); + } + + [Test] + public void MutateEnumAgainstEverySiblingIsEmptyWhenTheDocumentDoesNotContainTheSurface() + { + var grammar = XDocument.Parse(""); + + Assert.That( + GrammarMutator.MutateEnumAgainstEverySibling( + grammar, + "dtd:enum/MorphologicalOutput/redupMorphType/suffix", + Inventory() + ), + Is.Empty + ); + } + + [Test] + public void MutateEnumAgainstEverySiblingIsEmptyForAnElementSurface() + { + var grammar = XDocument.Parse("a"); + + Assert.That( + GrammarMutator.MutateEnumAgainstEverySibling(grammar, "dtd:element/Stratum", Inventory()), + Is.Empty + ); + } + + [Test] + public void SiblingSelectionIsDeterministicAndNeverTheValueItself() + { + SemanticInventory inventory = Inventory(); + + Assert.That(GrammarMutator.Sibling(inventory, "Stratum", "cyclicity", "cyclic"), Is.EqualTo("noncyclic")); + Assert.That(GrammarMutator.Sibling(inventory, "Stratum", "cyclicity", "noncyclic"), Is.EqualTo("cyclic")); + Assert.That( + GrammarMutator.Sibling(inventory, "Stratum", "cyclicity", "cyclic"), + Is.EqualTo(GrammarMutator.Sibling(inventory, "Stratum", "cyclicity", "cyclic")), + "repeated calls must agree" + ); + } + + // Percent-encoding is applied to every ID component, so a Greek variable name has to survive the + // round trip or its mutation would silently target nothing. + [Test] + public void EncodedValuesRoundTripThroughMutation() + { + var grammar = XDocument.Parse( + "" + ); + + GrammarMutation? mutation = GrammarMutator.Mutate(grammar, "dtd:enum/VariableFeature/name/%CE%B1", Inventory()); + + Assert.That(mutation, Is.Not.Null); + Assert.That( + (string?)mutation!.Mutated.Descendants("VariableFeature").Single().Attribute("name"), + Is.Not.EqualTo("α"), + "the Greek value must actually be replaced" + ); + } + + // A minimal, non-DTD-valid fragment mirroring the real fail-fast-IDREF shape: an inactive + // CharacterDefinitionTable ("tableDecoy") that only an equally inactive Stratum references. + // GrammarMutator manipulates XDocument directly and never loads via XmlLanguageLoader, so the + // fragment does not need to be schema-complete -- only the id/attribute shapes matter. + private const string JointPartnerFragment = """ + + Decoy + Live + DecoyStratum + Main + + """; + + [Test] + public void FindJointPartnerLocatesTheSoleInactiveReferencingDeclaration() + { + var grammar = XDocument.Parse(JointPartnerFragment); + + GrammarMutator.JointPartner? partner = GrammarMutator.FindJointPartner( + grammar, + "dtd:enum/CharacterDefinitionTable/isActive/no" + ); + + Assert.That(partner, Is.Not.Null); + Assert.That(partner!.TargetElement, Is.EqualTo("CharacterDefinitionTable")); + Assert.That(partner.TargetId, Is.EqualTo("tableDecoy")); + Assert.That(partner.PartnerElement, Is.EqualTo("Stratum")); + Assert.That(partner.PartnerAttribute, Is.EqualTo("characterDefinitionTable")); + } + + [Test] + public void FindJointPartnerReturnsNullWhenNothingReferencesTheInactiveDeclaration() + { + // tableLive's own isActive="yes" would need a "no" value to even be eligible, and the + // decoy table here is never named by anything -- the negative-space half of the fixture. + var grammar = XDocument.Parse( + """ + + Orphan + + """ + ); + + Assert.That(GrammarMutator.FindJointPartner(grammar, "dtd:enum/CharacterDefinitionTable/isActive/no"), Is.Null); + } + + [Test] + public void FindJointPartnerOnlyAppliesToInactiveEnumSurfaces() + { + var grammar = XDocument.Parse(JointPartnerFragment); + + // isActive/yes has no dangling-reference hazard to guard against, and cyclicity is not + // isActive at all -- neither shape is what a joint mutation exists to fix. + Assert.That( + GrammarMutator.FindJointPartner(grammar, "dtd:enum/CharacterDefinitionTable/isActive/yes"), + Is.Null + ); + Assert.That(GrammarMutator.FindJointPartner(grammar, "dtd:enum/Stratum/cyclicity/cyclic"), Is.Null); + Assert.That(GrammarMutator.FindJointPartner(grammar, "dtd:element/Stratum"), Is.Null); + } + + [Test] + public void MutatePartnerAloneActivatesOnlyThePartner() + { + var grammar = XDocument.Parse(JointPartnerFragment); + GrammarMutator.JointPartner partner = GrammarMutator.FindJointPartner( + grammar, + "dtd:enum/CharacterDefinitionTable/isActive/no" + )!; + + GrammarMutation? mutation = GrammarMutator.MutatePartnerAlone(grammar, partner); + + Assert.That(mutation, Is.Not.Null); + Assert.That(mutation!.Kind, Is.EqualTo(GrammarMutator.ActivatedPartnerAlone)); + XElement decoyStratum = mutation + .Mutated.Descendants("Stratum") + .First(e => (string?)e.Attribute("characterDefinitionTable") == "tableDecoy"); + Assert.That((string?)decoyStratum.Attribute("isActive"), Is.EqualTo("yes"), "the partner must activate"); + XElement decoyTable = mutation + .Mutated.Descendants("CharacterDefinitionTable") + .First(e => (string?)e.Attribute("id") == "tableDecoy"); + Assert.That((string?)decoyTable.Attribute("isActive"), Is.EqualTo("no"), "the target must stay inactive"); + // The original document must not be touched. + Assert.That( + (string?) + grammar + .Descendants("Stratum") + .First(e => (string?)e.Attribute("characterDefinitionTable") == "tableDecoy") + .Attribute("isActive"), + Is.EqualTo("no") + ); + } + + [Test] + public void MutateJointlyActivatesBothTargetAndPartner() + { + var grammar = XDocument.Parse(JointPartnerFragment); + SemanticInventory inventory = Inventory(); + GrammarMutator.JointPartner partner = GrammarMutator.FindJointPartner( + grammar, + "dtd:enum/CharacterDefinitionTable/isActive/no" + )!; + + GrammarMutation? mutation = GrammarMutator.MutateJointly( + grammar, + "dtd:enum/CharacterDefinitionTable/isActive/no", + partner, + inventory + ); + + Assert.That(mutation, Is.Not.Null); + Assert.That(mutation!.Kind, Is.EqualTo(GrammarMutator.ActivatedJointly)); + XElement decoyTable = mutation + .Mutated.Descendants("CharacterDefinitionTable") + .First(e => (string?)e.Attribute("id") == "tableDecoy"); + XElement decoyStratum = mutation + .Mutated.Descendants("Stratum") + .First(e => (string?)e.Attribute("characterDefinitionTable") == "tableDecoy"); + Assert.That((string?)decoyTable.Attribute("isActive"), Is.EqualTo("yes")); + Assert.That((string?)decoyStratum.Attribute("isActive"), Is.EqualTo("yes")); + // The original document must not be touched. + Assert.That( + (string?) + grammar + .Descendants("CharacterDefinitionTable") + .First(e => (string?)e.Attribute("id") == "tableDecoy") + .Attribute("isActive"), + Is.EqualTo("no") + ); + } + + [Test] + public void EveryObservableSurfaceInEveryFixtureCanBeMutated() + { + string root = RepositoryRoot(); + SemanticInventory inventory = Inventory(); + var unmutatable = new List(); + + foreach ((string fixtureId, string grammarPath) in GrammarCoverageGate.DiscoverGrammars(root)) + { + XDocument grammar = XDocument.Load(grammarPath); + foreach (string surfaceId in GrammarFeatureUsage.Read(grammar, inventory)) + { + if (GrammarMutator.Mutate(grammar, surfaceId, inventory) is null) + unmutatable.Add($"{fixtureId}: {surfaceId}"); + } + } + + Assert.That( + unmutatable, + Is.Empty, + $"a surface a fixture contains but the mutator cannot neutralize can never be evidenced:\n {string.Join("\n ", unmutatable)}" + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GraphCensusAuthorityTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GraphCensusAuthorityTests.cs new file mode 100644 index 000000000..b2fbb7a02 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/GraphCensusAuthorityTests.cs @@ -0,0 +1,126 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class GraphCensusAuthorityTests +{ + private static readonly string[] CensusedProjects = { "hc", "hc-tool" }; + + private static readonly string[] AuditedScopes = + { + "SIL.Machine.Morphology.HermitCrab.XmlLanguageLoader.Load(System.String)", + }; + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static async Task<(RepositoryCompilationGraph Captured, RoslynCompilationGraph Graph)> LoadAsync() + { + RepositoryCompilationGraph captured = await new RepositoryCompilationGraphLoader( + new MsBuildProcessRunner() + ).LoadAsync(new RepositoryRoot(RepositoryRoot()), CancellationToken.None); + return (captured, RoslynCompilationGraph.Build(captured)); + } + + [Test] + [CancelAfter(300_000)] + public async Task LiveGraphCensusResolvesEveryScopeWithoutApproximation() + { + (RepositoryCompilationGraph captured, RoslynCompilationGraph graph) = await LoadAsync(); + + SemanticInventory inventory = CSharpInventoryReader.ReadFromGraph( + graph, + captured, + RepositoryRoot(), + CensusedProjects, + AuditedScopes + ); + + Assert.Multiple(() => + { + Assert.That(inventory.Surfaces, Is.Not.Empty, "the graph census must produce surfaces"); + Assert.That( + inventory.Diagnostics.Select(item => item.Code), + Has.None.EqualTo("compilation-error"), + string.Join( + Environment.NewLine, + inventory + .Diagnostics.Where(item => item.Code == "compilation-error") + .Select(item => $"{item.Location}: {item.Message}") + ) + ); + Assert.That(inventory.SourceHash, Is.Not.Empty); + }); + } + + // The census hash must move when the compiler inputs move, or a stale product cannot be detected. + [Test] + [CancelAfter(300_000)] + public async Task LiveGraphCensusIsBoundToTheGraphHash() + { + (RepositoryCompilationGraph captured, RoslynCompilationGraph graph) = await LoadAsync(); + + SemanticInventory first = CSharpInventoryReader.ReadFromGraph( + graph, + captured, + RepositoryRoot(), + CensusedProjects, + AuditedScopes + ); + SemanticInventory second = CSharpInventoryReader.ReadFromGraph( + graph, + captured, + RepositoryRoot(), + CensusedProjects, + AuditedScopes + ); + + Assert.That(second.SourceHash, Is.EqualTo(first.SourceHash)); + } + + [Test] + [CancelAfter(300_000)] + public async Task GraphCensusRefusesAnUnknownProjectAndEmptyScopes() + { + (RepositoryCompilationGraph captured, RoslynCompilationGraph graph) = await LoadAsync(); + + Assert.Multiple(() => + { + Assert.That( + () => + CSharpInventoryReader.ReadFromGraph( + graph, + captured, + RepositoryRoot(), + new[] { "not-a-project" }, + AuditedScopes + ), + Throws.TypeOf() + ); + Assert.That( + () => + CSharpInventoryReader.ReadFromGraph( + graph, + captured, + RepositoryRoot(), + CensusedProjects, + Array.Empty() + ), + Throws.TypeOf() + ); + }); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ImpossibilityProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ImpossibilityProofsTests.cs new file mode 100644 index 000000000..ae78275a3 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/ImpossibilityProofsTests.cs @@ -0,0 +1,119 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class ImpossibilityProofsTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static CounterfactualResult Result(string surfaceId, CounterfactualVerdict verdict) => + new(surfaceId, "fx", verdict, "mutation", "delta"); + + [Test] + public void AVerdictThatIsNotEvidenceAndHasNoProofIsUnaccounted() + { + var verdicts = new[] + { + Result("a", CounterfactualVerdict.Evidenced), + Result("b", CounterfactualVerdict.RequiredByDtd), + Result("e", CounterfactualVerdict.RequiredByLoader), + Result("c", CounterfactualVerdict.Unobservable), + Result("d", CounterfactualVerdict.Timeout), + }; + + IReadOnlyList unaccounted = ImpossibilityProofs.Unaccounted( + verdicts, + new[] { new ImpossibilityProof("c", ImpossibilityProofs.NoConsumer, "no reference in the engine") } + ); + + Assert.That( + unaccounted.Select(item => item.SurfaceId), + Is.EqualTo(new[] { "d" }), + "a timeout is neither evidence nor a proof, so it must not pass unclaimed -- " + + "and neither required-to-load verdict (b, e) may appear here either" + ); + } + + [Test] + public void AProofForASurfaceThatIsNowEvidencedIsStale() + { + var verdicts = new[] + { + Result("a", CounterfactualVerdict.Evidenced), + Result("b", CounterfactualVerdict.Unobservable), + }; + var proofs = new[] + { + new ImpossibilityProof("a", ImpossibilityProofs.NoConsumer, "no reference in the engine"), + new ImpossibilityProof("b", ImpossibilityProofs.NoConsumer, "no reference in the engine"), + new ImpossibilityProof("gone", ImpossibilityProofs.DtdDefault, "the parser supplies it"), + }; + + Assert.That( + ImpossibilityProofs.Stale(verdicts, proofs), + Is.EqualTo(new[] { "a", "gone" }), + "a claim of impossibility must not outlive either the evidence appearing or the surface" + ); + } + + [Test] + public void TheCheckedInProofsFileIsWellFormedAndEveryClaimCarriesEvidence() + { + IReadOnlyList proofs = ImpossibilityProofs.Read(RepositoryRoot()); + + Assert.That(proofs, Is.Not.Empty); + foreach (ImpossibilityProof proof in proofs) + { + Assert.That(proof.Evidence.Trim(), Is.Not.Empty, $"{proof.SurfaceId} claims {proof.Kind} with no evidence"); + } + } + + // Only these four are checks rather than arguments, so the loader must refuse anything else. + [Test] + public void AnUnknownProofKindIsRefused() + { + string root = RepositoryRoot(); + string path = Path.Combine(root, "conformance", "semantic-coverage-proofs.tsv"); + string original = File.ReadAllText(path); + try + { + File.AppendAllText(path, "dtd:element/Whatever\tit-seems-fine\tbecause I say so\n"); + Assert.Throws(() => ImpossibilityProofs.Read(root)); + } + finally + { + File.WriteAllText(path, original); + } + } + + [Test] + public void AClaimWithoutEvidenceIsRefused() + { + string root = RepositoryRoot(); + string path = Path.Combine(root, "conformance", "semantic-coverage-proofs.tsv"); + string original = File.ReadAllText(path); + try + { + File.AppendAllText(path, $"dtd:element/Whatever\t{ImpossibilityProofs.NoConsumer}\t \n"); + Assert.Throws(() => ImpossibilityProofs.Read(root)); + } + finally + { + File.WriteAllText(path, original); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InactiveMemberProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InactiveMemberProofsTests.cs new file mode 100644 index 000000000..f84c99af8 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InactiveMemberProofsTests.cs @@ -0,0 +1,293 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class InactiveMemberProofsTests +{ + private const string SecondMemberInactiveGrammar = """ + + S + + r1 + r2 + + + + """; + + private const string BothMembersActiveGrammar = """ + + S + + r1 + r2 + + + + """; + + private const string InactiveSlotGrammar = """ + S + tmpl + s1 + s2 + + + """; + + // The Slot itself is active; only the single rule it names is inactive, so the Slot resolves to + // nothing -- the empty-slot case, distinct from InactiveSlotGrammar's own isActive="no" on the Slot. + private const string EmptySlotOnlyRuleInactiveGrammar = """ + S + + r1 + r2 + + tmpl + s1 + s2 + + + """; + + // m2 reactivated: the same Slot shape as EmptySlotOnlyRuleInactiveGrammar, but s2 now resolves to an + // active rule -- used to falsify a proof built against the grammar above. + private const string EmptySlotRuleReactivatedGrammar = """ + S + + r1 + r2 + + tmpl + s1 + s2 + + + """; + + // s2 declares no morphologicalRules attribute at all -- resolves to zero rules just as vacuously as + // naming only an inactive one. + private const string SlotWithNoRulesAttributeGrammar = """ + S + + r1 + + tmpl + s1 + s2 + + + """; + + // s2 names only an id that is not declared anywhere in the document. + private const string SlotNamingOnlyNonexistentRuleGrammar = """ + S + + r1 + + tmpl + s1 + s2 + + + """; + + // Both Slots resolve to an active rule -- must never be certified as empty. + private const string BothSlotsResolveToAnActiveRuleGrammar = """ + S + + r1 + r2 + + tmpl + s1 + s2 + + + """; + + // s1 names one active and one inactive rule: it can still contribute via m1, so the pair must not + // be certified even though m2 alone would resolve to nothing. + private const string SlotWithSomeActiveAndSomeInactiveRulesGrammar = """ + S + + r1 + r2 + r3 + + tmpl + s1 + s2 + + + """; + + [Test] + public void BuildsAProofWhenTheSecondMemberIsInactive() + { + XDocument grammar = XDocument.Parse(SecondMemberInactiveGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = InactiveMemberProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(InactiveMemberProofs.Kind)); + Assert.That(proof.Check, Does.Contain("m2")); + Assert.That(InactiveMemberProofs.Verify(grammar, "fx", proof), Is.True); + } + + [Test] + public void BuildsAProofForAnInactiveSlotMember() + { + XDocument grammar = XDocument.Parse(InactiveSlotGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = InactiveMemberProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Check, Does.Contain("s2")); + } + + // The empty-slot case: the Slot itself is active, but its only referenced rule is not. + [Test] + public void BuildsAProofForASlotWhoseOnlyReferencedRuleIsInactive() + { + XDocument grammar = XDocument.Parse(EmptySlotOnlyRuleInactiveGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = InactiveMemberProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(InactiveMemberProofs.Kind)); + Assert.That(proof.Check, Does.Contain("s2")); + Assert.That(proof.Check, Does.Contain("m2")); + Assert.That(InactiveMemberProofs.Verify(grammar, "fx", proof), Is.True); + } + + // A Slot with no morphologicalRules attribute at all resolves to zero rules just as vacuously as one + // naming only an inactive id. + [Test] + public void BuildsAProofForASlotWithNoMorphologicalRulesAttribute() + { + XDocument grammar = XDocument.Parse(SlotWithNoRulesAttributeGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = InactiveMemberProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Check, Does.Contain("s2")); + } + + // A Slot naming only an id that does not exist anywhere in the document is equally empty. + [Test] + public void BuildsAProofForASlotNamingOnlyNonexistentRuleIds() + { + XDocument grammar = XDocument.Parse(SlotNamingOnlyNonexistentRuleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = InactiveMemberProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Check, Does.Contain("s2")); + Assert.That(proof.Check, Does.Contain("ghost")); + } + + // Core rejection scenario: both members active must never license this proof kind. + [Test] + public void RefusesWhenBothMembersAreActive() + { + XDocument grammar = XDocument.Parse(BothMembersActiveGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(InactiveMemberProofs.TryBuild(grammar, item), Is.Null); + } + + // Rejection: a Slot whose referenced rules are ALL active must never be certified as empty. + [Test] + public void RefusesWhenBothSlotsResolveToAnActiveRule() + { + XDocument grammar = XDocument.Parse(BothSlotsResolveToAnActiveRuleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(InactiveMemberProofs.TryBuild(grammar, item), Is.Null); + } + + // Rejection: a Slot with SOME active and SOME inactive rules can still contribute a morpheme, so it + // must not be certified as empty even though one of its rules resolves to nothing. + [Test] + public void RefusesWhenASlotHasSomeActiveAndSomeInactiveRules() + { + XDocument grammar = XDocument.Parse(SlotWithSomeActiveAndSomeInactiveRulesGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(InactiveMemberProofs.TryBuild(grammar, item), Is.Null); + } + + // Rejection: the empty-slot resolution is reachable only through CheckSlotPair for an + // AffixTemplateSlots pair, never through CheckIdrefPair for a Stratum IDREFS pair. + [Test] + public void RefusesToApplyEmptySlotResolutionToNonSlotOrderingKinds() + { + XDocument grammar = XDocument.Parse(BothMembersActiveGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + Assert.That(item.Kind, Is.EqualTo(OrderingListKind.StratumMorphologicalRules)); + + Assert.That(InactiveMemberProofs.TryBuild(grammar, item), Is.Null); + } + + // Verify-goes-stale: a proof built while s2's only rule was inactive must be REJECTED once that + // rule is reactivated in a mutated document. + [Test] + public void VerifyRejectsAnEmptySlotProofOnceItsRuleIsReactivated() + { + XDocument original = XDocument.Parse(EmptySlotOnlyRuleInactiveGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(original, "fx").Single(); + Proof proof = InactiveMemberProofs.TryBuild(original, item)!; + + XDocument reactivated = XDocument.Parse(EmptySlotRuleReactivatedGrammar); + + Assert.That(InactiveMemberProofs.Verify(reactivated, "fx", proof), Is.False); + } + + // Guard: an unresolvable member must fail closed, never be treated as inactive by default. + [Test] + public void RefusesWhenAMemberCannotBeResolvedToAnyDeclaration() + { + XDocument grammar = XDocument.Parse( + """ + + S + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(InactiveMemberProofs.TryBuild(grammar, item), Is.Null); + } + + // The core rejection the task asks for: a proof built while m2 was inactive must be REJECTED once m2 + // is reactivated, because Verify recomputes rather than trusts. + [Test] + public void VerifyRejectsAProofOnceTheMemberIsReactivated() + { + XDocument original = XDocument.Parse(SecondMemberInactiveGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(original, "fx").Single(); + Proof proof = InactiveMemberProofs.TryBuild(original, item)!; + + XDocument reactivated = XDocument.Parse(BothMembersActiveGrammar); + + Assert.That(InactiveMemberProofs.Verify(reactivated, "fx", proof), Is.False); + } + + [Test] + public void VerifyRejectsAStaleProofWhoseItemNoLongerExists() + { + XDocument grammar = XDocument.Parse(SecondMemberInactiveGrammar); + var stale = new Proof("ordering:fx/morphologicalRules/gone~alsoGone", InactiveMemberProofs.Kind, "stale"); + + Assert.That(InactiveMemberProofs.Verify(grammar, "fx", stale), Is.False); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InteractionChainLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InteractionChainLedgerTests.cs new file mode 100644 index 000000000..c7a103b83 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InteractionChainLedgerTests.cs @@ -0,0 +1,215 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class InteractionChainLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Pins the four headline counts for the chain layer, derived from SemanticInterfaceDirection's + // engine-checked judgment rather than InterfaceInventoryLedger's name-prefix heuristic. That + // heuristic classifies LexicalEntry.ruleFeatures, LexicalEntry.partOfSpeech, and Allomorph.stemName + // as "ref" (none starts with output/assigned/required/excluded/obligatory/head/nonHead), but each + // one seeds a derivation payload another declared attribute later gates on -- ruleFeatures and + // partOfSpeech into MorphologicalPhonologicalRuleFeature and PartOfSpeech respectively (both already- + // known junctions, giving each a THIRD writer), and Allomorph.stemName into a StemName junction the + // prefix heuristic cannot see at all, since it never asks the writer/reader question of a payload + // type it has not already paired a writer and reader for by name. 3 writers x 8 readers (MPR) + 3 x 5 + // (PartOfSpeech) + 1 x 1 (StemName) = 40. Two chains are both exercised and hazardous: + // MorphologicalOutput.MPRFeatures -> MorphologicalInput.requiredMPRFeatures (the original canonical + // example, via edge-cases/mpr-overwrite-order-dependence among others) and the newly-visible + // LexicalEntry.ruleFeatures -> MorphologicalInput.requiredMPRFeatures (via + // languages/fusional-realizational-morphology among others) -- the lexicon-sourced hazard a real + // field grammar actually exercises. + [Test] + public void RealCorpusProducesTheDeclaredJunctionAndChainCounts() + { + string root = RepositoryRoot(); + IReadOnlyList junctions = InteractionChainLedger.ComputeJunctions(root); + IReadOnlyList rows = InteractionChainLedger.Compute(root); + + int exercised = rows.Count(r => r.Exercised); + int hazardous = rows.Count(r => r.Hazardous); + + TestContext.Out.WriteLine( + $"junctions={junctions.Count} chains={rows.Count} exercised={exercised} hazardous={hazardous}" + ); + foreach (ChainJunction junction in junctions) + { + TestContext.Out.WriteLine( + $" {junction.PayloadType}: {junction.Writers.Count} writer(s), {junction.Readers.Count} reader(s)" + ); + } + foreach (InteractionChainLedger.Row row in rows.Where(r => r.Hazardous)) + { + TestContext.Out.WriteLine( + $"hazardous: {row.WriterElement}.{row.WriterAttribute} -> {row.PayloadType} -> " + + $"{row.ReaderElement}.{row.ReaderAttribute} ({string.Join(",", row.ExercisingFixtures)})" + ); + } + + Assert.That(junctions, Has.Count.EqualTo(3)); + Assert.That( + junctions.Select(j => j.PayloadType), + Is.EquivalentTo(new[] { "MorphologicalPhonologicalRuleFeature", "PartOfSpeech", "StemName" }) + ); + + ChainJunction mprFeature = junctions.Single(j => j.PayloadType == "MorphologicalPhonologicalRuleFeature"); + Assert.That(mprFeature.Writers, Has.Count.EqualTo(3)); + Assert.That(mprFeature.Readers, Has.Count.EqualTo(8)); + + ChainJunction partOfSpeech = junctions.Single(j => j.PayloadType == "PartOfSpeech"); + Assert.That(partOfSpeech.Writers, Has.Count.EqualTo(3)); + Assert.That(partOfSpeech.Readers, Has.Count.EqualTo(5)); + + ChainJunction stemName = junctions.Single(j => j.PayloadType == "StemName"); + Assert.That(stemName.Writers, Has.Count.EqualTo(1)); + Assert.That(stemName.Readers, Has.Count.EqualTo(1)); + + Assert.That(rows, Has.Count.EqualTo(40)); + Assert.That(exercised, Is.EqualTo(26)); + Assert.That(rows.Count - exercised, Is.EqualTo(14)); + Assert.That(hazardous, Is.EqualTo(4)); + + InteractionChainLedger.Row[] hazards = rows.Where(r => r.Hazardous).ToArray(); + // Two MPR writers x two readers. The PhonologicalSubrule pair joined when the exception-feature + // obligation cells were covered: an MPR gate on a sound rule is order-hazardous for the same + // reason the MorphologicalInput one is -- an Overwrite group can destroy the payload before the + // gate reads it, so the outcome depends on rule order rather than on the payload alone. + Assert.That( + hazards.Select(h => (h.WriterElement, h.WriterAttribute, h.ReaderElement)), + Is.EquivalentTo( + new[] + { + ("LexicalEntry", "ruleFeatures", "MorphologicalInput"), + ("LexicalEntry", "ruleFeatures", "PhonologicalSubrule"), + ("MorphologicalOutput", "MPRFeatures", "MorphologicalInput"), + ("MorphologicalOutput", "MPRFeatures", "PhonologicalSubrule"), + } + ) + ); + Assert.That(hazards.All(h => h.PayloadType == "MorphologicalPhonologicalRuleFeature"), Is.True); + Assert.That(hazards.All(h => h.ReaderAttribute == "requiredMPRFeatures"), Is.True); + Assert.That( + hazards + .Single(h => h.WriterElement == "MorphologicalOutput" && h.ReaderElement == "MorphologicalInput") + .ExercisingFixtures, + Contains.Item("edge-cases/mpr-overwrite-order-dependence") + ); + } + + // Every (element, attribute) InterfaceInventoryLedger declares from the DTD must have an explicit + // entry in SemanticInterfaceDirection -- Classify throws rather than silently defaulting to Ref for + // an unrecognized pair, exactly so a DTD change that adds a new IDREF/IDREFS attribute forces someone + // to make the write/read/ref call rather than have it fall out of a naming accident. + [Test] + public void EveryDeclaredInterfaceHasAnExplicitSemanticDirection() + { + string root = RepositoryRoot(); + IReadOnlyList edgeRows = InterfaceInventoryLedger.Compute(root); + + Assert.That(edgeRows, Has.Count.EqualTo(60)); + Assert.DoesNotThrow(() => + { + foreach (InterfaceInventoryLedger.Row row in edgeRows) + SemanticInterfaceDirection.Classify(row.Element, row.Attribute); + }); + } + + // The three reclassifications a real field grammar's evidence forced: each was "ref" under + // InterfaceInventoryLedger's own name-prefix heuristic (none starts with output/assigned) but is a + // genuine write once checked against the engine. + [Test] + public void LexiconSeedingAttributesAreClassifiedAsWritesNotRefs() + { + Assert.That( + SemanticInterfaceDirection.Classify("LexicalEntry", "ruleFeatures"), + Is.EqualTo(InterfaceDirection.Write) + ); + Assert.That( + SemanticInterfaceDirection.Classify("LexicalEntry", "partOfSpeech"), + Is.EqualTo(InterfaceDirection.Write) + ); + Assert.That(SemanticInterfaceDirection.Classify("Allomorph", "stemName"), Is.EqualTo(InterfaceDirection.Write)); + } + + // A declared interface appears in its own denominator whether or not any fixture exercises it -- that + // is what stops an unexercised construct from being silently absent rather than visibly uncovered. + // The two PhonologicalSubrule MPR readers were the original examples and are now EXERCISED, by the + // words that closed the exception-feature obligation cells, so they can only carry the first half of + // the claim. CompoundingRule.nonHeadProdRestrictionsMprFeatures still carries both: no grammar + // declares it, and it must still appear as a reader. + [Test] + public void DeclaredInterfacesAppearInTheirOwnChainsWhetherExercisedOrNot() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InteractionChainLedger.Compute(root); + + (string Element, string Attribute)[] mustAppearAsReaders = + { + ("PhonologicalSubrule", "requiredMPRFeatures"), + ("PhonologicalSubrule", "excludedMPRFeatures"), + ("CompoundingRule", "nonHeadProdRestrictionsMprFeatures"), + }; + foreach ((string element, string attribute) in mustAppearAsReaders) + { + InteractionChainLedger.Row[] matches = rows.Where(r => + r.ReaderElement == element && r.ReaderAttribute == attribute + ) + .ToArray(); + Assert.That(matches, Is.Not.Empty, $"{element}.{attribute} should appear as a reader"); + } + + InteractionChainLedger.Row[] nonHead = rows.Where(r => + r.ReaderElement == "CompoundingRule" && r.ReaderAttribute == "nonHeadProdRestrictionsMprFeatures" + ) + .ToArray(); + Assert.That( + nonHead.All(r => !r.Exercised), + Is.True, + "no grammar declares nonHeadProdRestrictionsMprFeatures, so it must still be unexercised" + ); + + InteractionChainLedger.Row[] writerMatches = rows.Where(r => + r.WriterElement == "CompoundingRule" && r.WriterAttribute == "outputProdRestrictionsMprFeatures" + ) + .ToArray(); + Assert.That(writerMatches, Is.Not.Empty); + Assert.That(writerMatches.All(r => !r.Exercised), Is.True); + } + + // Mirrors InterfaceInventoryLedgerTests.CheckedInInterfaceInventoryLedgerIsUpToDate: regenerate the + // ledger from the DTD plus the real corpus plus the engine-verified supplement, and require the + // checked-in file to match byte for byte. + [Test] + public void CheckedInInteractionChainLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InteractionChainLedger.Compute(root); + + string fresh = InteractionChainLedger.ToText(rows); + string checkedIn = File.ReadAllText( + Path.Combine(root, InteractionChainLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + fresh.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-interaction-chains --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InterfaceInventoryLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InterfaceInventoryLedgerTests.cs new file mode 100644 index 000000000..9eb169d9b --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InterfaceInventoryLedgerTests.cs @@ -0,0 +1,130 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class InterfaceInventoryLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Pins the four headline counts from the DTD+corpus derivation: 60 IDREF/IDREFS attributes are + // declared across HermitCrabInput.dtd, 42 of them are PRESENT in at least one of the 33 fixtures + // (18 are not), the 42 present ones resolve to 51 distinct (element, attribute, target-type) + // edges, and exactly three target types -- MorphologicalPhonologicalRuleFeature, PartOfSpeech, + // and StemName -- are reached by both a write-direction and a read-direction edge, per + // SemanticInterfaceDirection's engine-checked judgment (NOT a name-prefix guess: that heuristic + // missed StemName entirely -- Allomorph.stemName matches neither its write nor read prefixes -- + // and undercounted the other two, since it also misclassifies LexicalEntry.partOfSpeech and + // LexicalEntry.ruleFeatures as Ref rather than Write). Unlike RuleInteractionLedger's + // corpus-statistic denominator, the "60 declared" figure here cannot move by adding a fixture; + // only "present" and "typed edges" can. "Present" is STRUCTURAL ONLY (see Row's own doc comment) + // -- InterfaceWitnessLedgerTests pins the separate, strictly weaker WITNESSED counts. + [Test] + public void RealCorpusProducesTheDeclaredPresentEdgeAndJunctionCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InterfaceInventoryLedger.Compute(root); + + int present = rows.Count(r => r.Present); + int typedEdges = rows.Sum(r => r.ObservedTargetTypes.Count); + IReadOnlyList junctions = InterfaceInventoryLedger.ComputeJunctions(rows); + + TestContext.Out.WriteLine($"declared={rows.Count} present={present} notPresent={rows.Count - present}"); + TestContext.Out.WriteLine($"typedEdges={typedEdges}"); + foreach (InterfaceJunction junction in junctions) + { + TestContext.Out.WriteLine( + $"junction: {junction.TargetType} writers={junction.WriterCount} readers={junction.ReaderCount}" + ); + } + + Assert.That(rows, Has.Count.EqualTo(60)); + Assert.That(present, Is.EqualTo(44)); + Assert.That(rows.Count - present, Is.EqualTo(16)); + Assert.That(typedEdges, Is.EqualTo(53)); + Assert.That(junctions, Has.Count.EqualTo(3)); + Assert.That( + junctions.Select(j => j.TargetType), + Is.EquivalentTo(new[] { "MorphologicalPhonologicalRuleFeature", "PartOfSpeech", "StemName" }) + ); + + InterfaceJunction mprFeature = junctions.Single(j => j.TargetType == "MorphologicalPhonologicalRuleFeature"); + Assert.That(mprFeature.WriterCount, Is.EqualTo(2)); + Assert.That(mprFeature.ReaderCount, Is.EqualTo(7)); + + InterfaceJunction partOfSpeech = junctions.Single(j => j.TargetType == "PartOfSpeech"); + Assert.That(partOfSpeech.WriterCount, Is.EqualTo(3)); + Assert.That(partOfSpeech.ReaderCount, Is.EqualTo(5)); + + InterfaceJunction stemName = junctions.Single(j => j.TargetType == "StemName"); + Assert.That(stemName.WriterCount, Is.EqualTo(1)); + Assert.That(stemName.ReaderCount, Is.EqualTo(1)); + } + + // Every present row must name at least one fixture, and every not-present row must name none -- + // this pins that the two fields (Present, Fixtures) can never disagree with each other. + [Test] + public void PresentRowsNameFixturesAndOnlyPresentRowsDo() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InterfaceInventoryLedger.Compute(root); + + Assert.Multiple(() => + { + foreach (InterfaceInventoryLedger.Row row in rows) + { + if (row.Present) + { + Assert.That( + row.Fixtures, + Is.Not.Empty, + $"{row.Element}.{row.Attribute} is present but names no fixture" + ); + } + else + { + Assert.That( + row.Fixtures, + Is.Empty, + $"{row.Element}.{row.Attribute} is not present but names a fixture" + ); + } + } + }); + } + + // Mirrors OrderingGeneratorTests.CheckedInRuleInteractionLedgerIsUpToDate: regenerate the ledger + // from the DTD plus the real corpus and require the checked-in file to match byte for byte, so a + // DTD edit or a fixture change that shifts either half of the derivation is caught as a diff + // instead of silently going stale. + [Test] + public void CheckedInInterfaceInventoryLedgerIsUpToDate() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InterfaceInventoryLedger.Compute(root); + + string fresh = InterfaceInventoryLedger.ToText(rows); + string checkedIn = File.ReadAllText( + Path.Combine(root, InterfaceInventoryLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + fresh.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-interface-inventory --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InterfaceWitnessLedgerTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InterfaceWitnessLedgerTests.cs new file mode 100644 index 000000000..730c5c50c --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/InterfaceWitnessLedgerTests.cs @@ -0,0 +1,105 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class InterfaceWitnessLedgerTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // Pins the headline this whole split exists to produce: of the 42 interfaces + // InterfaceInventoryLedger marks present, only 19 ever reach a word-level Evidenced verdict + // ANYWHERE in the corpus -- the other 25 are present-but-never-witnessed (see + // FoldInCandidateLedgerTests for that split by category). Presence overclaimed by nearly 3x. + // timeout is pinned at 0 deliberately: a Timeout is a statement about the machine, not the + // grammar, so any reappearance is a signal to re-sweep rather than a verdict to record. + [Test] + public void CheckedInLedgerHasTheMeasuredVerdictAndWitnessedInterfaceCounts() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InterfaceWitnessLedger.Read(root); + + int evidenced = rows.Count(r => r.Verdict == CounterfactualVerdict.Evidenced); + int requiredByDtd = rows.Count(r => r.Verdict == CounterfactualVerdict.RequiredByDtd); + int requiredByLoader = rows.Count(r => r.Verdict == CounterfactualVerdict.RequiredByLoader); + int timeout = rows.Count(r => r.Verdict == CounterfactualVerdict.Timeout); + int unobservable = rows.Count(r => r.Verdict == CounterfactualVerdict.Unobservable); + int distinctInterfacesEverEvidenced = rows.Where(r => r.Verdict == CounterfactualVerdict.Evidenced) + .Select(r => (r.Element, r.Attribute)) + .Distinct() + .Count(); + + TestContext.Out.WriteLine( + $"rows={rows.Count} evidenced={evidenced} requiredByDtd={requiredByDtd} " + + $"requiredByLoader={requiredByLoader} timeout={timeout} unobservable={unobservable} " + + $"distinctInterfacesEvidenced={distinctInterfacesEverEvidenced}" + ); + + Assert.That(rows, Has.Count.EqualTo(369)); + Assert.That(evidenced, Is.EqualTo(85)); + Assert.That(requiredByDtd, Is.EqualTo(170)); + Assert.That(requiredByLoader, Is.EqualTo(24)); + Assert.That(timeout, Is.EqualTo(0)); + Assert.That(unobservable, Is.EqualTo(90)); + Assert.That(distinctInterfacesEverEvidenced, Is.EqualTo(19)); + } + + // A concrete instance of the overclaim this ledger exists to catch: InterfaceInventoryLedger + // marks SymbolicFeature.defaultSymbol present (it appears, with a real IDREF value, in + // edge-cases/loader-default-symbol), yet severing it there changes neither of that fixture's two + // words. Presence said "exercised"; witness says "inert". If this ever flips, that is real news + // about the grammar or the fixture, not a reason to update this pin without checking why. + [Test] + public void DefaultSymbolIsPresentButNeverWitnessed() + { + string root = RepositoryRoot(); + IReadOnlyList rows = InterfaceWitnessLedger.Read(root); + + InterfaceWitnessResult row = rows.Single(r => + r.Element == "SymbolicFeature" + && r.Attribute == "defaultSymbol" + && r.FixtureId == "edge-cases/loader-default-symbol" + ); + + Assert.That(row.Verdict, Is.EqualTo(CounterfactualVerdict.Unobservable)); + } + + // Mirrors InterfaceInventoryLedgerTests.CheckedInInterfaceInventoryLedgerIsUpToDate and + // EvidenceLedgerFreshnessTests: recompute the whole severance sweep and require the checked-in + // file to match byte for byte. [Explicit] because -- unlike InterfaceInventoryLedger's cheap, + // reparse-free Compute() -- this re-parses every present interface x fixture pair (362 severance + // runs plus one baseline per contributing fixture), the same cost class as + // EvidenceLedgerFreshnessTests' own full sweep. Measured locally: ~2m45s. + [Test] + [Explicit("re-parses every present interface x fixture pair; ~2-3 minutes")] + [Category("Counterfactual")] + public void TheCheckedInWitnessLedgerMatchesAFreshRecomputeExactly() + { + string root = RepositoryRoot(); + IReadOnlyList fresh = InterfaceWitnessLedger.Sweep(root); + + string freshText = InterfaceWitnessLedger.ToText(fresh); + string checkedIn = File.ReadAllText( + Path.Combine(root, InterfaceWitnessLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + freshText.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-coverage-traceability --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/NeverFiresProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/NeverFiresProofsTests.cs new file mode 100644 index 000000000..c17068ed8 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/NeverFiresProofsTests.cs @@ -0,0 +1,238 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class NeverFiresProofsTests +{ + // Mirrors edge-cases/feature-system-breadth's prHighTrigger~mtSwap shape: a FeatureNaturalClass + // requiring featHigh=hiPlus AND featCons=consPlus, where no active segment declares both -- cI is + // high but not a consonant, cT is a consonant but not high -- so prDead's LeftEnvironment can never + // match and the rule can never fire. + private const string DeadEnvironmentGrammar = """ + + + high+- + cons+- + + Main + i + + + t + + + + + sOnly + highCons + + + + + dead + + + + + + + other + + + + + + + S + + """; + + // cK now declares BOTH hiPlus and consPlus, so ncHighCons is non-empty -- prDead's environment can + // match cK and the rule is no longer dead. + private const string NonEmptyEnvironmentGrammar = """ + + + high+- + cons+- + + Main + i + + + t + + + k + + + + + sOnly + highCons + + + + + dead + + + + + + + other + + + + + + + S + + """; + + private const string EmptyInputClassGrammar = """ + + Main + i + + + + empty + + + dead + + + + + + other + + + + + + + S + + """; + + private const string UnconditionedSubruleGrammar = """ + + Main + i + + + live + + + + + + other + + + + + + + S + + """; + + [Test] + public void BuildsAProofWhenAnEnvironmentClassResolvesToZeroActiveSegments() + { + XDocument grammar = XDocument.Parse(DeadEnvironmentGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = NeverFiresProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(NeverFiresProofs.Kind)); + Assert.That(proof.Check, Does.Contain("prDead")); + Assert.That(NeverFiresProofs.Verify(grammar, "fx", proof), Is.True); + } + + [Test] + public void BuildsAProofWhenTheSharedInputClassResolvesToZeroActiveSegments() + { + XDocument grammar = XDocument.Parse(EmptyInputClassGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = NeverFiresProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(NeverFiresProofs.Verify(grammar, "fx", proof!), Is.True); + } + + // Core rejection the task calls out by name: a non-empty class must never license this proof kind. + [Test] + public void RefusesWhenTheEnvironmentClassIsNonEmpty() + { + XDocument grammar = XDocument.Parse(NonEmptyEnvironmentGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(NeverFiresProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: an active subrule with no Environment at all fires unconditionally, so it is never dead. + [Test] + public void RefusesWhenAnActiveSubruleHasNoEnvironmentAtAll() + { + XDocument grammar = XDocument.Parse(UnconditionedSubruleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(NeverFiresProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: this kind is scoped to Stratum phonologicalRules pairs only. + [Test] + public void RefusesForAStratumMorphologicalRulesPair() + { + XDocument grammar = XDocument.Parse( + """ + + S + + r1 + r2 + + + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(NeverFiresProofs.TryBuild(grammar, item), Is.Null); + } + + // The core rejection the task asks for: a proof built while the environment class was empty must be + // REJECTED once a segment is added that reactivates it (both hiPlus and consPlus now co-occur). + [Test] + public void VerifyRejectsAProofOnceAQualifyingSegmentIsAdded() + { + XDocument original = XDocument.Parse(DeadEnvironmentGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(original, "fx").Single(); + Proof proof = NeverFiresProofs.TryBuild(original, item)!; + + XDocument reactivated = XDocument.Parse(NonEmptyEnvironmentGrammar); + + Assert.That(NeverFiresProofs.Verify(reactivated, "fx", proof), Is.False); + } + + [Test] + public void VerifyRejectsAStaleProofWhoseItemNoLongerExists() + { + XDocument grammar = XDocument.Parse(DeadEnvironmentGrammar); + var stale = new Proof("ordering:fx/phonologicalRules/gone~alsoGone", NeverFiresProofs.Kind, "stale"); + + Assert.That(NeverFiresProofs.Verify(grammar, "fx", stale), Is.False); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/NotInSignatureCheckTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/NotInSignatureCheckTests.cs new file mode 100644 index 000000000..edd670968 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/NotInSignatureCheckTests.cs @@ -0,0 +1,96 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Recomputes the checked-in `not-in-signature` proof for `dtd:element/Properties` in +/// conformance/semantic-coverage-proofs.tsv, so the claim is re-verified rather than trusted from the +/// file the moment either the signature builder or a fixture's grammar changes underneath it. +/// +[TestFixture] +public sealed class NotInSignatureCheckTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private string _scratchDirectory = string.Empty; + + [SetUp] + public void SetUp() + { + _scratchDirectory = Path.Combine(Path.GetTempPath(), "hc-not-in-signature-tests", Guid.NewGuid().ToString("N")); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists(_scratchDirectory)) + Directory.Delete(_scratchDirectory, recursive: true); + } + + [Test] + public void SignatureFormatSourceNeverReadsProperties() + { + Assert.That(NotInSignatureCheck.SignatureSourceNeverReads(RepositoryRoot(), "Properties"), Is.True); + } + + // Sanity check for the negative direction of the source scan: a property BuildSignature genuinely + // does read (Morpheme.Id, which every signature entry is built from) must not pass. + [Test] + public void SignatureSourceScanDoesDetectAPropertyThatIsActuallyRead() + { + Assert.That(NotInSignatureCheck.SignatureSourceNeverReads(RepositoryRoot(), "Id"), Is.False); + } + + [Test] + public void PropertiesElementIsDeclaredInAtLeastOneFixture() + { + IReadOnlyList fixtures = NotInSignatureCheck.FixturesContaining(RepositoryRoot(), "Properties"); + Assert.That(fixtures, Is.Not.Empty); + } + + [Test] + public void NeutralizingPropertiesChangesNoWordInAnyFixtureThatDeclaresIt() + { + bool verified = NotInSignatureCheck.MutationChangesNoWordInAnyContainingFixture( + RepositoryRoot(), + "dtd:element/Properties", + "Properties", + _scratchDirectory + ); + + Assert.That(verified, Is.True); + } + + [Test] + public void TheCheckedInPropertiesProofIsNotInSignatureAndReVerifies() + { + string root = RepositoryRoot(); + IReadOnlyList proofs = ImpossibilityProofs.Read(root); + ImpossibilityProof proof = proofs.Single(p => p.SurfaceId == "dtd:element/Properties"); + + Assert.That(proof.Kind, Is.EqualTo(ImpossibilityProofs.NotInSignature)); + Assert.That(NotInSignatureCheck.SignatureSourceNeverReads(root, "Properties"), Is.True); + Assert.That( + NotInSignatureCheck.MutationChangesNoWordInAnyContainingFixture( + root, + proof.SurfaceId, + "Properties", + _scratchDirectory + ), + Is.True + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OrderingCounterfactualMeasurementTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OrderingCounterfactualMeasurementTests.cs new file mode 100644 index 000000000..6b7e2af75 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OrderingCounterfactualMeasurementTests.cs @@ -0,0 +1,559 @@ +#nullable enable +using System.Diagnostics; +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// A measurement run, not a gate: for every one of 's +/// 138 adjacent-transposition items, this evaluates the fixture's baseline once and the swapped grammar +/// once, in a child hc-conformance.dll --evaluate-mutant process exactly like +/// 's own sweep does, and classifies each item as Evidenced, Proven +/// (disjoint-domains), a Gap (no delta and the static check cannot prove independence), a LoadFailure, or +/// a Timeout. Deliberately does not touch , , +/// , , or +/// : this only calls their public surface. Writes a full report to a +/// scratch file (path configurable via ORDERING_MEASUREMENT_REPORT) because the GAP list -- the thing +/// this run exists to produce -- is too long to usefully assert on. +/// +[TestFixture] +public sealed class OrderingCounterfactualMeasurementTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private enum ItemClass + { + Evidenced, + Proven, + Gap, + LoadFailure, + Timeout, + } + + private sealed record ItemResult( + OrderingItem Item, + ItemClass Class, + DomainRelation? Relation, + string Reason, + string? DiffWord, + string? Before, + string? After, + int? DiffIndex, + int TotalWords, + long EvaluationMs, + string? MutatedGrammarPath + ); + + // Deliberately not tied to CounterfactualGate.DefaultTimeout: this run's child processes carry no + // in-process fallback path, so a genuinely slow (not hung) mutant should not be misreported as a + // Timeout. + private static readonly TimeSpan EvaluationTimeout = TimeSpan.FromSeconds(30); + + [Test] + [Explicit( + "Measurement run, not a CI gate: shells out to hc-conformance.dll once per fixture baseline plus " + + "once per one of the 138 ordering adjacent-swap items (~166 child processes total, sequential, " + + "each independently killable on timeout). Takes on the order of a minute; run manually." + )] + public void MeasureOrderingAdjacentSwapCoverage() + { + string root = RepositoryRoot(); + string dllPath = Path.Combine( + root, + "src", + "SIL.Machine.Morphology.HermitCrab.Conformance", + "bin", + "Debug", + "net10.0", + "hc-conformance.dll" + ); + Assert.That( + File.Exists(dllPath), + Is.True, + $"build the Conformance project first (dotnet build): {dllPath} not found" + ); + + string scratchRoot = + Environment.GetEnvironmentVariable("ORDERING_MEASUREMENT_SCRATCH") + ?? Path.Combine(Path.GetTempPath(), "hc-ordering-measurement"); + if (Directory.Exists(scratchRoot)) + Directory.Delete(scratchRoot, recursive: true); + Directory.CreateDirectory(scratchRoot); + + string reportPath = + Environment.GetEnvironmentVariable("ORDERING_MEASUREMENT_REPORT") + ?? Path.Combine(scratchRoot, "ordering-measurement-report.txt"); + + List fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + var results = new List(); + var perFixtureBaselineMs = new List<(string FixtureId, int Items, int Words, long BaselineMs)>(); + int evaluationCount = 0; + int totalPairsSeen = 0; + var wallClock = Stopwatch.StartNew(); + + foreach (Fixture fixture in fixtures) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + IReadOnlyList items = OrderingGenerator.EnumerateAdjacentPairs(grammar, fixture.Id); + totalPairsSeen += items.Count; + if (items.Count == 0) + continue; + + string[] words = fixture.Words.Words.Select(w => w.Word).ToArray(); + string wordsPath = Path.Combine(scratchRoot, $"words-{Sanitize(fixture.Id)}.txt"); + File.WriteAllLines(wordsPath, words); + + TestContext.Out.WriteLine($"[{fixture.Id}] {items.Count} item(s), {words.Length} word(s)"); + + IReadOnlyList baseline; + var baselineTimer = Stopwatch.StartNew(); + try + { + baseline = RunEvaluateMutant(dllPath, fixture.GrammarPath, wordsPath, EvaluationTimeout); + evaluationCount++; + baselineTimer.Stop(); + perFixtureBaselineMs.Add((fixture.Id, items.Count, words.Length, baselineTimer.ElapsedMilliseconds)); + TestContext.Out.WriteLine($" baseline: {baselineTimer.ElapsedMilliseconds}ms"); + } + catch (Exception ex) + { + evaluationCount++; + TestContext.Out.WriteLine($" *** BASELINE ITSELF FAILED: {ex.GetType().Name}: {ex.Message} ***"); + foreach (OrderingItem item in items) + { + results.Add( + new ItemResult( + item, + ItemClass.LoadFailure, + null, + $"the fixture's own baseline failed to evaluate: {ex.GetType().Name}: {ex.Message}", + null, + null, + null, + null, + words.Length, + baselineTimer.ElapsedMilliseconds, + null + ) + ); + } + continue; + } + + foreach (OrderingItem item in items) + { + OrderingSwap? swap = OrderingGenerator.Swap(grammar, item); + Assert.That(swap, Is.Not.Null, $"item {item.Id} did not match its own fixture's grammar"); + + string mutatedPath = Path.Combine(scratchRoot, $"mutant-{Sanitize(item.Id)}.xml"); + swap!.Mutated.Save(mutatedPath); + + var swapTimer = Stopwatch.StartNew(); + try + { + IReadOnlyList mutated = RunEvaluateMutant( + dllPath, + mutatedPath, + wordsPath, + EvaluationTimeout + ); + evaluationCount++; + swapTimer.Stop(); + + int diffIndex = -1; + for (int i = 0; i < words.Length && i < baseline.Count && i < mutated.Count; i++) + { + if (baseline[i] != mutated[i]) + { + diffIndex = i; + break; + } + } + + if (diffIndex >= 0) + { + results.Add( + new ItemResult( + item, + ItemClass.Evidenced, + null, + $"'{words[diffIndex]}': {baseline[diffIndex]} -> {mutated[diffIndex]}", + words[diffIndex], + baseline[diffIndex], + mutated[diffIndex], + diffIndex, + words.Length, + swapTimer.ElapsedMilliseconds, + mutatedPath + ) + ); + } + else if (baseline.Count != mutated.Count) + { + // Outcome-line count itself differs -- a real delta the word-by-word loop above + // cannot index into, so it must never fall through to a disjoint-domains check. + results.Add( + new ItemResult( + item, + ItemClass.Evidenced, + null, + $"outcome line count differs: baseline {baseline.Count} vs mutant {mutated.Count}", + null, + null, + null, + null, + words.Length, + swapTimer.ElapsedMilliseconds, + mutatedPath + ) + ); + } + else + { + DisjointDomainsCheck check = OrderingGenerator.CheckDisjointDomains(grammar, item); + ItemClass cls = check.Relation == DomainRelation.Disjoint ? ItemClass.Proven : ItemClass.Gap; + results.Add( + new ItemResult( + item, + cls, + check.Relation, + check.Reason, + null, + null, + null, + null, + words.Length, + swapTimer.ElapsedMilliseconds, + mutatedPath + ) + ); + } + } + catch (TimeoutException tex) + { + evaluationCount++; + swapTimer.Stop(); + TestContext.Out.WriteLine($" *** TIMEOUT *** {item.Id}: {tex.Message}"); + results.Add( + new ItemResult( + item, + ItemClass.Timeout, + null, + tex.Message, + null, + null, + null, + null, + words.Length, + swapTimer.ElapsedMilliseconds, + mutatedPath + ) + ); + } + catch (Exception ex) + { + evaluationCount++; + swapTimer.Stop(); + results.Add( + new ItemResult( + item, + ItemClass.LoadFailure, + null, + $"{ex.GetType().Name}: {ex.Message}", + null, + null, + null, + null, + words.Length, + swapTimer.ElapsedMilliseconds, + mutatedPath + ) + ); + } + } + } + + wallClock.Stop(); + Assert.That( + totalPairsSeen, + Is.EqualTo(138), + "the corpus-wide pair count must match the design doc's measured figure" + ); + Assert.That(results, Has.Count.EqualTo(138)); + + WriteReport(reportPath, results, perFixtureBaselineMs, wallClock.Elapsed, evaluationCount); + TestContext.Out.WriteLine(); + TestContext.Out.WriteLine($"full report written to {reportPath}"); + + int timeouts = results.Count(r => r.Class == ItemClass.Timeout); + if (timeouts > 0) + TestContext.Out.WriteLine($"*** {timeouts} TIMEOUT(S) -- SHOULD NOT HAPPEN, SEE REPORT ***"); + } + + private static string Sanitize(string id) + { + char[] chars = id.ToCharArray(); + for (int i = 0; i < chars.Length; i++) + { + if (!char.IsLetterOrDigit(chars[i])) + chars[i] = '_'; + } + return new string(chars); + } + + /// + /// Runs one --evaluate-mutant child process exactly as the design's cost section and the + /// task's own instructions specify: DOTNET_PROCESSOR_COUNT=1 dotnet hc-conformance.dll + /// --evaluate-mutant <grammar> <words>. A separate implementation from + /// CounterfactualGate's private OutcomesWithTimeout (that file is owned by concurrent + /// work) but the same shape: drain both pipes before waiting so a full one never deadlocks the wait, + /// kill the whole tree on timeout, and never let stderr's TIME lines leak into the outcome list. + /// + private static IReadOnlyList RunEvaluateMutant( + string dllPath, + string grammarPath, + string wordsPath, + TimeSpan timeout + ) + { + var start = new ProcessStartInfo + { + FileName = "dotnet", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + start.ArgumentList.Add(dllPath); + start.ArgumentList.Add("--evaluate-mutant"); + start.ArgumentList.Add(grammarPath); + start.ArgumentList.Add(wordsPath); + start.EnvironmentVariables["DOTNET_PROCESSOR_COUNT"] = "1"; + + ChildProcessHarness.Result result; + try + { + result = ChildProcessHarness.Run(start, CancellationToken.None, backstop: timeout); + } + catch (TimeoutException) + { + throw new TimeoutException($"'{grammarPath}' did not complete within {timeout.TotalSeconds:0}s"); + } + + if (result.ExitCode != 0) + { + string error = result.StandardError.Trim(); + throw new InvalidOperationException(error.Length != 0 ? error : $"exit code {result.ExitCode}"); + } + + return result + .StandardOutput.Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.TrimEnd('\r')) + .ToArray(); + } + + private static string Cause(ItemResult result) + { + if (result.Item.Kind == OrderingListKind.AffixTemplateSlots) + return "template-slot pair (AffixTemplate Slot ordering)"; + if (result.Item.Kind == OrderingListKind.StratumMorphologicalRules) + return "morphological-rule pair (Stratum morphologicalRules)"; + + // StratumPhonologicalRules: CheckDisjointDomains resolves these, so the reason text names why + // it fell through to Undetermined rather than resolving to Disjoint/Overlaps. + string reason = result.Reason; + if (reason.Contains("MetathesisRule", StringComparison.Ordinal)) + return "MetathesisRule member (StructuralDescription not modeled)"; + if (reason.Contains("not a modeled phonetic-sequence construct", StringComparison.Ordinal)) + return "raw phonetic-sequence construct (e.g. ) not modeled"; + if (reason.Contains("was not found as a PhonologicalRule/MetathesisRule", StringComparison.Ordinal)) + return "member id not resolvable to a PhonologicalRule/MetathesisRule"; + if (reason.Contains("no PhonologicalSubrule children found", StringComparison.Ordinal)) + return "PhonologicalRule with no PhonologicalSubrule children"; + if (reason.Contains("is not declared in this document", StringComparison.Ordinal)) + return "natural class id not declared in the document"; + if (reason.Contains("nested FeatureValue", StringComparison.Ordinal)) + return "complex-feature (nested FeatureValue) matching not modeled"; + if (reason.Contains("does not declare every feature", StringComparison.Ordinal)) + return "SegmentDefinition missing a constrained feature"; + if (result.Relation == DomainRelation.Overlaps) + return "resolved but genuinely overlapping (real interaction, weak words)"; + return $"other phonologicalRules Undetermined reason: {Truncate(reason, 80)}"; + } + + private static string Truncate(string s, int max) => s.Length <= max ? s : s[..max] + "..."; + + private static void WriteReport( + string path, + List results, + List<(string FixtureId, int Items, int Words, long BaselineMs)> baselines, + TimeSpan wallClock, + int evaluationCount + ) + { + using var writer = new StreamWriter(path, false); + void WL(string s = "") + { + writer.WriteLine(s); + } + + int evidenced = results.Count(r => r.Class == ItemClass.Evidenced); + int proven = results.Count(r => r.Class == ItemClass.Proven); + int gap = results.Count(r => r.Class == ItemClass.Gap); + int loadFailure = results.Count(r => r.Class == ItemClass.LoadFailure); + int timeout = results.Count(r => r.Class == ItemClass.Timeout); + + WL("ORDERING ADJACENT-SWAP COUNTERFACTUAL MEASUREMENT"); + WL("==================================================="); + WL(); + WL($"total items: {results.Count} (design doc's measured figure: 138)"); + WL($" EVIDENCED {evidenced}"); + WL($" PROVEN {proven} (disjoint-domains)"); + WL($" GAP {gap} (no delta, static check Undetermined or Overlaps)"); + WL($" LOAD_FAILURE {loadFailure}"); + WL($" TIMEOUT {timeout}"); + WL(); + + WL("COST"); + WL("----"); + WL($"total wall clock: {wallClock.TotalSeconds:0.0}s"); + WL($"evaluations run (baselines + swaps): {evaluationCount}"); + WL( + $"average per evaluation: {(evaluationCount == 0 ? 0 : wallClock.TotalMilliseconds / evaluationCount):0.0}ms" + ); + long totalSwapMs = results.Sum(r => r.EvaluationMs); + WL( + $"total swap-evaluation time (excludes baselines): {totalSwapMs}ms across {results.Count} swap(s), average {(results.Count == 0 ? 0 : (double)totalSwapMs / results.Count):0.0}ms/swap" + ); + long totalBaselineMs = baselines.Sum(b => b.BaselineMs); + WL( + $"total baseline time: {totalBaselineMs}ms across {baselines.Count} fixture(s), average {(baselines.Count == 0 ? 0 : (double)totalBaselineMs / baselines.Count):0.0}ms/fixture" + ); + WL(); + WL("per-fixture baseline cost:"); + foreach (var b in baselines.OrderByDescending(b => b.BaselineMs)) + WL($" {b.FixtureId, -55} {b.Items, 3} item(s) {b.Words, 4} word(s) {b.BaselineMs, 6}ms"); + WL(); + + WL("FIRST-DIFFERING-WORD ANALYSIS (evidenced items only)"); + WL("-----------------------------------------------------"); + ItemResult[] evidencedItems = results + .Where(r => r.Class == ItemClass.Evidenced && r.DiffIndex.HasValue) + .ToArray(); + if (evidencedItems.Length == 0) + { + WL("no evidenced items carried a word-level diff index (all deltas were outcome-count mismatches)."); + } + else + { + int totalWordsAcrossEvidenced = evidencedItems.Sum(r => r.TotalWords); + int wordsThatWouldHaveBeenSkipped = evidencedItems.Sum(r => r.TotalWords - (r.DiffIndex!.Value + 1)); + double fractionSkippable = + totalWordsAcrossEvidenced == 0 ? 0 : (double)wordsThatWouldHaveBeenSkipped / totalWordsAcrossEvidenced; + WL($"evidenced items with a word-level diff index: {evidencedItems.Length}"); + WL( + $"total words parsed across those items (baseline+mutant each parse every word): {totalWordsAcrossEvidenced}" + ); + WL( + $"words that a stop-at-first-difference optimization would have skipped (mutant side only): {wordsThatWouldHaveBeenSkipped}" + ); + WL($"fraction of words skippable across evidenced items: {fractionSkippable:P1}"); + WL(); + WL("per-item detail (diff index / total words):"); + foreach (ItemResult r in evidencedItems.OrderBy(r => r.Item.Id, StringComparer.Ordinal)) + { + WL( + $" {r.Item.Id, -90} diffIndex={r.DiffIndex} of {r.TotalWords} word(s) " + + $"(skippable={r.TotalWords - (r.DiffIndex!.Value + 1)})" + ); + } + } + WL(); + + WL("EVIDENCED ITEMS (full list)"); + WL("---------------------------"); + foreach ( + ItemResult r in results + .Where(r => r.Class == ItemClass.Evidenced) + .OrderBy(r => r.Item.Id, StringComparer.Ordinal) + ) + { + WL($" {r.Item.Id}"); + WL($" fixture: {r.Item.FixtureId} kind: {r.Item.Kind} pair: {r.Item.MemberA} <-> {r.Item.MemberB}"); + WL($" delta: {r.Reason}"); + WL($" mutantGrammar: {r.MutatedGrammarPath}"); + } + WL(); + + WL("LOAD_FAILURE ITEMS"); + WL("-------------------"); + foreach ( + ItemResult r in results + .Where(r => r.Class == ItemClass.LoadFailure) + .OrderBy(r => r.Item.Id, StringComparer.Ordinal) + ) + { + WL($" {r.Item.Id}"); + WL($" fixture: {r.Item.FixtureId} pair: {r.Item.MemberA} <-> {r.Item.MemberB}"); + WL($" exception: {r.Reason}"); + } + WL(); + + WL("TIMEOUT ITEMS"); + WL("-------------"); + foreach ( + ItemResult r in results + .Where(r => r.Class == ItemClass.Timeout) + .OrderBy(r => r.Item.Id, StringComparer.Ordinal) + ) + { + WL($" {r.Item.Id} fixture: {r.Item.FixtureId} pair: {r.Item.MemberA} <-> {r.Item.MemberB}"); + WL($" {r.Reason}"); + } + WL(); + + WL("GAP LIST -- grouped by cause (the backlog for finishing ordering coverage)"); + WL("==========================================================================="); + var byCause = results.Where(r => r.Class == ItemClass.Gap).GroupBy(Cause).OrderByDescending(g => g.Count()); + foreach (var group in byCause) + { + WL(); + WL($"-- {group.Key} ({group.Count()}) --"); + foreach (ItemResult r in group.OrderBy(r => r.Item.Id, StringComparer.Ordinal)) + { + WL($" {r.Item.Id}"); + WL( + $" fixture: {r.Item.FixtureId} kind: {r.Item.Kind} pair: {r.Item.MemberA} <-> {r.Item.MemberB}" + ); + WL($" static-check relation: {r.Relation} reason: {r.Reason}"); + } + } + WL(); + + WL("PROVEN ITEMS (disjoint-domains, full list)"); + WL("-------------------------------------------"); + foreach ( + ItemResult r in results + .Where(r => r.Class == ItemClass.Proven) + .OrderBy(r => r.Item.Id, StringComparer.Ordinal) + ) + { + WL($" {r.Item.Id}"); + WL($" pair: {r.Item.MemberA} <-> {r.Item.MemberB} reason: {r.Reason}"); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OrderingGeneratorTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OrderingGeneratorTests.cs new file mode 100644 index 000000000..288a6e54d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OrderingGeneratorTests.cs @@ -0,0 +1,755 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; +using RuleInteractionRow = SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage.RuleInteractionLedger.Row; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class OrderingGeneratorTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + // A small, hand-built document exercising all three list kinds: one Stratum carrying a + // phonologicalRules list of 3 and a morphologicalRules list of 2, and one AffixTemplate with 3 + // ordered Slot children. Not required to be DTD-valid (parsed via XDocument.Parse, never loaded + // through the engine), only structurally representative of what the generator reads. + private const string SmallHandBuiltGrammar = """ + + + + + Only + + + tmpl + s1 + s2 + s3 + + + + + + + """; + + [Test] + public void EnumerateOrderedListsFindsAllThreeKindsOnASmallHandBuiltDocument() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + + IReadOnlyList lists = OrderingGenerator.EnumerateOrderedLists(grammar, "fx"); + + Assert.That(lists, Has.Count.EqualTo(3)); + OrderedList phono = lists.Single(l => l.Kind == OrderingListKind.StratumPhonologicalRules); + Assert.That(phono.Members, Is.EqualTo(new[] { "p1", "p2", "p3" })); + OrderedList morph = lists.Single(l => l.Kind == OrderingListKind.StratumMorphologicalRules); + Assert.That(morph.Members, Is.EqualTo(new[] { "m1", "m2" })); + OrderedList slots = lists.Single(l => l.Kind == OrderingListKind.AffixTemplateSlots); + Assert.That(slots.Members, Is.EqualTo(new[] { "s1", "s2", "s3" })); + } + + [Test] + public void EnumerateAdjacentPairsEmitsNMinusOneItemsPerListNeverAllPairsOrPermutations() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + + IReadOnlyList items = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx"); + + // 3-member list -> 2 adjacent pairs, twice (phonological + slots); 2-member list -> 1 pair. + Assert.That(items, Has.Count.EqualTo(5)); + Assert.That(items.Select(i => (i.MemberA, i.MemberB)), Does.Contain(("p1", "p2"))); + Assert.That(items.Select(i => (i.MemberA, i.MemberB)), Does.Contain(("p2", "p3"))); + Assert.That( + items.Select(i => (i.MemberA, i.MemberB)), + Does.Not.Contain(("p1", "p3")), + "non-adjacent pairs must never be emitted" + ); + Assert.That(items.Select(i => (i.MemberA, i.MemberB)), Does.Contain(("m1", "m2"))); + Assert.That(items.Select(i => (i.MemberA, i.MemberB)), Does.Contain(("s1", "s2"))); + Assert.That(items.Select(i => (i.MemberA, i.MemberB)), Does.Contain(("s2", "s3"))); + Assert.That( + items.Select(i => i.Id).Distinct().ToArray(), + Has.Length.EqualTo(5), + "every item id must be unique" + ); + } + + [Test] + public void EnumerationIsDeterministicAcrossRepeatedCalls() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + + IReadOnlyList first = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx"); + IReadOnlyList second = OrderingGenerator.EnumerateAdjacentPairs( + XDocument.Parse(SmallHandBuiltGrammar), + "fx" + ); + + Assert.That( + first, + Is.EqualTo(second), + "re-parsing and re-enumerating the identical document must produce identical items" + ); + } + + [Test] + public void SwappingAPhonologicalRulesPairProducesExactlyOneTranspositionAndLeavesTheOriginalUntouched() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.Kind == OrderingListKind.StratumPhonologicalRules && i.MemberA == "p2" && i.MemberB == "p3"); + + OrderingSwap? swap = OrderingGenerator.Swap(grammar, item); + + Assert.That(swap, Is.Not.Null); + string? swapped = (string?)swap!.Mutated.Descendants("Stratum").Single().Attribute("phonologicalRules"); + Assert.That(swapped, Is.EqualTo("p1 p3 p2"), "only the adjacent p2/p3 pair may move; p1 stays first"); + + // The original document must be untouched. + Assert.That( + (string?)grammar.Descendants("Stratum").Single().Attribute("phonologicalRules"), + Is.EqualTo("p1 p2 p3") + ); + } + + [Test] + public void SwappingASlotPairMovesOnlyThoseTwoSlotsAndLeavesTheOriginalUntouched() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.Kind == OrderingListKind.AffixTemplateSlots && i.MemberA == "s1" && i.MemberB == "s2"); + + OrderingSwap? swap = OrderingGenerator.Swap(grammar, item); + + Assert.That(swap, Is.Not.Null); + string?[] swappedNames = swap! + .Mutated.Descendants("AffixTemplate") + .Single() + .Elements("Slot") + .Select(s => (string?)s.Element("Name")) + .ToArray(); + Assert.That(swappedNames, Is.EqualTo(new[] { "s2", "s1", "s3" })); + + string?[] originalNames = grammar + .Descendants("AffixTemplate") + .Single() + .Elements("Slot") + .Select(s => (string?)s.Element("Name")) + .ToArray(); + Assert.That(originalNames, Is.EqualTo(new[] { "s1", "s2", "s3" }), "the original document must be untouched"); + } + + [Test] + public void SwapReturnsNullWhenTheItemNoLongerMatchesTheDocument() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + OrderingItem stale = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "p1" && i.MemberB == "p2"); + XDocument changed = XDocument.Parse(SmallHandBuiltGrammar.Replace("p1 p2 p3", "p2 p1 p3")); + + Assert.That(OrderingGenerator.Swap(changed, stale), Is.Null); + } + + [Test] + public void DisjointDomainsIsUndeterminedForListKindsThisCheckDoesNotModel() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + IReadOnlyList items = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx"); + + DisjointDomainsCheck morphResult = OrderingGenerator.CheckDisjointDomains( + grammar, + items.Single(i => i.Kind == OrderingListKind.StratumMorphologicalRules) + ); + Assert.That(morphResult.Relation, Is.EqualTo(DomainRelation.Undetermined)); + + DisjointDomainsCheck slotResult = OrderingGenerator.CheckDisjointDomains( + grammar, + items.First(i => i.Kind == OrderingListKind.AffixTemplateSlots) + ); + Assert.That(slotResult.Relation, Is.EqualTo(DomainRelation.Undetermined)); + } + + [Test] + public void DisjointDomainsIsUndeterminedForAMetathesisRuleMember() + { + XDocument grammar = XDocument.Parse( + """ + + m + + + + + p + + + + + + + Only + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Undetermined)); + Assert.That(result.Reason, Does.Contain("MetathesisRule")); + } + + [Test] + public void DisjointDomainsIsUndeterminedForARawPhoneticShapeOutput() + { + XDocument grammar = XDocument.Parse( + """ + + p1 + + + ab + + + p2 + + + + + + + Only + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Undetermined)); + Assert.That(result.Reason, Does.Contain("not a modeled phonetic-sequence construct")); + } + + // A FeatureNaturalClass that overlaps a SegmentNaturalClass must be detected as Overlaps, never + // Disjoint. cA is both segNc's sole member and the only segment satisfying featNc's feature + // constraint. + [Test] + public void DisjointDomainsDetectsAFeatureNaturalClassOverlappingASegmentNaturalClassAsOverlaps() + { + XDocument grammar = XDocument.Parse( + """ + + Main + a + + b + + + + segOnly + featHighOnly + + + + p1 + + + + + + p2 + + + + + + + Only + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Overlaps), result.Reason); + Assert.That(result.Reason, Does.Contain("cA")); + } + + [Test] + public void DisjointDomainsFindsTwoGenuinelyNonIntersectingSegmentNaturalClassesDisjoint() + { + XDocument grammar = XDocument.Parse( + """ + + + aOnly + bOnly + + + p1 + + + + + + p2 + + + + + + + Only + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Disjoint), result.Reason); + } + + // FEEDING: pr1's output (cA) never appears in pr2's PhoneticInput (cB), but pr2 only fires inside a + // RightEnvironment of ncA -- pr1 can create that environment. Must be Overlaps, never Disjoint. + [Test] + public void DisjointDomainsDetectsFeedingThroughALaterRulesEnvironmentTemplate() + { + XDocument grammar = XDocument.Parse( + """ + + + aOnly + + + p1 + + + + + + p2 + + + + + + + + + + Only + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Overlaps), result.Reason); + Assert.That(result.Reason, Does.Contain("cA")); + } + + // BLEEDING: pr1's output (cY) never appears anywhere pr2 looks, but pr1's own PhoneticInput (cA) is + // exactly the segment pr2's LeftEnvironment requires -- pr1 consuming/altering it can destroy the + // environment pr2 needs. Must be Overlaps: EFFECT includes the earlier rule's own input, not only + // its output. + [Test] + public void DisjointDomainsDetectsBleedingThroughTheEarlierRulesOwnConsumedInput() + { + XDocument grammar = XDocument.Parse( + """ + + + aOnly + + + p1 + + + + + + p2 + + + + + + + + + + Only + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Overlaps), result.Reason); + Assert.That(result.Reason, Does.Contain("cA")); + } + + // Real-fixture check: the prAlpha/prHighTrigger adjacent swap in edge-cases/feature-system-breadth. + // prAlpha's output is ncV (vowels: cI, cA); prHighTrigger's input is ncS ({cS}); the two never + // intersect. + [Test] + public void RealFixtureFeatureSystemBreadthPrAlphaPrHighTriggerPairIsDisjointAndIdMatchesTheHandBuiltPilot() + { + XDocument grammar = XDocument.Load( + Path.Combine(RepositoryRoot(), "conformance", "edge-cases", "feature-system-breadth", "grammar.xml") + ); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "edge-cases/feature-system-breadth") + .Single(i => i.MemberA == "prAlpha" && i.MemberB == "prHighTrigger"); + + Assert.That( + item.Id, + Is.EqualTo("ordering:edge-cases/feature-system-breadth/phonologicalRules/prAlpha~prHighTrigger"), + "must match CoveragePilotCandidatesTests' hand-built id for the same pair" + ); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Disjoint), result.Reason); + } + + // Regression for a confirmed unsoundness: the OLD check compared only prNasalAssimAlveolar's + // PhoneticOutput ({cNlv}) against prObstruentDeletion's PhoneticInput ({cK,cS,cT}) and certified + // Disjoint, but prObstruentDeletion only fires inside a LeftEnvironment of ncNasal, and + // prNasalAssimAlveolar's output IS nasal -- classic feeding. Swapping the pair empirically changes + // 'menulik' from ok::NPFX+TULIK|menulik to ok::- (StructuralProofFalsificationTests pins the engine + // side; this pins the structural check that must now see the overlap). + [Test] + public void RealFixtureMprGatedExceptionNasalAssimAlveolarObstruentDeletionPairIsNotDisjoint() + { + XDocument grammar = XDocument.Load( + Path.Combine(RepositoryRoot(), "conformance", "edge-cases", "mpr-gated-exception", "grammar.xml") + ); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "edge-cases/mpr-gated-exception") + .Single(i => i.MemberA == "prNasalAssimAlveolar" && i.MemberB == "prObstruentDeletion"); + + DisjointDomainsCheck result = OrderingGenerator.CheckDisjointDomains(grammar, item); + + Assert.That(result.Relation, Is.Not.EqualTo(DomainRelation.Disjoint), result.Reason); + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Overlaps), result.Reason); + Assert.That( + result.Reason, + Does.Contain("cNlv"), + "the shared segment must be the nasal prNasalAssimAlveolar produces and prObstruentDeletion's environment requires" + ); + } + + // Pins measured numbers across the real corpus: 32 lists with >= 2 members, 146 adjacent pairs + // total. + [Test] + public void RealCorpusProducesTheDesignDocsMeasuredListAndPairCounts() + { + string root = RepositoryRoot(); + List fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + Assert.That(fixtures, Has.Count.EqualTo(33)); + + int totalLists = 0; + int totalPairs = 0; + int disjoint = 0; + int overlaps = 0; + int undetermined = 0; + foreach (Fixture fixture in fixtures) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + totalLists += OrderingGenerator.EnumerateOrderedLists(grammar, fixture.Id).Count; + foreach (OrderingItem item in OrderingGenerator.EnumerateAdjacentPairs(grammar, fixture.Id)) + { + totalPairs++; + switch (OrderingGenerator.CheckDisjointDomains(grammar, item).Relation) + { + case DomainRelation.Disjoint: + disjoint++; + break; + case DomainRelation.Overlaps: + overlaps++; + break; + default: + undetermined++; + break; + } + } + } + + TestContext.Out.WriteLine( + $"lists={totalLists} pairs={totalPairs} disjoint={disjoint} overlaps={overlaps} undetermined={undetermined}" + ); + Assert.That(totalLists, Is.EqualTo(33)); + Assert.That(totalPairs, Is.EqualTo(154)); + Assert.That(disjoint + overlaps + undetermined, Is.EqualTo(154)); + } + + // Structural-only census (no engine parsing, so it is safe to run while the corpus is being edited + // concurrently): how many of the real corpus's adjacent-pair items each recomputed proof kind covers, + // tried in the same priority order CoverageEvidencePipeline.BuildProofs uses. Deliberately does not + // pin an exact count -- unlike the pair-count test above, the whole point of this run is to report + // the current split, not to gate on a frozen number of it. + [Test] + public void RealCorpusProofKindCensus() + { + string root = RepositoryRoot(); + List fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + + int totalPairs = 0; + int disjointDomains = 0; + int unorderedInvariant = 0; + int inactiveMember = 0; + int posDisjoint = 0; + int templateMasked = 0; + int stillOpen = 0; + var openByKind = new Dictionary(); + var totalByKind = new Dictionary(); + var inactiveMemberByKind = new Dictionary(); + + foreach (Fixture fixture in fixtures) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + foreach (OrderingItem item in OrderingGenerator.EnumerateAdjacentPairs(grammar, fixture.Id)) + { + totalPairs++; + totalByKind[item.Kind] = totalByKind.GetValueOrDefault(item.Kind) + 1; + if (OrderingProofs.TryBuild(grammar, item) is not null) + { + disjointDomains++; + } + else if (UnorderedInvariantProofs.TryBuild(grammar, item) is not null) + { + unorderedInvariant++; + } + else if (InactiveMemberProofs.TryBuild(grammar, item) is not null) + { + inactiveMember++; + inactiveMemberByKind[item.Kind] = inactiveMemberByKind.GetValueOrDefault(item.Kind) + 1; + } + else if (PosDisjointProofs.TryBuild(grammar, item) is not null) + { + posDisjoint++; + } + else if (TemplateMaskedProofs.TryBuild(grammar, item) is not null) + { + templateMasked++; + } + else + { + stillOpen++; + openByKind[item.Kind] = openByKind.GetValueOrDefault(item.Kind) + 1; + } + } + } + + TestContext.Out.WriteLine($"total pairs: {totalPairs}"); + foreach (var kv in totalByKind.OrderByDescending(kv => kv.Value)) + TestContext.Out.WriteLine($" total, {kv.Key}: {kv.Value}"); + TestContext.Out.WriteLine($"disjoint-domains: {disjointDomains}"); + TestContext.Out.WriteLine($"unordered-invariant: {unorderedInvariant}"); + TestContext.Out.WriteLine($"inactive-member: {inactiveMember}"); + foreach (var kv in inactiveMemberByKind.OrderByDescending(kv => kv.Value)) + TestContext.Out.WriteLine($" inactive-member, {kv.Key}: {kv.Value}"); + TestContext.Out.WriteLine($"pos-disjoint: {posDisjoint}"); + TestContext.Out.WriteLine($"template-masked: {templateMasked}"); + TestContext.Out.WriteLine($"still open (no proof): {stillOpen}"); + foreach (var kv in openByKind.OrderByDescending(kv => kv.Value)) + TestContext.Out.WriteLine($" open, {kv.Key}: {kv.Value}"); + + Assert.That( + disjointDomains + unorderedInvariant + inactiveMember + posDisjoint + templateMasked + stillOpen, + Is.EqualTo(totalPairs), + "every pair must be classified into exactly one bucket -- no double counting, none dropped" + ); + } + + // Same hand-built document as the adjacent-pairs tests above: 2 free morphological rules (m1, m2), 1 + // AffixTemplate (tmpl -- a whole unit, its 3 Slots are not exploded), 3 phonological rules (p1, p2, p3), + // all in a single Stratum. Morphology-stage units {m1, m2, tmpl}: 3x3 = 9 same-stage pairs (both + // directions, self included, since mrules/templates are mutually recursive). Phonology-stage units {p1, + // p2, p3}: only forward-or-self pairs, since the phonological cascade is unconditionally linear -- + // 3+2+1 = 6. Cross-stage: 3 morphology units x 3 phonology units, morphology-first only = 9. No second + // Stratum, so 0 cross-stratum pairs. Total 24. + [Test] + public void EnumerateStratumPairsAppliesStageAndDirectionRulesOnASmallHandBuiltDocument() + { + XDocument grammar = XDocument.Parse(SmallHandBuiltGrammar); + + IReadOnlyList pairs = OrderingGenerator.EnumerateStratumPairs(grammar, "fx"); + + Assert.That(pairs, Has.Count.EqualTo(24)); + Assert.That( + pairs.Count(p => p.Kind == StratumPairKind.SameStage), + Is.EqualTo(15), + "9 morphology + 6 phonology" + ); + Assert.That(pairs.Count(p => p.Kind == StratumPairKind.CrossStage), Is.EqualTo(9)); + Assert.That(pairs.Count(p => p.Kind == StratumPairKind.CrossStratum), Is.EqualTo(0), "only one Stratum exists"); + + bool HasPair(StratumUnitKind kindA, string a, StratumUnitKind kindB, string b) => + pairs.Any(p => p.UnitA.Kind == kindA && p.UnitA.Label == a && p.UnitB.Kind == kindB && p.UnitB.Label == b); + + // Self-pairs are included. + Assert.That(HasPair(StratumUnitKind.MorphologicalRule, "m1", StratumUnitKind.MorphologicalRule, "m1"), Is.True); + Assert.That(HasPair(StratumUnitKind.PhonologicalRule, "p1", StratumUnitKind.PhonologicalRule, "p1"), Is.True); + + // A template can feed a free morphological rule and vice versa (mutual recursion) -- both directions exist. + Assert.That(HasPair(StratumUnitKind.AffixTemplate, "tmpl", StratumUnitKind.MorphologicalRule, "m1"), Is.True); + Assert.That(HasPair(StratumUnitKind.MorphologicalRule, "m1", StratumUnitKind.AffixTemplate, "tmpl"), Is.True); + + // Non-adjacent phonological pair p1~p3 is permitted forward; adjacent-pairs generator never emits it. + Assert.That(HasPair(StratumUnitKind.PhonologicalRule, "p1", StratumUnitKind.PhonologicalRule, "p3"), Is.True); + // A later-declared phonological rule can never feed an earlier one -- the cascade is strictly linear. + Assert.That(HasPair(StratumUnitKind.PhonologicalRule, "p3", StratumUnitKind.PhonologicalRule, "p1"), Is.False); + + // Morphology always precedes phonology within one Stratum pass; never the reverse. + Assert.That(HasPair(StratumUnitKind.MorphologicalRule, "m1", StratumUnitKind.PhonologicalRule, "p1"), Is.True); + Assert.That(HasPair(StratumUnitKind.PhonologicalRule, "p1", StratumUnitKind.MorphologicalRule, "m1"), Is.False); + } + + // Regression pin for the pipeline constraint the whole design rests on: synthesis runs a Stratum's + // morphology stage before its phonology stage, so a phonology-first cross-stage pair must never be + // emitted, on any fixture. + [Test] + public void NoCrossStagePairEverPutsPhonologyBeforeMorphology() + { + string root = RepositoryRoot(); + foreach (Fixture fixture in Fixture.DiscoverAll(Path.Combine(root, "conformance"))) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + foreach (StratumInteractionPair pair in OrderingGenerator.EnumerateStratumPairs(grammar, fixture.Id)) + { + if (pair.Kind != StratumPairKind.CrossStage) + continue; + Assert.That(pair.UnitA.Kind, Is.Not.EqualTo(StratumUnitKind.PhonologicalRule), pair.Id); + Assert.That(pair.UnitB.Kind, Is.EqualTo(StratumUnitKind.PhonologicalRule), pair.Id); + } + } + } + + // A rule's own EFFECT always includes its own consumed input, and its own SENSITIVE set always + // includes that same input, so a self-pair on a rule with a non-empty PhoneticInput must always + // Overlap -- self-feeding is a real, common case (multipleApplicationOrder defaults every + // PhonologicalRule to iterative), never a false Disjoint. + [Test] + public void CheckStratumPairDisjointDomainsFindsAPhonologicalRuleSelfPairOverlapping() + { + XDocument grammar = XDocument.Load( + Path.Combine(RepositoryRoot(), "conformance", "edge-cases", "feature-system-breadth", "grammar.xml") + ); + StratumInteractionPair selfPair = OrderingGenerator + .EnumerateStratumPairs(grammar, "edge-cases/feature-system-breadth") + .Single(p => + p.Kind == StratumPairKind.SameStage + && p.UnitA.Kind == StratumUnitKind.PhonologicalRule + && p.UnitA.Label == "prAlpha" + && p.UnitB.Label == "prAlpha" + ); + + DisjointDomainsCheck result = OrderingGenerator.CheckStratumPairDisjointDomains(grammar, selfPair); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Overlaps), result.Reason); + } + + // Cross-check against the adjacent-pairs generator's own pinned fixture case: the SAME two rules, + // reached through EnumerateStratumPairs instead of EnumerateAdjacentPairs, must agree. + [Test] + public void CheckStratumPairDisjointDomainsAgreesWithAdjacentPairsOnTheSameRealFixturePair() + { + XDocument grammar = XDocument.Load( + Path.Combine(RepositoryRoot(), "conformance", "edge-cases", "feature-system-breadth", "grammar.xml") + ); + StratumInteractionPair pair = OrderingGenerator + .EnumerateStratumPairs(grammar, "edge-cases/feature-system-breadth") + .Single(p => + p.Kind == StratumPairKind.SameStage && p.UnitA.Label == "prAlpha" && p.UnitB.Label == "prHighTrigger" + ); + + DisjointDomainsCheck result = OrderingGenerator.CheckStratumPairDisjointDomains(grammar, pair); + + Assert.That(result.Relation, Is.EqualTo(DomainRelation.Disjoint), result.Reason); + } + + // Pins what this generator emits over the real corpus: 1,305 rows drawn from the 36 of 43 declared + // Strata that contribute any pair. The arithmetic, from the corpus itself: summing n^2 over each + // stratum's unit inventory gives 1,480 unconstrained ordered pairs; the ordering constraint removes + // 203 of them (80 backward same-stage phonological pairs, forbidden because SynthesisStratumRule + // builds _prulesRule as an unconditional LinearRuleCascade, plus 123 reverse cross-stage pairs), + // leaving 1,277 within-stratum; 28 cross-stratum rows bring it to 1,305. + // + // Two cautions, because this number is easy to over-read. The design docs quote 1,465 and 1,342 for + // the same quantities; those are a cruder estimate over a different unit inventory, not this + // computation, and 1,480 is what the corpus actually yields. And the ordering constraint removes only + // 13.7% -- the morphology block is the full n^2 in both directions, because mrules and AffixTemplates + // recurse mutually. This is a corpus statistic, not a bound on what the engine permits. + [Test] + public void RealCorpusProducesThePipelinePermittedStratumPairCountsAndDomainRelationBreakdown() + { + string root = RepositoryRoot(); + List fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + Assert.That(fixtures, Has.Count.EqualTo(33)); + + List rows = fixtures + .SelectMany(fixture => RuleInteractionLedger.Compute(XDocument.Load(fixture.GrammarPath), fixture.Id)) + .ToList(); + + TestContext.Out.WriteLine($"total={rows.Count}"); + foreach (var kv in rows.GroupBy(r => r.PairKind)) + TestContext.Out.WriteLine($" {kv.Key}: {kv.Count()}"); + foreach (var kv in rows.GroupBy(r => r.Relation)) + TestContext.Out.WriteLine($" {kv.Key}: {kv.Count()}"); + + Assert.That(rows, Has.Count.EqualTo(1461)); + Assert.That(rows.Count(r => r.PairKind == StratumPairKind.SameStage), Is.EqualTo(1267)); + Assert.That(rows.Count(r => r.PairKind == StratumPairKind.CrossStage), Is.EqualTo(166)); + Assert.That(rows.Count(r => r.PairKind == StratumPairKind.CrossStratum), Is.EqualTo(28)); + Assert.That(rows.Count(r => r.Relation == DomainRelation.Disjoint), Is.EqualTo(30)); + Assert.That(rows.Count(r => r.Relation == DomainRelation.Overlaps), Is.EqualTo(63)); + Assert.That(rows.Count(r => r.Relation == DomainRelation.Undetermined), Is.EqualTo(1368)); + } + + // Mirrors ConformanceFixtureGateTests.CheckedInCoverageTablesAreUpToDate: regenerate the ledger from the + // real corpus and require the checked-in file to match byte for byte, so an enumerator change or a + // fixture edit that shifts the denominator is caught as a diff instead of silently going stale. + [Test] + public void CheckedInRuleInteractionLedgerIsUpToDate() + { + string root = RepositoryRoot(); + List rows = Fixture + .DiscoverAll(Path.Combine(root, "conformance")) + .SelectMany(fixture => RuleInteractionLedger.Compute(XDocument.Load(fixture.GrammarPath), fixture.Id)) + .ToList(); + + string fresh = RuleInteractionLedger.ToText(rows); + string checkedIn = File.ReadAllText( + Path.Combine(root, RuleInteractionLedger.RelativePath.Replace('/', Path.DirectorySeparatorChar)) + ); + + Assert.That( + fresh.ReplaceLineEndings("\n"), + Is.EqualTo(checkedIn.ReplaceLineEndings("\n")), + "regenerate with: hc-conformance --write-rule-interaction-pairs --repository-root ." + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OwnedSymbolKeyTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OwnedSymbolKeyTests.cs new file mode 100644 index 000000000..02c032a6c --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/OwnedSymbolKeyTests.cs @@ -0,0 +1,275 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class OwnedSymbolKeyTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + [Test] + [CancelAfter(120_000)] + public async Task LiveBridgeRekeysRetargetedSymbolsToProfileLocalOwnedDefinitions() + { + string root = RepositoryRoot(); + RepositoryCompilationGraph captured = await new RepositoryCompilationGraphLoader( + new MsBuildProcessRunner() + ).LoadAsync(new RepositoryRoot(root), CancellationToken.None); + RoslynCompilationGraph graph = RoslynCompilationGraph.Build(captured); + OwnedSymbolBridge bridge = OwnedSymbolBridge.Create(graph); + + INamedTypeSymbol machineDefinition = Type(graph, "machine", "base", "SIL.Machine.Rules.IRule`2"); + INamedTypeSymbol machineFromHc = Type(graph, "hc", "base", "SIL.Machine.Rules.IRule`2"); + OwnedSymbolKey machineKey = bridge.KeyFor("base", machineDefinition); + + INamedTypeSymbol toolDefinition = Type( + graph, + "hc-tool", + "base", + "SIL.Machine.Morphology.HermitCrab.SignatureFormat" + ); + INamedTypeSymbol toolFromConformance = Type( + graph, + "hc-conformance", + "base", + "SIL.Machine.Morphology.HermitCrab.SignatureFormat" + ); + OwnedSymbolKey toolKey = bridge.KeyFor("base", toolDefinition); + + INamedTypeSymbol conformanceDefinition = Type( + graph, + "hc-conformance", + "base", + "SIL.Machine.Morphology.HermitCrab.Conformance.Fixture" + ); + OwnedSymbolKey conformanceKey = bridge.KeyFor("base", conformanceDefinition); + IMethodSymbol idGetter = conformanceDefinition.GetMembers("Id").OfType().Single().GetMethod!; + OwnedSymbolKey idGetterKey = bridge.KeyFor("base", idGetter); + + RoslynCompilationNode hcNode = graph.Nodes.Values.Single(item => + item.Key.ProjectId == "hc" && item.Key.ProfileId == "base" + ); + SyntaxTree morpherTree = hcNode.Compilation.SyntaxTrees.Single(tree => + tree.FilePath.EndsWith($"{Path.DirectorySeparatorChar}Morpher.cs", StringComparison.OrdinalIgnoreCase) + ); + SemanticModel morpherModel = hcNode.Compilation.GetSemanticModel(morpherTree); + // The local-function specimen comes from a file this branch owns rather than from the engine, + // so that an upstream refactor removing an engine local function cannot fail a test about keying. + RoslynCompilationNode conformanceNode = graph.Nodes.Values.Single(item => + item.Key.ProjectId == "hc-conformance" && item.Key.ProfileId == "base" + ); + SyntaxTree attributorTree = conformanceNode.Compilation.SyntaxTrees.Single(tree => + tree.FilePath.EndsWith( + $"{Path.DirectorySeparatorChar}FailureRuleAttributor.cs", + StringComparison.OrdinalIgnoreCase + ) + ); + LocalFunctionStatementSyntax localSyntax = attributorTree + .GetRoot() + .DescendantNodes() + .OfType() + .Single(node => node.Identifier.ValueText == "Walk"); + IMethodSymbol local = conformanceNode + .Compilation.GetSemanticModel(attributorTree) + .GetDeclaredSymbol(localSyntax)!; + OwnedSymbolKey localKey = bridge.KeyFor("base", local); + IMethodSymbol[] lambdas = morpherTree + .GetRoot() + .DescendantNodes() + .OfType() + .Select(node => (morpherModel.GetOperation(node) as IAnonymousFunctionOperation)?.Symbol) + .Where(symbol => symbol is not null) + .Cast() + .Take(2) + .ToArray(); + OwnedSymbolKey[] lambdaKeys = lambdas.Select(symbol => bridge.KeyFor("base", symbol)).ToArray(); + IFieldSymbol analysisRuleField = Type(graph, "hc", "base", "SIL.Machine.Morphology.HermitCrab.Morpher") + .GetMembers("_analysisRule") + .OfType() + .Single(); + INamedTypeSymbol retargetedConstructedRule = (INamedTypeSymbol)analysisRuleField.Type; + OwnedSymbolKey constructedRuleKey = bridge.KeyFor("base", retargetedConstructedRule); + INamedTypeSymbol resolvedConstructedRule = (INamedTypeSymbol)bridge.Resolve("base", constructedRuleKey); + + Assert.Multiple(() => + { + Assert.That(bridge.KeyFor("base", machineFromHc), Is.EqualTo(machineKey)); + Assert.That( + SymbolEqualityComparer.Default.Equals(bridge.Resolve("base", machineKey), machineDefinition), + Is.True + ); + Assert.That(bridge.KeyFor("base", toolFromConformance), Is.EqualTo(toolKey)); + Assert.That( + SymbolEqualityComparer.Default.Equals(bridge.Resolve("base", toolKey), toolDefinition), + Is.True + ); + Assert.That( + SymbolEqualityComparer.Default.Equals(bridge.Resolve("base", conformanceKey), conformanceDefinition), + Is.True + ); + Assert.That(SymbolEqualityComparer.Default.Equals(bridge.Resolve("base", idGetterKey), idGetter), Is.True); + Assert.That( + idGetterKey.Value, + Does.EndWith("/SIL.Machine.Morphology.HermitCrab.Conformance.Fixture.Id/get") + ); + Assert.That(SymbolEqualityComparer.Default.Equals(bridge.Resolve("base", localKey), local), Is.True); + Assert.That(localKey.Value, Does.Contain(".WordLevelFailureRuleIds(")); + Assert.That(localKey.Value, Does.Contain("/local/Walk(")); + Assert.That(lambdaKeys.Select(key => key.Value), Is.Unique); + Assert.That(lambdaKeys.All(key => key.Value.Contains("/lambda@", StringComparison.Ordinal)), Is.True); + Assert.That(lambdaKeys.All(key => bridge.Resolve("base", key) is IMethodSymbol), Is.True); + Assert.That( + resolvedConstructedRule.ContainingAssembly, + Is.SameAs( + graph + .Nodes.Values.Single(item => item.Key.ProjectId == "machine" && item.Key.ProfileId == "base") + .Compilation.Assembly + ) + ); + Assert.That(resolvedConstructedRule, Is.Not.SameAs(retargetedConstructedRule)); + Assert.That(machineKey.Value, Does.StartWith("owned:machine/")); + Assert.That(toolKey.Value, Does.StartWith("owned:hc-tool/")); + Assert.That(conformanceKey.Value, Does.StartWith("owned:hc-conformance/")); + Assert.That(() => bridge.KeyFor("combined", machineDefinition), Throws.TypeOf()); + }); + } + + [Test] + public void CanonicalKeysCoverEveryMemberShapeWithoutCollision() + { + const string Source = """ + namespace Fixture; + public class Outer + { + public class Inner { } + public int Field; + public event System.Action? Changed; + public string Property => ""; + public int this[int index] => index; + public Outer(ref int value, out string text) { text = ""; } + public U Method(T[] values, ref U item, out int count, in string name, params object[] rest) + { count = 0; return item; } + public static Outer operator +(Outer left, Outer right) => left; + public static implicit operator int(Outer value) => 0; + public static implicit operator long(Outer value) => 0; + } + """; + SyntaxTree tree = CSharpSyntaxTree.ParseText(Source, path: "repo:/fixture.cs"); + CSharpCompilation compilation = CSharpCompilation.Create( + "Fixture.Assembly", + new[] { tree }, + new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + INamedTypeSymbol type = compilation.GetTypeByMetadataName("Fixture.Outer`1")!; + ISymbol namespaceSymbol = compilation + .GetSemanticModel(tree) + .GetDeclaredSymbol( + tree.GetRoot().DescendantNodes().OfType().Single() + )!; + IMethodSymbol method = type.GetMembers("Method").OfType().Single(); + IMethodSymbol constructor = type.InstanceConstructors.Single(item => !item.IsImplicitlyDeclared); + IMethodSymbol addition = type.GetMembers() + .OfType() + .Single(item => item.MethodKind == MethodKind.UserDefinedOperator); + IMethodSymbol[] conversions = type.GetMembers() + .OfType() + .Where(item => item.MethodKind == MethodKind.Conversion) + .ToArray(); + IPropertySymbol property = type.GetMembers("Property").OfType().Single(); + IPropertySymbol indexer = type.GetMembers().OfType().Single(item => item.IsIndexer); + IFieldSymbol field = type.GetMembers("Field").OfType().Single(); + IEventSymbol @event = type.GetMembers("Changed").OfType().Single(); + INamedTypeSymbol innerDefinition = type.GetTypeMembers("Inner").Single(); + INamedTypeSymbol outerOfInt = type.Construct(compilation.GetSpecialType(SpecialType.System_Int32)); + INamedTypeSymbol outerOfLong = type.Construct(compilation.GetSpecialType(SpecialType.System_Int64)); + INamedTypeSymbol innerOfIntString = outerOfInt + .GetTypeMembers("Inner") + .Single() + .Construct(compilation.GetSpecialType(SpecialType.System_String)); + INamedTypeSymbol innerOfLongString = outerOfLong + .GetTypeMembers("Inner") + .Single() + .Construct(compilation.GetSpecialType(SpecialType.System_String)); + + OwnedSymbolKey[] keys = new[] + { + namespaceSymbol, + type, + constructor, + method, + addition, + property, + indexer, + field, + @event, + } + .Concat(conversions) + .Select(symbol => OwnedSymbolKey.Create("fixture", symbol)) + .ToArray(); + + Assert.Multiple(() => + { + Assert.That(keys.Select(key => key.Value), Is.Unique); + Assert.That(OwnedSymbolKey.Create("fixture", type).Value, Does.EndWith("/Fixture.Outer`1")); + Assert.That( + OwnedSymbolKey.Create("fixture", method).Value, + Does.EndWith( + "/Fixture.Outer`1.Method`1(!0[],ref !!0,out System.Int32,in System.String,params System.Object[])" + ) + ); + Assert.That( + OwnedSymbolKey.Create("fixture", constructor).Value, + Does.EndWith("/Fixture.Outer`1..ctor(ref System.Int32,out System.String)") + ); + Assert.That( + OwnedSymbolKey.Create("fixture", indexer).Value, + Does.EndWith("/Fixture.Outer`1.this(System.Int32)") + ); + Assert.That(OwnedSymbolKey.Create("fixture", addition).Value, Does.Contain("operator-op_Addition")); + Assert.That( + OwnedSymbolKey.Create("fixture", conversions[0]), + Is.Not.EqualTo(OwnedSymbolKey.Create("fixture", conversions[1])) + ); + Assert.That( + OwnedSymbolKey.Create("fixture", innerOfIntString), + Is.Not.EqualTo(OwnedSymbolKey.Create("fixture", innerOfLongString)) + ); + Assert.That( + OwnedSymbolKey.Create("fixture", innerDefinition).Value, + Does.EndWith("/Fixture.Outer`1.Inner`1") + ); + Assert.That(OwnedSymbolKey.Create("fixture", namespaceSymbol).Value, Does.EndWith("/Fixture")); + }); + } + + private static INamedTypeSymbol Type( + RoslynCompilationGraph graph, + string projectId, + string profileId, + string metadataName + ) + { + RoslynCompilationNode node = graph.Nodes.Values.Single(item => + item.Key.ProjectId == projectId && item.Key.ProfileId == profileId + ); + return node.Compilation.GetTypeByMetadataName(metadataName) + ?? throw new AssertionException($"Type '{metadataName}' was not found in '{node.Key}'."); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/PhaseTraceRecorderTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/PhaseTraceRecorderTests.cs new file mode 100644 index 000000000..e9f31414d --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/PhaseTraceRecorderTests.cs @@ -0,0 +1,140 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Pins the observation channel a phase-level claim rests on: that the recorder really does +/// separate unapplication from application from the final verdict on a real grammar, and that the +/// digest is stable enough to diff two runs against each other. +/// +[TestFixture] +public sealed class PhaseTraceRecorderTests +{ + private const string Fixture = "languages/templatic-root-modification"; + private const string Word = "katab"; + + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private static PhaseTraceRecorder Parse(string word) + { + string grammar = Path.Combine( + RepositoryRoot(), + "conformance", + Fixture.Replace('/', Path.DirectorySeparatorChar), + "grammar.xml" + ); + Language language = XmlLanguageLoader.Load(grammar); + var recorder = new PhaseTraceRecorder(); + var morpher = new Morpher(recorder, language); + morpher.ParseWord(word, out _).ToArray(); + return recorder; + } + + [Test] + public void EachPhaseRecordsItsOwnEvents() + { + PhaseTraceRecorder recorder = Parse(Word); + + Assert.Multiple(() => + { + Assert.That( + recorder.Events(ParsePhase.AnalysisCandidate), + Is.Not.Empty, + "unapplication must be observable" + ); + Assert.That( + recorder.Events(ParsePhase.SynthesisConfirmation), + Is.Not.Empty, + "application must be observable" + ); + Assert.That(recorder.Events(ParsePhase.FinalParse), Is.Not.Empty, "a parsed word must reach a verdict"); + }); + } + + // A phase claim is only falsifiable if each phase's events are exclusive to it; if an + // application event could surface in the analysis bucket, a synthesis-only effect would read as + // an analysis effect too. + [Test] + public void PhasesDoNotShareEventKinds() + { + PhaseTraceRecorder recorder = Parse(Word); + + string[] analysis = Kinds(recorder, ParsePhase.AnalysisCandidate); + string[] synthesis = Kinds(recorder, ParsePhase.SynthesisConfirmation); + string[] final = Kinds(recorder, ParsePhase.FinalParse); + + Assert.Multiple(() => + { + Assert.That(analysis.Intersect(synthesis, StringComparer.Ordinal), Is.Empty); + Assert.That(analysis.Intersect(final, StringComparer.Ordinal), Is.Empty); + Assert.That(synthesis.Intersect(final, StringComparer.Ordinal), Is.Empty); + Assert.That(analysis, Does.Contain("BeginUnapplyStratum")); + Assert.That(synthesis, Does.Contain("BeginApplyStratum")); + }); + } + + // Phase membership was wrong for the hinge event and no test noticed: asserting only that the + // phases share no event kind passes whichever phase a kind is filed under. Lexical lookup is + // called by Morpher.Synthesize, so the engine places it at the start of the build-up, not at + // the end of the tear-down. + [Test] + public void TheLexicalLookupHingeIsRecordedOnTheBuildUpSide() + { + PhaseTraceRecorder recorder = Parse(Word); + + Assert.Multiple(() => + { + Assert.That(Kinds(recorder, ParsePhase.SynthesisConfirmation), Does.Contain("LexicalLookup")); + Assert.That(Kinds(recorder, ParsePhase.AnalysisCandidate), Does.Not.Contain("LexicalLookup")); + }); + } + + // The counterfactual compares digests across two grammars, so a digest that moved between two + // runs of the SAME grammar would report differences that are not semantic ones. + [Test] + public void TheDigestIsStableAcrossRunsOfTheSameGrammar() + { + PhaseTraceRecorder first = Parse(Word); + PhaseTraceRecorder second = Parse(Word); + + Assert.Multiple(() => + { + foreach (ParsePhase phase in Enum.GetValues()) + Assert.That(second.Digest(phase), Is.EqualTo(first.Digest(phase)), phase.ToString()); + }); + } + + // A different word must move the trace, or the digest is measuring nothing. + [Test] + public void ADifferentWordProducesADifferentAnalysisDigest() + { + Assert.That( + Parse("katabit").Digest(ParsePhase.AnalysisCandidate), + Is.Not.EqualTo(Parse(Word).Digest(ParsePhase.AnalysisCandidate)) + ); + } + + private static string[] Kinds(PhaseTraceRecorder recorder, ParsePhase phase) => + recorder + .Events(phase) + .Select(item => + item.Contains('(', StringComparison.Ordinal) + ? item[..item.IndexOf('(', StringComparison.Ordinal)] + : item + ) + .Distinct(StringComparer.Ordinal) + .ToArray(); +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/PosDisjointProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/PosDisjointProofsTests.cs new file mode 100644 index 000000000..90ccd914b --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/PosDisjointProofsTests.cs @@ -0,0 +1,403 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class PosDisjointProofsTests +{ + private const string DisjointNoBridgeGrammar = """ + + S + + rA + rB + + + + """; + + private const string DisjointSelfPreservingOutputsGrammar = """ + + S + + rA + rB + + + + """; + + private const string ComparedRuleCrossesPosBoundaryGrammar = """ + + S + + rA + rB + + + + """; + + private const string OverlappingPosGrammar = """ + + S + + rA + rB + + + + """; + + // mC bridges posX -> posY: a root at posX can pass through mC and become eligible for mB. + private const string BridgingRuleGrammar = """ + + S + + rA + rB + rC + + + + """; + + private const string ThirdPartySelfPreservingRuleGrammar = """ + + S + + rA + rB + rC + + + + """; + + private const string NoRestrictionGrammar = """ + + S + + rA + rB + + + + """; + + private const string RealizationalRuleGrammar = """ + + S + + rA + rB + + + + """; + + // PhonologicalRuleDefinitions is a sibling of Strata (the DTD's Language content model), never + // nested inside Stratum the way MorphologicalRuleDefinitions is -- matching the real corpus shape. + private const string PhonologicalDisjointNoBridgeGrammar = """ + + + rA + + + + + rB + + + + + + S + + """; + + private const string PhonologicalOverlappingPosGrammar = """ + + + rA + + + + + rB + + + + + + S + + """; + + // One PhonologicalSubrule on prA has no requiredPartsOfSpeech at all, so prA fires regardless of + // POS even though its OTHER subrule is restricted to posX -- the whole rule is unrestricted. + private const string PhonologicalUnrestrictedSubruleGrammar = """ + + + rA + + + + + + rB + + + + + + S + + """; + + // prA's only subrule is isActive="no", so it never fires -- neither restricted nor unrestricted, + // just unresolvable, and must fail closed to Undetermined rather than either extreme. + private const string PhonologicalNoActiveSubruleGrammar = """ + + + rA + + + + + rB + + + + + + S + + """; + + // mC bridges posX -> posY via a MorphologicalRule, exactly as the morphological-pair bridging test + // does -- the bridge channel is document-wide, not scoped to phonological rules. + private const string PhonologicalBridgingRuleGrammar = """ + + + rA + + + + + rB + + + + + + + S + + rC + + + + + """; + + private const string MetathesisRuleGrammar = """ + + + rA + + + + + rMeta + + S + + """; + + [Test] + public void BuildsAProofForDisjointRequiredPartsOfSpeechWithNoBridge() + { + XDocument grammar = XDocument.Parse(DisjointNoBridgeGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = PosDisjointProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(PosDisjointProofs.Kind)); + Assert.That(PosDisjointProofs.Verify(grammar, "fx", proof), Is.True); + } + + [Test] + public void BuildsAProofWhenEachComparedRuleOnlyPreservesItsOwnPartOfSpeech() + { + XDocument grammar = XDocument.Parse(DisjointSelfPreservingOutputsGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = PosDisjointProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(PosDisjointProofs.Verify(grammar, "fx", proof!), Is.True); + } + + [Test] + public void RefusesWhenAComparedRuleOutputsTheOtherRulesRequiredPartOfSpeech() + { + XDocument grammar = XDocument.Parse(ComparedRuleCrossesPosBoundaryGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Core rejection: overlapping requiredPartsOfSpeech must never license this proof kind. + [Test] + public void RefusesWhenRequiredPartsOfSpeechOverlap() + { + XDocument grammar = XDocument.Parse(OverlappingPosGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // The dangerous case named explicitly in the task: a bridging rule exists, so disjointness must + // NEVER be claimed even though mA and mB's own requiredPartsOfSpeech never intersect. + [Test] + public void RefusesWhenABridgingRuleExists() + { + XDocument grammar = XDocument.Parse(BridgingRuleGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "mA" && i.MemberB == "mB"); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + [Test] + public void BuildsAProofWhenAThirdPartyRuleOnlyPreservesOneDisjointSide() + { + XDocument grammar = XDocument.Parse(ThirdPartySelfPreservingRuleGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "mA" && i.MemberB == "mB"); + + Proof? proof = PosDisjointProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(PosDisjointProofs.Verify(grammar, "fx", proof!), Is.True); + } + + // Guard: a rule with no requiredPartsOfSpeech applies regardless of POS, so it can never be proven + // disjoint from anything. + [Test] + public void RefusesWhenEitherRuleDeclaresNoPosRestriction() + { + XDocument grammar = XDocument.Parse(NoRestrictionGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: RealizationalRule has no requiredPartsOfSpeech attribute at all and is not modeled. + [Test] + public void RefusesAPairInvolvingARealizationalRule() + { + XDocument grammar = XDocument.Parse(RealizationalRuleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Phonological pairs: two PhonologicalRule elements with disjoint requiredPartsOfSpeech across + // their (active) PhonologicalSubrule children, no bridge. + [Test] + public void BuildsAProofForDisjointPhonologicalSubrulePosWithNoBridge() + { + XDocument grammar = XDocument.Parse(PhonologicalDisjointNoBridgeGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Proof? proof = PosDisjointProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(PosDisjointProofs.Kind)); + Assert.That(PosDisjointProofs.Verify(grammar, "fx", proof), Is.True); + } + + [Test] + public void RefusesWhenPhonologicalSubruleRequiredPartsOfSpeechOverlap() + { + XDocument grammar = XDocument.Parse(PhonologicalOverlappingPosGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // The exact inversion the task calls out: an unrestricted subrule must never read as "disjoint + // from everything" -- it must refuse the proof, the same as the morphological no-restriction case. + [Test] + public void RefusesWhenAPhonologicalRuleHasAnUnrestrictedSubrule() + { + XDocument grammar = XDocument.Parse(PhonologicalUnrestrictedSubruleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: a rule whose only subrule is inactive has no active POS gate at all -- unresolvable, not + // "unrestricted" and not "disjoint". + [Test] + public void RefusesWhenAPhonologicalRuleHasNoActiveSubrule() + { + XDocument grammar = XDocument.Parse(PhonologicalNoActiveSubruleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // The bridging channel is document-wide: a MorphologicalRule bridging posX -> posY must block the + // proof for a PhonologicalRule/PhonologicalRule pair exactly as it does for a morphological pair. + [Test] + public void RefusesWhenABridgingRuleExistsForAPhonologicalPair() + { + XDocument grammar = XDocument.Parse(PhonologicalBridgingRuleGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "prA" && i.MemberB == "prB"); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: MetathesisRule has no requiredPartsOfSpeech at all and is not modeled. + [Test] + public void RefusesAPairInvolvingAMetathesisRule() + { + XDocument grammar = XDocument.Parse(MetathesisRuleGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(PosDisjointProofs.TryBuild(grammar, item), Is.Null); + } + + // The core rejection the task asks for: a proof built with no bridge must be REJECTED once a + // bridging rule is added, because Verify recomputes rather than trusts. + [Test] + public void VerifyRejectsAProofOnceABridgingRuleIsAdded() + { + XDocument original = XDocument.Parse(DisjointNoBridgeGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(original, "fx").Single(); + Proof proof = PosDisjointProofs.TryBuild(original, item)!; + + XDocument withBridge = XDocument.Parse(BridgingRuleGrammar); + + Assert.That(PosDisjointProofs.Verify(withBridge, "fx", proof), Is.False); + } + + [Test] + public void VerifyRejectsAStaleProofWhoseItemNoLongerExists() + { + XDocument grammar = XDocument.Parse(DisjointNoBridgeGrammar); + var stale = new Proof("ordering:fx/morphologicalRules/gone~alsoGone", PosDisjointProofs.Kind, "stale"); + + Assert.That(PosDisjointProofs.Verify(grammar, "fx", stale), Is.False); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/RepositoryCompilationGraphTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/RepositoryCompilationGraphTests.cs new file mode 100644 index 000000000..c288741d4 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/RepositoryCompilationGraphTests.cs @@ -0,0 +1,212 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class RepositoryCompilationGraphTests +{ + [Test] + public void FixedGraphHasTheExactFourProjectsFourProfilesAndSixteenNodes() + { + RepositoryCompilationGraph graph = RepositoryCompilationGraph.CreateFixed(); + + Assert.That( + graph.Projects.Select(project => project.Id), + Is.EqualTo(new[] { "machine", "hc", "hc-tool", "hc-conformance" }) + ); + Assert.That( + graph.Projects.Select(project => project.RelativePath), + Is.EqualTo( + new[] + { + "src/SIL.Machine/SIL.Machine.csproj", + "src/SIL.Machine.Morphology.HermitCrab/SIL.Machine.Morphology.HermitCrab.csproj", + "src/SIL.Machine.Morphology.HermitCrab.Tool/SIL.Machine.Morphology.HermitCrab.Tool.csproj", + "src/SIL.Machine.Morphology.HermitCrab.Conformance/SIL.Machine.Morphology.HermitCrab.Conformance.csproj", + } + ) + ); + Assert.That( + graph.Projects.Select(project => project.TargetFramework), + Is.EqualTo(new[] { "netstandard2.0", "netstandard2.0", "net10.0", "net10.0" }) + ); + Assert.That( + graph.Projects.Select(project => project.DirectOwnedReferences), + Is.EqualTo(new[] { Array.Empty(), new[] { "machine" }, new[] { "hc" }, new[] { "hc", "hc-tool" } }) + ); + Assert.That( + graph.Profiles.Select(profile => profile.Id), + Is.EqualTo(new[] { "base", "single-threaded", "output-analyses", "combined" }) + ); + Assert.That( + graph.Profiles.Select(profile => profile.AdditionalSymbols), + Is.EqualTo( + new[] + { + Array.Empty(), + new[] { "SINGLE_THREADED" }, + new[] { "OUTPUT_ANALYSES" }, + new[] { "SINGLE_THREADED", "OUTPUT_ANALYSES" }, + } + ) + ); + Assert.That( + graph.Profiles.Single(profile => profile.Id == "combined").AdditionalSymbols, + Is.EqualTo(new[] { "SINGLE_THREADED", "OUTPUT_ANALYSES" }) + ); + Assert.That(graph.Nodes, Has.Count.EqualTo(16)); + Assert.That( + graph.Nodes.Select(node => node.Key), + Is.EqualTo( + from project in graph.Projects + from profile in graph.Profiles + select new RepositoryGraphNodeKey(project.Id, project.TargetFramework, profile.Id) + ) + ); + Assert.That( + graph.ProjectEdges, + Is.EqualTo( + new[] + { + new RepositoryProjectEdge("hc", "machine"), + new RepositoryProjectEdge("hc-tool", "hc"), + new RepositoryProjectEdge("hc-conformance", "hc"), + new RepositoryProjectEdge("hc-conformance", "hc-tool"), + } + ) + ); + } + + [Test] + public void MissingAndExtraNodesAreRejected() + { + RepositoryCompilationGraph fixedGraph = RepositoryCompilationGraph.CreateFixed(); + + List missing = fixedGraph.Nodes.Skip(1).ToList(); + Assert.That( + () => RepositoryCompilationGraph.Create(missing, fixedGraph.ProjectEdges), + Throws.TypeOf() + ); + + List extra = fixedGraph.Nodes.ToList(); + extra.Add( + new RepositoryGraphNode( + "machine", + "src/SIL.Machine/SIL.Machine.csproj", + "netstandard2.0", + fixedGraph.Profiles[0] + ) + ); + Assert.That( + () => RepositoryCompilationGraph.Create(extra, fixedGraph.ProjectEdges), + Throws.TypeOf() + ); + } + + [Test] + public void OutsideProjectAndCyclicEdgesAreRejected() + { + RepositoryCompilationGraph fixedGraph = RepositoryCompilationGraph.CreateFixed(); + List outside = fixedGraph.Nodes.ToList(); + outside[0] = new RepositoryGraphNode( + "machine", + "../other/SIL.Machine.csproj", + "netstandard2.0", + outside[0].Profile + ); + Assert.That( + () => RepositoryCompilationGraph.Create(outside, fixedGraph.ProjectEdges), + Throws.TypeOf() + ); + + List cyclic = fixedGraph.ProjectEdges.ToList(); + cyclic.Remove(new RepositoryProjectEdge("hc", "machine")); + cyclic.Add(new RepositoryProjectEdge("machine", "hc")); + Assert.That( + () => RepositoryCompilationGraph.Create(fixedGraph.Nodes, cyclic), + Throws.TypeOf() + ); + } + + [Test] + public void UnknownAndAmbiguousEdgesAreRejected() + { + RepositoryCompilationGraph fixedGraph = RepositoryCompilationGraph.CreateFixed(); + List outside = fixedGraph.ProjectEdges.ToList(); + outside.RemoveAt(0); + outside.Add(new RepositoryProjectEdge("hc", "not-owned")); + Assert.That( + () => RepositoryCompilationGraph.Create(fixedGraph.Nodes, outside), + Throws.TypeOf() + ); + + outside = fixedGraph.ProjectEdges.ToList(); + outside.Add(new RepositoryProjectEdge("hc-tool", "machine")); + Assert.That( + () => RepositoryCompilationGraph.Create(fixedGraph.Nodes, outside), + Throws.TypeOf() + ); + } + + [Test] + public void IndependentlyConstructedEquivalentProfileIsAcceptedAsTheSameClosedValue() + { + RepositoryCompilationGraph fixedGraph = RepositoryCompilationGraph.CreateFixed(); + BuildProfile equivalent = new("base", Array.Empty()); + List nodes = fixedGraph.Nodes.ToList(); + nodes[0] = new RepositoryGraphNode( + nodes[0].ProjectId, + nodes[0].ProjectPath, + nodes[0].TargetFramework, + equivalent + ); + + Assert.That(RepositoryCompilationGraph.Create(nodes, fixedGraph.ProjectEdges).Nodes, Has.Count.EqualTo(16)); + } + + [Test] + public void UnknownProfileIdAndKnownProfileWithWrongSymbolsAreRejected() + { + RepositoryCompilationGraph fixedGraph = RepositoryCompilationGraph.CreateFixed(); + List nodes = fixedGraph.Nodes.ToList(); + nodes[0] = new RepositoryGraphNode( + nodes[0].ProjectId, + nodes[0].ProjectPath, + nodes[0].TargetFramework, + new BuildProfile("fifth-profile", Array.Empty()) + ); + Assert.That( + () => RepositoryCompilationGraph.Create(nodes, fixedGraph.ProjectEdges), + Throws.TypeOf() + ); + + nodes[0] = new RepositoryGraphNode( + nodes[0].ProjectId, + nodes[0].ProjectPath, + nodes[0].TargetFramework, + new BuildProfile("base", new[] { "SINGLE_THREADED" }) + ); + Assert.That( + () => RepositoryCompilationGraph.Create(nodes, fixedGraph.ProjectEdges), + Throws.TypeOf() + ); + } + + [Test] + public void ExplicitCompatibleTargetSelectionResolvesSyntheticMultiTargetProject() + { + Assert.That( + RepositoryTargetFrameworkSelection.Select(new[] { "netstandard2.0", "net8.0" }, "netstandard2.0"), + Is.EqualTo("netstandard2.0") + ); + Assert.That( + () => RepositoryTargetFrameworkSelection.Select(new[] { "netstandard2.0", "net8.0" }, null), + Throws.TypeOf() + ); + Assert.That( + () => RepositoryTargetFrameworkSelection.Select(new[] { "netstandard2.0", "net8.0" }, "net6.0"), + Throws.TypeOf() + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/RoslynCompilationGraphTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/RoslynCompilationGraphTests.cs new file mode 100644 index 000000000..96ca527ea --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/RoslynCompilationGraphTests.cs @@ -0,0 +1,140 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class RoslynCompilationGraphTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + [Test] + public void CompilationDiagnosticsRetainWarningsButErrorsAreFatal() + { + MetadataReference[] references = { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }; + CSharpCompilation warningCompilation = CSharpCompilation.Create( + "Fixture", + new[] { CSharpSyntaxTree.ParseText("class C { void M() { int unused = 1; } }") }, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + CSharpCompilation promotedWarningCompilation = warningCompilation.WithOptions( + warningCompilation.Options.WithGeneralDiagnosticOption(ReportDiagnostic.Error) + ); + CSharpCompilation errorCompilation = CSharpCompilation.Create( + "BrokenFixture", + new[] { CSharpSyntaxTree.ParseText("class C { MissingType Value; }") }, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + + CompilationDiagnostics warnings = CompilationDiagnostics.From("fixture", warningCompilation.GetDiagnostics()); + CompilationDiagnostics promoted = CompilationDiagnostics.From( + "promoted", + promotedWarningCompilation.GetDiagnostics() + ); + CompilationDiagnostics errors = CompilationDiagnostics.From("broken", errorCompilation.GetDiagnostics()); + + Assert.Multiple(() => + { + Assert.That(warnings.Warnings.Select(item => item.Code), Does.Contain("CS0219")); + Assert.That(warnings.Errors, Is.Empty); + Assert.That(warnings.ThrowIfFatal, Throws.Nothing); + Assert.That(promoted.Errors.Select(item => item.Code), Does.Contain("CS0219")); + Assert.That( + promoted.ThrowIfFatal, + Throws + .TypeOf() + .With.Property(nameof(CompilerInputException.Code)) + .EqualTo("compiler-error") + ); + Assert.That(errors.Errors.Select(item => item.Code), Does.Contain("CS0246")); + Assert.That( + errors.ThrowIfFatal, + Throws + .TypeOf() + .With.Property(nameof(CompilerInputException.Code)) + .EqualTo("compiler-error") + ); + }); + } + + [Test] + public void MalformedExternalMetadataIsAControlledFatalDiagnostic() + { + string malformed = Path.Combine(RepositoryRoot(), "conformance", "constructs.txt"); + + CompilerInputException exception = Assert.Throws(() => + RoslynCompilationGraph.LoadExternalReference(malformed, MetadataReferenceProperties.Assembly) + )!; + + Assert.That(exception.Code, Is.EqualTo("reference-parser-diagnostic")); + } + + [Test] + [CancelAfter(120_000)] + public async Task LiveGraphBuildsAllNodesWithOwnedCompilationReferencesAndNoErrors() + { + string root = RepositoryRoot(); + RepositoryCompilationGraph captured = await new RepositoryCompilationGraphLoader( + new MsBuildProcessRunner() + ).LoadAsync(new RepositoryRoot(root), CancellationToken.None); + + RoslynCompilationGraph graph = RoslynCompilationGraph.Build(captured); + + Assert.Multiple(() => + { + Assert.That(graph.Nodes, Has.Count.EqualTo(16)); + Assert.That(graph.Nodes.Values.All(node => node.Diagnostics.Errors.Count == 0), Is.True); + Assert.That( + graph + .Nodes.Values.Where(node => node.Key.TargetFramework == "net10.0") + .All(node => node.ProbedSdkGeneratorCount > 0), + Is.True + ); + Assert.That( + graph + .Nodes.Values.Where(node => node.Key.TargetFramework == "netstandard2.0") + .All(node => node.ProbedSdkGeneratorCount == 0), + Is.True + ); + Assert.That( + graph + .Nodes.Values.Where(node => node.Key.ProjectId != "machine") + .All(node => node.Compilation.References.Any(reference => reference is CompilationReference)), + Is.True + ); + Assert.That( + graph + .Nodes.Values.SelectMany(node => node.Compilation.References) + .OfType() + .Any(reference => reference.FilePath is not null && IsOwnedOutputPath(reference.FilePath)), + Is.False + ); + }); + } + + private static bool IsOwnedOutputPath(string path) + { + string name = Path.GetFileNameWithoutExtension(path); + return name is ("SIL.Machine" or "SIL.Machine.Morphology.HermitCrab" or "hc" or "hc-conformance") + && path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + .Any(part => + part.Equals("bin", StringComparison.OrdinalIgnoreCase) + || part.Equals("obj", StringComparison.OrdinalIgnoreCase) + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/SemanticCoverageAuditTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/SemanticCoverageAuditTests.cs new file mode 100644 index 000000000..b661903fe --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/SemanticCoverageAuditTests.cs @@ -0,0 +1,385 @@ +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class SemanticCoverageAuditTests +{ + private const string Dtd = ""; + private const string Path = "semantic-catalog.yaml"; + + private static SemanticInventory Inventory() => + SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("fixture.dtd", Dtd)); + + private static string Catalog(string features, string mappings) => + $""" + profile: sil.machine.hc-semantic-catalog/v1 + auditedSourceScopes: [Fixture.Root] + features: + {features} + surfaceMappings: + {mappings} + """; + + private static string SemanticFeatureYaml(string id) => + $""" + - id: {id} + disposition: semantic + analysisCandidateEffect: + behavior: proposes + reads: [shape] + writes: [candidate] + synthesisConfirmationEffect: + behavior: confirms + reads: [candidate] + writes: [word] + finalParseEffect: + behavior: reports + reads: [word] + writes: [analysis] + carriers: [element] + """; + + private static string MetadataFeatureYaml(string id, string reason, string citations) => + $""" + - id: {id} + disposition: metadata + reason: {reason} + citations: {citations} + """; + + private static string MappingsFor(SemanticInventory inventory, string featureId) => + string.Join( + "\n", + inventory.Surfaces.Select(surface => $" - surface: \"{surface.Id}\"\n feature: {featureId}") + ); + + [Test] + public void FullyMappedCatalogPasses() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), MappingsFor(inventory, "root-element")), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(result.Diagnostics, Is.Empty); + Assert.That(result.IsComplete, Is.True); + } + + // The semantic coverage program now audits the grammar format (dtd: surfaces), not the C# + // engine's internals, so an empty auditedSourceScopes list names no gap and must not fail + // the audit on its own. + [Test] + public void EmptyAuditedSourceScopesDoNotFailTheAudit() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), MappingsFor(inventory, "root-element")) + .Replace("auditedSourceScopes: [Fixture.Root]", "auditedSourceScopes: []", StringComparison.Ordinal), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(result.Diagnostics, Is.Empty); + Assert.That(result.IsComplete, Is.True); + } + + [Test] + public void EveryMappingToAnUnclassifiedFeatureIsIncomplete() + { + SemanticInventory inventory = Inventory(); + const string Unclassified = """ + - id: pending + disposition: unclassified + reason: "not reviewed yet" + citations: ["HermitCrabInput.dtd"] + """; + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(Unclassified, MappingsFor(inventory, "pending")), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(result.IsComplete, Is.False); + Assert.That( + result + .Diagnostics.Where(item => item.Code == SemanticCoverageAudit.UnclassifiedMapping) + .Select(item => item.SubjectId), + Is.EqualTo(inventory.Surfaces.Select(surface => surface.Id).OrderBy(id => id, StringComparer.Ordinal)) + ); + } + + [Test] + public void InventoryExecutionDiagnosticsAreAlwaysIncomplete() + { + SemanticInventory basis = Inventory(); + SemanticInventory inventory = basis with + { + Diagnostics = new[] + { + new InventoryDiagnostic( + "unresolved-delegate-dispatch", + "Fixture.Root.Run(System.Boolean)", + "mutable delegate target cannot be closed statically", + "base,SINGLE_THREADED", + "fixture.cs:4:9-4:24" + ), + }, + }; + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), MappingsFor(inventory, "root-element")), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(result.IsComplete, Is.False); + AuditDiagnostic diagnostic = result.Diagnostics.Single(item => item.Code == "unresolved-delegate-dispatch"); + Assert.Multiple(() => + { + Assert.That(diagnostic.SubjectId, Is.EqualTo("Fixture.Root.Run(System.Boolean)")); + Assert.That(diagnostic.Configurations, Is.EqualTo("base,SINGLE_THREADED")); + Assert.That(diagnostic.Location, Is.EqualTo("fixture.cs:4:9-4:24")); + }); + } + + [Test] + public void UnmappedSurfaceIsReported() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog( + SemanticFeatureYaml("root-element"), + $" - surface: \"{inventory.Surfaces[0].Id}\"\n feature: root-element" + ), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(result.IsComplete, Is.False); + Assert.That(result.Diagnostics.Select(item => item.Code), Does.Contain(SemanticCoverageAudit.UnmappedSurface)); + } + + [Test] + public void DuplicateMappingIsReported() + { + SemanticInventory inventory = Inventory(); + string duplicated = $" - surface: \"{inventory.Surfaces[0].Id}\"\n feature: root-element"; + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), $"{MappingsFor(inventory, "root-element")}\n{duplicated}"), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That( + result + .Diagnostics.Where(item => item.Code == SemanticCoverageAudit.DuplicateSurfaceMapping) + .Select(item => item.SubjectId), + Is.EqualTo(new[] { inventory.Surfaces[0].Id }) + ); + } + + [Test] + public void UnknownFeatureIsReported() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), MappingsFor(inventory, "not-declared")), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That(result.Diagnostics.Select(item => item.Code), Does.Contain(SemanticCoverageAudit.UnknownFeature)); + } + + [Test] + public void PatternMappingIsRejectedRatherThanExpanded() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), " - surface: \"dtd:element/*\"\n feature: root-element"), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That( + result + .Diagnostics.Where(item => item.Code == SemanticCoverageAudit.PatternMapping) + .Select(item => item.SubjectId), + Is.EqualTo(new[] { "dtd:element/*" }) + ); + Assert.That( + result.Diagnostics.Select(item => item.Code), + Does.Contain(SemanticCoverageAudit.UnmappedSurface), + "a pattern must not silently cover the surfaces it resembles" + ); + } + + [Test] + public void StaleMappingIsReported() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog( + SemanticFeatureYaml("root-element"), + $"{MappingsFor(inventory, "root-element")}\n - surface: \"dtd:element/Retired\"\n feature: root-element" + ), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That( + result + .Diagnostics.Where(item => item.Code == SemanticCoverageAudit.StaleSurfaceMapping) + .Select(item => item.SubjectId), + Is.EqualTo(new[] { "dtd:element/Retired" }) + ); + } + + [Test] + public void SemanticFeatureMissingAPhaseEffectIsReported() + { + SemanticInventory inventory = Inventory(); + const string Partial = """ + - id: root-element + disposition: semantic + analysisCandidateEffect: + behavior: proposes + reads: [shape] + writes: [candidate] + carriers: [element] + """; + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog(Partial, MappingsFor(inventory, "root-element")), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That( + result + .Diagnostics.Where(item => item.Code == SemanticCoverageAudit.MissingPhaseEffect) + .Select(item => item.Message), + Has.Exactly(2).Items, + "the two absent phase effects must each be named" + ); + } + + [Test] + public void NonSemanticFeatureWithoutReasonOrCitationIsReported() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog missingBoth = SemanticCatalogLoader.Parse( + Catalog(" - id: schema-noise\n disposition: metadata", MappingsFor(inventory, "schema-noise")), + Path + ); + Assert.That( + SemanticCoverageAudit.Run(inventory, missingBoth).Diagnostics.Select(item => item.Code), + Does.Contain(SemanticCoverageAudit.RetirementWithoutReason) + ); + + SemanticCatalog missingCitation = SemanticCatalogLoader.Parse( + Catalog( + MetadataFeatureYaml("schema-noise", "\"declared type only\"", "[]"), + MappingsFor(inventory, "schema-noise") + ), + Path + ); + Assert.That( + SemanticCoverageAudit.Run(inventory, missingCitation).Diagnostics.Select(item => item.Code), + Does.Contain(SemanticCoverageAudit.RetirementWithoutReason) + ); + + SemanticCatalog complete = SemanticCatalogLoader.Parse( + Catalog( + MetadataFeatureYaml("schema-noise", "\"declared type only\"", "[\"HermitCrabInput.dtd\"]"), + MappingsFor(inventory, "schema-noise") + ), + Path + ); + Assert.That(SemanticCoverageAudit.Run(inventory, complete).Diagnostics, Is.Empty); + } + + [Test] + public void DeclaredFeatureWithNoMappingIsReported() + { + SemanticInventory inventory = Inventory(); + SemanticCatalog catalog = SemanticCatalogLoader.Parse( + Catalog( + $"{SemanticFeatureYaml("root-element")}\n{SemanticFeatureYaml("never-used")}", + MappingsFor(inventory, "root-element") + ), + Path + ); + + AuditResult result = SemanticCoverageAudit.Run(inventory, catalog); + + Assert.That( + result + .Diagnostics.Where(item => item.Code == SemanticCoverageAudit.UnusedFeature) + .Select(item => item.SubjectId), + Is.EqualTo(new[] { "never-used" }) + ); + } + + [Test] + public void CatalogLoadingIsStrict() + { + SemanticInventory inventory = Inventory(); + Assert.Throws( + () => + SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("root-element"), MappingsFor(inventory, "root-element")) + .Replace("auditedSourceScopes:", "auditedScopes:", StringComparison.Ordinal), + Path + ), + "unknown root keys are errors" + ); + + Assert.Throws( + () => + SemanticCatalogLoader.Parse( + Catalog(" - id: x\n disposition: not-a-disposition", " - surface: \"a\"\n feature: x"), + Path + ), + "unknown dispositions are errors" + ); + + Assert.Throws( + () => + SemanticCatalogLoader.Parse( + Catalog(SemanticFeatureYaml("dup"), " - surface: \"a\"\n feature: dup") + .Replace( + "profile: sil.machine.hc-semantic-catalog/v1", + "profile: other/v9", + StringComparison.Ordinal + ), + Path + ), + "an unexpected profile is an error" + ); + + Assert.Throws( + () => + SemanticCatalogLoader.Parse( + Catalog( + $"{SemanticFeatureYaml("same")}\n{SemanticFeatureYaml("same")}", + " - surface: \"a\"\n feature: same" + ), + Path + ), + "duplicate feature ids are errors" + ); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/StructuralProofFalsificationTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/StructuralProofFalsificationTests.cs new file mode 100644 index 000000000..39ea8db11 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/StructuralProofFalsificationTests.cs @@ -0,0 +1,398 @@ +#nullable enable +using System.Diagnostics; +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +/// +/// Falsifies the structural-proof contract against the REAL corpus. Every proof kind +/// (, , , +/// , , , +/// ) asserts that an item can NEVER show a counterfactual delta. So an item +/// that is BOTH certified by one of them AND empirically evidenced by an actual engine run is a +/// contradiction in the proof kind, not a tie to break -- see 's +/// Conflicting resolution, which this test exercises against the real corpus rather than a +/// hand-built input. +/// +/// Deliberately does not touch , , or +/// -- those are owned by concurrent work -- and runs its own child +/// hc-conformance.dll --evaluate-mutant process per baseline/swap, one at a time, sequentially, +/// exactly as 's own design intends. Proof-kind certification itself is +/// pure XML analysis (no engine, no process) and costs nothing extra. +/// +[TestFixture] +public sealed class StructuralProofFalsificationTests +{ + private static string RepositoryRoot() + { + string? directory = TestContext.CurrentContext.TestDirectory; + while (directory is not null) + { + if (File.Exists(Path.Combine(directory, "conformance", "constructs.txt"))) + return directory; + directory = Directory.GetParent(directory)?.FullName; + } + + Assert.Fail("Could not locate the repository root."); + return string.Empty; + } + + private enum Certification + { + None, + DisjointDomains, + UnorderedInvariant, + InactiveMember, + PosDisjoint, + TemplateMasked, + NeverFires, + FeatureValueDisjoint, + } + + private sealed record ItemOutcome( + OrderingItem Item, + Certification Certification, + string? ProofReason, + bool Evidenced, + string? DiffWord, + string? Before, + string? After + ); + + // 30s, matching OrderingCounterfactualMeasurementTests: this run's child processes carry no + // in-process fallback, so a genuinely slow (not hung) mutant must not be misreported as a timeout. + private static readonly TimeSpan EvaluationTimeout = TimeSpan.FromSeconds(30); + + [Test] + [Explicit( + "Falsification run, not a CI gate: shells out to hc-conformance.dll once per fixture baseline " + + "plus once per one of the 138 ordering adjacent-swap items (~166 child processes total, " + + "sequential, each independently killable on timeout). Takes on the order of a few minutes; " + + "run manually." + )] + public void CertifiedItemsMustNeverShowAnEmpiricalDelta() + { + string root = RepositoryRoot(); + string dllPath = Path.Combine( + root, + "src", + "SIL.Machine.Morphology.HermitCrab.Conformance", + "bin", + "Debug", + "net10.0", + "hc-conformance.dll" + ); + Assert.That( + File.Exists(dllPath), + Is.True, + $"build the Conformance project first (dotnet build): {dllPath} not found" + ); + + string scratchRoot = + Environment.GetEnvironmentVariable("FALSIFICATION_SCRATCH") + ?? Path.Combine(Path.GetTempPath(), "hc-structural-proof-falsification"); + if (Directory.Exists(scratchRoot)) + Directory.Delete(scratchRoot, recursive: true); + Directory.CreateDirectory(scratchRoot); + + List fixtures = Fixture.DiscoverAll(Path.Combine(root, "conformance")); + var outcomes = new List(); + int totalPairsSeen = 0; + var wallClock = Stopwatch.StartNew(); + + foreach (Fixture fixture in fixtures) + { + XDocument grammar = XDocument.Load(fixture.GrammarPath); + IReadOnlyList items = OrderingGenerator.EnumerateAdjacentPairs(grammar, fixture.Id); + totalPairsSeen += items.Count; + if (items.Count == 0) + continue; + + string[] words = fixture.Words.Words.Select(w => w.Word).ToArray(); + string wordsPath = Path.Combine(scratchRoot, $"words-{Sanitize(fixture.Id)}.txt"); + File.WriteAllLines(wordsPath, words); + + TestContext.Out.WriteLine($"[{fixture.Id}] {items.Count} item(s), {words.Length} word(s)"); + + IReadOnlyList? baseline; + try + { + baseline = RunEvaluateMutant(dllPath, fixture.GrammarPath, wordsPath, EvaluationTimeout); + } + catch (Exception ex) + { + TestContext.Out.WriteLine($" *** BASELINE ITSELF FAILED: {ex.GetType().Name}: {ex.Message} ***"); + baseline = null; + } + + foreach (OrderingItem item in items) + { + Certification certification = Certify(grammar, item, out string? proofReason); + + if (baseline is null) + { + // The fixture's own baseline did not evaluate cleanly. Not evidence either way, so + // it is neither Evidenced nor safe to certify against -- record and move on rather + // than guessing what a comparison against a failed baseline would even mean. + outcomes.Add(new ItemOutcome(item, certification, proofReason, false, null, null, null)); + continue; + } + + OrderingSwap? swap = OrderingGenerator.Swap(grammar, item); + Assert.That(swap, Is.Not.Null, $"item {item.Id} did not match its own fixture's grammar"); + string mutatedPath = Path.Combine(scratchRoot, $"mutant-{Sanitize(item.Id)}.xml"); + swap!.Mutated.Save(mutatedPath); + + try + { + IReadOnlyList mutated = RunEvaluateMutant( + dllPath, + mutatedPath, + wordsPath, + EvaluationTimeout + ); + + int diffIndex = -1; + for (int i = 0; i < words.Length && i < baseline.Count && i < mutated.Count; i++) + { + if (baseline[i] != mutated[i]) + { + diffIndex = i; + break; + } + } + + bool countMismatch = baseline.Count != mutated.Count; + bool evidenced = diffIndex >= 0 || countMismatch; + outcomes.Add( + new ItemOutcome( + item, + certification, + proofReason, + evidenced, + diffIndex >= 0 ? words[diffIndex] : (countMismatch ? "" : null), + diffIndex >= 0 ? baseline[diffIndex] : null, + diffIndex >= 0 ? mutated[diffIndex] : null + ) + ); + } + catch (TimeoutException tex) + { + TestContext.Out.WriteLine($" *** TIMEOUT *** {item.Id}: {tex.Message}"); + // A timeout is "I could not look", never evidence and never safe to treat as + // matching a proof's claim either -- record as unresolved (not evidenced). + outcomes.Add(new ItemOutcome(item, certification, proofReason, false, null, null, null)); + } + catch (Exception ex) + { + // A load failure IS a counterfactual delta and must count as evidenced here, exactly + // as CounterfactualVerdict.RequiredByDtd/RequiredByLoader do for a Surface item. + TestContext.Out.WriteLine($" *** LOAD FAILURE *** {item.Id}: {ex.GetType().Name}: {ex.Message}"); + outcomes.Add( + new ItemOutcome( + item, + certification, + proofReason, + true, + "", + null, + $"{ex.GetType().Name}: {ex.Message}" + ) + ); + } + } + } + + wallClock.Stop(); + Assert.That( + totalPairsSeen, + Is.EqualTo(138), + "the corpus-wide pair count must match the design doc's measured figure" + ); + Assert.That(outcomes, Has.Count.EqualTo(138)); + + WriteTally(outcomes, wallClock.Elapsed); + + // The headline check. A structural proof claims an item can NEVER show a delta; empirical + // evidence that it just did is a contradiction in the proof kind, not a tie to break. + ItemOutcome[] contradictions = outcomes + .Where(o => o.Certification != Certification.None && o.Evidenced) + .ToArray(); + if (contradictions.Length != 0) + { + string detail = string.Join( + "\n", + contradictions.Select(o => + $" {o.Item.Id}\n" + + $" certified by: {o.Certification} ({o.ProofReason})\n" + + $" differing word: '{o.DiffWord}': {o.Before} -> {o.After}" + ) + ); + Assert.Fail( + $"{contradictions.Length} item(s) are BOTH structurally certified AND empirically evidenced -- " + + $"the proof kind is UNSOUND on the real corpus:\n{detail}" + ); + } + } + + /// + /// Certifies using the SAME fallback order + /// uses, so this test's certification matches what + /// the real pipeline would record rather than a re-invented ordering. + /// + private static Certification Certify(XDocument grammar, OrderingItem item, out string? reason) + { + Proof? disjointDomains = OrderingProofs.TryBuild(grammar, item); + if (disjointDomains is not null) + { + reason = disjointDomains.Check; + return Certification.DisjointDomains; + } + + Proof? unorderedInvariant = UnorderedInvariantProofs.TryBuild(grammar, item); + if (unorderedInvariant is not null) + { + reason = unorderedInvariant.Check; + return Certification.UnorderedInvariant; + } + + Proof? inactiveMember = InactiveMemberProofs.TryBuild(grammar, item); + if (inactiveMember is not null) + { + reason = inactiveMember.Check; + return Certification.InactiveMember; + } + + Proof? posDisjoint = PosDisjointProofs.TryBuild(grammar, item); + if (posDisjoint is not null) + { + reason = posDisjoint.Check; + return Certification.PosDisjoint; + } + + Proof? templateMasked = TemplateMaskedProofs.TryBuild(grammar, item); + if (templateMasked is not null) + { + reason = templateMasked.Check; + return Certification.TemplateMasked; + } + + Proof? neverFires = NeverFiresProofs.TryBuild(grammar, item); + if (neverFires is not null) + { + reason = neverFires.Check; + return Certification.NeverFires; + } + + Proof? featureValueDisjoint = FeatureValueDisjointProofs.TryBuild(grammar, item); + if (featureValueDisjoint is not null) + { + reason = featureValueDisjoint.Check; + return Certification.FeatureValueDisjoint; + } + + reason = null; + return Certification.None; + } + + private static string Sanitize(string id) + { + char[] chars = id.ToCharArray(); + for (int i = 0; i < chars.Length; i++) + { + if (!char.IsLetterOrDigit(chars[i])) + chars[i] = '_'; + } + return new string(chars); + } + + /// + /// Runs one --evaluate-mutant child process: DOTNET_PROCESSOR_COUNT=1 dotnet + /// hc-conformance.dll --evaluate-mutant <grammar> <words>, one word per line, never + /// words.yaml. A separate implementation from CounterfactualGate's private + /// OutcomesWithTimeout (that file is owned by concurrent work) but the same shape: drain both + /// pipes before waiting so a full one never deadlocks the wait, kill the whole tree on timeout. + /// + private static IReadOnlyList RunEvaluateMutant( + string dllPath, + string grammarPath, + string wordsPath, + TimeSpan timeout + ) + { + var start = new ProcessStartInfo + { + FileName = "dotnet", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + start.ArgumentList.Add(dllPath); + start.ArgumentList.Add("--evaluate-mutant"); + start.ArgumentList.Add(grammarPath); + start.ArgumentList.Add(wordsPath); + start.EnvironmentVariables["DOTNET_PROCESSOR_COUNT"] = "1"; + + ChildProcessHarness.Result result; + try + { + result = ChildProcessHarness.Run(start, CancellationToken.None, backstop: timeout); + } + catch (TimeoutException) + { + throw new TimeoutException($"'{grammarPath}' did not complete within {timeout.TotalSeconds:0}s"); + } + + if (result.ExitCode != 0) + { + string error = result.StandardError.Trim(); + throw new InvalidOperationException(error.Length != 0 ? error : $"exit code {result.ExitCode}"); + } + + return result + .StandardOutput.Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.TrimEnd('\r')) + .ToArray(); + } + + private static void WriteTally(List outcomes, TimeSpan wallClock) + { + TestContext.Out.WriteLine(); + TestContext.Out.WriteLine("STRUCTURAL PROOF FALSIFICATION -- 138-ITEM TALLY"); + TestContext.Out.WriteLine("=================================================="); + TestContext.Out.WriteLine($"wall clock: {wallClock.TotalSeconds:0.0}s"); + TestContext.Out.WriteLine(); + + int evidenced = outcomes.Count(o => o.Evidenced); + TestContext.Out.WriteLine($"evidenced (real delta from the engine): {evidenced}"); + foreach (Certification kind in Enum.GetValues()) + { + if (kind == Certification.None) + continue; + int count = outcomes.Count(o => o.Certification == kind); + TestContext.Out.WriteLine($"certified by {kind}: {count}"); + } + int uncertifiedAndUnevidenced = outcomes.Count(o => o.Certification == Certification.None && !o.Evidenced); + TestContext.Out.WriteLine($"open (neither evidenced nor certified): {uncertifiedAndUnevidenced}"); + TestContext.Out.WriteLine(); + + TestContext.Out.WriteLine("evidenced items:"); + foreach (ItemOutcome o in outcomes.Where(o => o.Evidenced).OrderBy(o => o.Item.Id, StringComparer.Ordinal)) + TestContext.Out.WriteLine($" {o.Item.Id} '{o.DiffWord}': {o.Before} -> {o.After}"); + TestContext.Out.WriteLine(); + + TestContext.Out.WriteLine("certified items (by kind):"); + foreach ( + ItemOutcome o in outcomes + .Where(o => o.Certification != Certification.None) + .OrderBy(o => o.Certification) + .ThenBy(o => o.Item.Id, StringComparer.Ordinal) + ) + { + TestContext.Out.WriteLine($" [{o.Certification}] {o.Item.Id}"); + } + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/TemplateMaskedProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/TemplateMaskedProofsTests.cs new file mode 100644 index 000000000..f0d46f6ec --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/TemplateMaskedProofsTests.cs @@ -0,0 +1,209 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class TemplateMaskedProofsTests +{ + // Three slots, all of whose rules are members of the unordered Stratum's own morphologicalRules list + // -- the shape that certifies both s1~s2 and s2~s3. + private const string FullyMaskedGrammar = """ + + S + tmpl + s1 + s2 + s3 + + + + """; + + private const string LinearGrammar = """ + + S + tmpl + s1 + s2 + s3 + + + + """; + + private const string AbsentOrderGrammar = """ + + S + tmpl + s1 + s2 + s3 + + + + """; + + // s3's rule m3 is NOT in the cascade -- the whole template is not reproducible, so even the s1~s2 + // pair (which never touches m3) must be rejected: precondition (c) is about every Slot, not the pair. + private const string OtherSlotEscapesCascadeGrammar = """ + + S + tmpl + s1 + s2 + s3 + + + + """; + + [Test] + public void BuildsAProofForAnAdjacentSlotPairFullyReproducedByTheCascade() + { + XDocument grammar = XDocument.Parse(FullyMaskedGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "s1" && i.MemberB == "s2"); + + Proof? proof = TemplateMaskedProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(TemplateMaskedProofs.Kind)); + Assert.That(proof.Check, Does.Contain("unordered")); + Assert.That(TemplateMaskedProofs.Verify(grammar, "fx", proof), Is.True); + } + + [Test] + public void BuildsAProofForTheOtherAdjacentSlotPairInTheSameTemplate() + { + XDocument grammar = XDocument.Parse(FullyMaskedGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "s2" && i.MemberB == "s3"); + + Assert.That(TemplateMaskedProofs.TryBuild(grammar, item), Is.Not.Null); + } + + // Guard: a linear stratum must never license this proof kind -- linear order is exactly the case + // where slot position DOES matter. + [Test] + public void RefusesWhenTheOwningStratumIsLinear() + { + XDocument grammar = XDocument.Parse(LinearGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "s1" && i.MemberB == "s2"); + + Assert.That(TemplateMaskedProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: an absent morphologicalRuleOrder resolves to the DTD default "linear", never treated as unordered. + [Test] + public void RefusesWhenMorphologicalRuleOrderIsAbsent() + { + XDocument grammar = XDocument.Parse(AbsentOrderGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "s1" && i.MemberB == "s2"); + + Assert.That(TemplateMaskedProofs.TryBuild(grammar, item), Is.Null); + } + + // The precondition-(c) case: a rule referenced by a slot OUTSIDE the swapped pair is missing from the + // cascade, so the whole template is a genuinely distinct derivation path and the pair itself -- which + // never references the missing rule -- must still be rejected. + [Test] + public void RefusesWhenAnyOtherSlotInTheTemplateReferencesARuleMissingFromTheCascade() + { + XDocument grammar = XDocument.Parse(OtherSlotEscapesCascadeGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.MemberA == "s1" && i.MemberB == "s2"); + + Assert.That(TemplateMaskedProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: this kind never fires for a non-Slot item, even on an unordered Stratum whose morphologicalRules + // pair would satisfy UnorderedInvariantProofs. + [Test] + public void RefusesForAStratumMorphologicalRulesPair() + { + XDocument grammar = XDocument.Parse( + """ + + S + + """ + ); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(TemplateMaskedProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: a Slot with no morphologicalRules attribute at all cannot be verified reproducible -- fail + // closed rather than treating "no attribute" as "no rules to worry about". + [Test] + public void RefusesWhenASlotDeclaresNoMorphologicalRulesAttribute() + { + XDocument grammar = XDocument.Parse( + """ + + S + tmpl + s1 + s2 + + + + """ + ); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.Kind == OrderingListKind.AffixTemplateSlots); + + Assert.That(TemplateMaskedProofs.TryBuild(grammar, item), Is.Null); + } + + // The core rejection scenario the task asks for: a proof built while the stratum was unordered must be + // REJECTED once the stratum is flipped to linear, because Verify recomputes rather than trusts. + [Test] + public void VerifyRejectsAProofOnceTheStratumIsFlippedToLinear() + { + XDocument original = XDocument.Parse(FullyMaskedGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(original, "fx") + .Single(i => i.MemberA == "s1" && i.MemberB == "s2"); + Proof proof = TemplateMaskedProofs.TryBuild(original, item)!; + + XDocument flipped = XDocument.Parse(LinearGrammar); + + Assert.That(TemplateMaskedProofs.Verify(flipped, "fx", proof), Is.False); + } + + // The second stale-proof scenario: a proof built while every slot's rules were in the cascade must be + // REJECTED once one of those rules is removed from the Stratum's morphologicalRules list. + [Test] + public void VerifyRejectsAProofOnceARuleIsRemovedFromTheCascade() + { + XDocument original = XDocument.Parse(FullyMaskedGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(original, "fx") + .Single(i => i.MemberA == "s1" && i.MemberB == "s2"); + Proof proof = TemplateMaskedProofs.TryBuild(original, item)!; + + XDocument shrunkCascade = XDocument.Parse(OtherSlotEscapesCascadeGrammar); + + Assert.That(TemplateMaskedProofs.Verify(shrunkCascade, "fx", proof), Is.False); + } + + [Test] + public void VerifyRejectsAStaleProofWhoseItemNoLongerExists() + { + XDocument grammar = XDocument.Parse(FullyMaskedGrammar); + var stale = new Proof("ordering:fx/slots/gone~alsoGone", TemplateMaskedProofs.Kind, "stale"); + + Assert.That(TemplateMaskedProofs.Verify(grammar, "fx", stale), Is.False); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/TraceEvidenceTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/TraceEvidenceTests.cs new file mode 100644 index 000000000..30948a9a5 --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/TraceEvidenceTests.cs @@ -0,0 +1,134 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class TraceEvidenceTests +{ + private const string Dtd = ""; + + private static SemanticInventory InventoryWith(params string[] surfaceIds) + { + SemanticInventory basis = SemanticCoverageInventory.Generate(SemanticCoverageSourceSet.FromDtd("f.dtd", Dtd)); + return basis with + { + Surfaces = surfaceIds.Select(id => new InventorySurface(id, "enum", id, null, "f.dtd")).ToArray(), + }; + } + + private static XDocument Grammar(string ruleAttributes) => + XDocument.Parse( + $"" + + $"n" + + $"" + ); + + [Test] + public void AnAttributeOnAFiringRuleIsTraceEvidence() + { + SemanticInventory inventory = InventoryWith("dtd:enum/MorphologicalRule/blockable/true"); + + IReadOnlyList graded = TraceEvidence.Grade( + "fx", + Grammar("blockable=\"true\""), + inventory, + new[] { "mrLive" }, + hasVerifiedParse: true, + Array.Empty() + ); + + Assert.That(graded.Single().Strength, Is.EqualTo(EvidenceStrength.Trace)); + } + + // The whole point of trace grading: a rule can be declared, load fine, and never run. + [Test] + public void AnAttributeOnARuleThatNeverFiredIsOnlyPresence() + { + SemanticInventory inventory = InventoryWith("dtd:enum/MorphologicalRule/blockable/true"); + + IReadOnlyList graded = TraceEvidence.Grade( + "fx", + Grammar("blockable=\"true\""), + inventory, + Array.Empty(), + hasVerifiedParse: true, + Array.Empty() + ); + + Assert.That(graded.Single().Strength, Is.EqualTo(EvidenceStrength.Presence)); + Assert.That(graded.Single().Detail, Does.Contain("mrLive")); + } + + [Test] + public void ADeactivatedDeclarationNeedsAWordThatNamesItToCountAsANegativeControl() + { + SemanticInventory inventory = InventoryWith("dtd:enum/MorphologicalRule/isActive/no"); + XDocument grammar = Grammar("isActive=\"no\""); + + Assert.That( + TraceEvidence + .Grade("fx", grammar, inventory, Array.Empty(), true, new[] { "mrLive" }) + .Single() + .Strength, + Is.EqualTo(EvidenceStrength.NegativeControl) + ); + Assert.That( + TraceEvidence + .Grade("fx", grammar, inventory, Array.Empty(), true, Array.Empty()) + .Single() + .Strength, + Is.EqualTo(EvidenceStrength.Presence), + "a decoy no word names is not evidence" + ); + } + + [Test] + public void AFixtureWithNoVerifiedParseCannotReachStructuralStrength() + { + SemanticInventory inventory = InventoryWith("dtd:enum/Stratum/cyclicity/cyclic"); + var grammar = XDocument.Parse("n"); + + Assert.That( + TraceEvidence + .Grade("fx", grammar, inventory, Array.Empty(), hasVerifiedParse: false, Array.Empty()) + .Single() + .Strength, + Is.EqualTo(EvidenceStrength.Presence) + ); + Assert.That( + TraceEvidence + .Grade("fx", grammar, inventory, Array.Empty(), hasVerifiedParse: true, Array.Empty()) + .Single() + .Strength, + Is.EqualTo(EvidenceStrength.Structural) + ); + } + + [Test] + public void OwningRuleIsTheNearestIdentifiedRuleAncestor() + { + var grammar = XDocument.Parse( + "" + + "" + ); + XElement output = grammar.Descendants("MorphologicalOutput").Single(); + + // MorphologicalSubrule ids are not fired-rule ids, so attribution walks past them. + Assert.That(TraceEvidence.OwningRuleId(output), Is.EqualTo("outer")); + Assert.That(TraceEvidence.DeactivatedAncestor(output), Is.Null); + } + + [Test] + public void DeactivationIsInheritedByDescendants() + { + var grammar = XDocument.Parse( + "" + + "x" + ); + XElement shape = grammar.Descendants("PhoneticShape").Single(); + + Assert.That(TraceEvidence.DeactivatedAncestor(shape), Is.EqualTo("e")); + } +} diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/UnorderedInvariantProofsTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/UnorderedInvariantProofsTests.cs new file mode 100644 index 000000000..a4f5268ae --- /dev/null +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/SemanticCoverage/UnorderedInvariantProofsTests.cs @@ -0,0 +1,105 @@ +using System.Xml.Linq; +using NUnit.Framework; +using SIL.Machine.Morphology.HermitCrab.Conformance.SemanticCoverage; + +namespace SIL.Machine.Morphology.HermitCrab; + +[TestFixture] +public sealed class UnorderedInvariantProofsTests +{ + private const string UnorderedStratumGrammar = """ + + + S + + + """; + + private const string LinearStratumGrammar = """ + + S + + """; + + private const string DefaultOrderStratumGrammar = """ + + S + + """; + + [Test] + public void BuildsAProofForAMorphologicalRulesPairOnAnUnorderedStratum() + { + XDocument grammar = XDocument.Parse(UnorderedStratumGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.Kind == OrderingListKind.StratumMorphologicalRules); + + Proof? proof = UnorderedInvariantProofs.TryBuild(grammar, item); + + Assert.That(proof, Is.Not.Null); + Assert.That(proof!.Kind, Is.EqualTo(UnorderedInvariantProofs.Kind)); + Assert.That(proof.Check, Does.Contain("unordered")); + Assert.That(UnorderedInvariantProofs.Verify(grammar, "fx", proof), Is.True); + } + + // Guard: the precondition (unordered) does not hold for a phonologicalRules pair on the SAME + // unordered stratum -- StratumPhonologicalRules is compiled as an unconditional LinearRuleCascade + // regardless of morphologicalRuleOrder, so this kind must never license a proof for it. + [Test] + public void RefusesAPhonologicalRulesPairEvenOnAnUnorderedStratum() + { + XDocument grammar = XDocument.Parse(UnorderedStratumGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(grammar, "fx") + .Single(i => i.Kind == OrderingListKind.StratumPhonologicalRules); + + Assert.That(UnorderedInvariantProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: a linear stratum must never license this proof kind -- linear order is exactly the case + // where adjacent position DOES matter. + [Test] + public void RefusesAMorphologicalRulesPairOnALinearStratum() + { + XDocument grammar = XDocument.Parse(LinearStratumGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(UnorderedInvariantProofs.TryBuild(grammar, item), Is.Null); + } + + // Guard: an absent morphologicalRuleOrder resolves to the DTD default "linear", never treated as unordered. + [Test] + public void RefusesAMorphologicalRulesPairWhenOrderIsAbsent() + { + XDocument grammar = XDocument.Parse(DefaultOrderStratumGrammar); + OrderingItem item = OrderingGenerator.EnumerateAdjacentPairs(grammar, "fx").Single(); + + Assert.That(UnorderedInvariantProofs.TryBuild(grammar, item), Is.Null); + } + + // The core rejection scenario the task asks for: a proof built while the stratum was unordered must + // be REJECTED once the stratum is flipped to linear, because Verify recomputes rather than trusts. + [Test] + public void VerifyRejectsAProofOnceTheStratumIsFlippedToLinear() + { + XDocument original = XDocument.Parse(UnorderedStratumGrammar); + OrderingItem item = OrderingGenerator + .EnumerateAdjacentPairs(original, "fx") + .Single(i => i.Kind == OrderingListKind.StratumMorphologicalRules); + Proof proof = UnorderedInvariantProofs.TryBuild(original, item)!; + + XDocument flipped = XDocument.Parse(UnorderedStratumGrammar.Replace("unordered", "linear")); + + Assert.That(UnorderedInvariantProofs.Verify(flipped, "fx", proof), Is.False); + } + + [Test] + public void VerifyRejectsAStaleProofWhoseItemNoLongerExists() + { + XDocument grammar = XDocument.Parse(UnorderedStratumGrammar); + var stale = new Proof("ordering:fx/morphologicalRules/gone~alsoGone", UnorderedInvariantProofs.Kind, "stale"); + + Assert.That(UnorderedInvariantProofs.Verify(grammar, "fx", stale), Is.False); + } +}