Skip to content

Add 4 construct rows for characteristics with no coverage id - #465

Merged
johnml1135 merged 1 commit into
conformance-frameworkfrom
g9-add-missing-construct-rows
Jul 28, 2026
Merged

Add 4 construct rows for characteristics with no coverage id#465
johnml1135 merged 1 commit into
conformance-frameworkfrom
g9-add-missing-construct-rows

Conversation

@johnml1135

@johnml1135 johnml1135 commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • PanGloss's pg-foma::conformance_coverage cross-check maps every CharacteristicKind to one or more constructs.txt identifiers. Four characteristics had no corresponding row at all, so no fixture could ever be written to exercise them by name: rewrite-rule directionality (left-to-right / right-to-left), phonological subrule-level MPR/POS gating, and stratification across more than one CharacterDefinitionTable.
  • Adds one new row per characteristic, next to the closest existing related rows, in the file's existing plain-line style. No renumbering or reordering of existing rows.

Detail

  • RewriteRule direction (Dir): left-to-right / RewriteRule direction (Dir): right-to-left — the existing RewriteRule Iterative/RewriteRule Simultaneous rows tag application order, not directionality; no row named direction as its own phenomenon.
  • RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level — the existing MPR features/groups row is morphological MprGroup territory (MprGroupAppend/MprGroupOverwrite); this is the distinct phonological-subrule gate.
  • CharacterDefinitionTable: more than one table, one per stratum — the two existing CharacterDefinitionTable rows are about segmentation/pattern constructs within one table, not about multiple tables potentially disagreeing across strata.

Test plan

  • Format matches the file's existing convention (one construct per line, no header changes)
  • CI (if any) on this branch

🤖 Generated with Claude Code


This change is Reviewable

conformance_coverage.rs's mapping (machine-consuming PanGloss repo) found
4 CharacteristicKind values -- rewrite direction (LeftToRightRewrite/
RightToLeftRewrite), phonological subrule-level MPR/POS gating
(SubruleGating), and multi-CharacterDefinitionTable stratification
(MultiTable) -- with no constructs.txt row distinctly tagging them, so no
fixture could ever be written to exercise them by name. The existing
"RewriteRule Iterative/Simultaneous" rows tag application-order, not
directionality; "MPR features/groups" is morphological MprGroup territory,
not phonological subrule gating; the two existing CharacterDefinitionTable
rows are about segmentation/pattern constructs within one table, not about
multiple tables disagreeing across strata.

Add one row per characteristic so each can be evidenced independently.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.34%. Comparing base (dd8f95c) to head (4560e9e).

Additional details and impacted files
@@                  Coverage Diff                   @@
##           conformance-framework     #465   +/-   ##
======================================================
  Coverage                  73.34%   73.34%           
======================================================
  Files                        443      443           
  Lines                      37214    37214           
  Branches                    5110     5110           
======================================================
  Hits                       27294    27294           
  Misses                      8798     8798           
  Partials                    1122     1122           

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

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

johnml1135 added a commit to sillsdev/PanGloss that referenced this pull request Jul 27, 2026
… citation liveness

G8 -- widen the conformance cross-check from the 6 Proven kinds to all 20.

`supported_kinds()` now returns every `CharacteristicKind`. A new
`EvidenceRequirement` + `evidence_requirement_for(Disposition)` encode the
honest per-disposition rule from ADR 0001: Proven/ConfigPredicate/ConfirmOnly
need a passing analysis fixture (with `disposition` now carried on every
`CoverageReportRow` so a build-breaking flip can stage Proven first), while
FailClosed needs a REFUSAL witness instead -- a refused construct can never
have a passing analysis fixture, so demanding one would be incoherent.
`supported_coverage_report`/`supported_uncovered` take the two evidence sets as
separate parameters so they cannot cross-contaminate.

This fixed a real overclaim, not just a scoping gap. `build_ledger` previously
graded every row -- FailClosed included -- against the passing-fixture set
alone. Because MprGroupOverwrite (FailClosed) and MprGroupAppend (ConfirmOnly)
share the construct id "MPR features/groups", MprGroupOverwrite could report
Covered purely because its SIBLING's passing fixture tagged the same shared id,
without the refusal ever being exercised. Pinned by
`fail_closed_row_is_covered_via_refusal_witness_regardless_of_passing_set`.

Computed flip-blocker list (still ADVISORY -- the flip is a separate step):
20 rows, 16 Covered, 4 Uncovered, 0 Unmappable.
  Proven (hard error on flip): LeftToRightRewrite, SubruleGating
  ConfigPredicate/ConfirmOnly (stageable):  RightToLeftRewrite, MultiTable
  FailClosed: none -- MprGroupOverwrite has its witness
Those 4 are exactly the newly-mapped G9 characteristics: the mapping now
exists, but no fixture yet tags the new construct ids.

G9 -- align the two construct vocabularies.

Added the 4 missing rows to machine/conformance/constructs.txt (rewrite
direction L-to-R and R-to-L, subrule-level required/excluded POS-or-MPR gating,
multiple character-definition tables) and mapped them in `construct_ids_for`,
taking Unmappable to zero. Upstream PR: sillsdev/machine#465. Submodule
pointer bumped to that branch tip (4560e9e2, not yet merged upstream).

The 12 orphan constructs.txt rows get no invented characteristics -- they are
documented one-by-one with a reason in a new ORPHAN_CONSTRUCT_ROWS const
(output-action primitives, template slots, boundary markers, guesser, disjunctive
allomorph free variation, stem names, syntactic feature agreement,
alpha-variables, compounding/rule constraint variants, and tracing, which is an
engine debug feature with no capability basis).

Golden regenerated from the test's own computation, never hand-edited.

NEW -- citation liveness (tests/coverage_citation_liveness.rs, mine, on review).

G8 makes a FailClosed row's Covered verdict depend ENTIRELY on a hand-written
citation string, and nothing verified that string pointed at anything real. A
citation naming a deleted file or a renamed #[test] would report Covered
forever -- exactly the overclaim ADR 0001 exists to forbid. Three gates now
check that every ledger citation's `tests/<file>.rs` paths exist, that every
`::<test_fn>` reference resolves to a real `fn`, and (strictest, for the one
disposition where the citation IS the evidence) that a FailClosed row's refusal
witness resolves to an actual `#[test]` in one of its own cited files.

Proven non-vacuous both ways before commit: renaming the cited fn fails
`every_ledger_citation_names_a_test_fn_that_exists` (1 of 30 references);
renaming the cited file fails both the file gate and the FailClosed gate. Each
gate also asserts it scanned a non-zero number of citations, so a future
citation-format change fails loudly instead of going silently vacuous. It does
NOT check that a cited test proves what its `note` claims -- that stays a human
review obligation, stated as such.

Also: dropped a real-word/language-noun reference from
conformance-staging/edge-cases/template-category-sharing (grammar.xml comment,
STAGING.md prose, words.yaml note); the remaining prose references in that
fixture are queued for the part-B delanguaging sweep. And corrected a doc line
in coverage_ledger.rs that still described `supported_kinds` as the Proven-only
subset, which G8 makes false.

Verification: cargo test -p pg-foma 328 passed / 0 failed / 13 ignored, plus
every integration binary green; cargo clippy -p pg-foma --all-targets clean on
every touched file; openspec validate --all --strict 27 passed;
run-conformance.sh --skip-build at the 15+1 baseline; `pangloss coverage`
reports 0 Unmappable. The cross-check is deliberately NOT yet build-breaking.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
johnml1135 added a commit to sillsdev/PanGloss that referenced this pull request Jul 27, 2026
…whole class

The 4 rows blocking the build-breaking flip were not missing evidence -- their
evidence was being thrown away by a string mismatch.

`conformance_coverage::construct_ids_for` maps each CharacteristicKind to
`constructs.txt` row-id strings and credits coverage by byte-for-byte set
match. Three staged fixtures wrote the CHARACTERISTIC NAME instead:

  subrule-morphosyntactic-gating              "SubruleGating"
    -> "RewriteSubruleDef gating: required/excluded POS or MPR at the subrule level"
  right-to-left-bounded-quantifier-rewrite    "RightToLeftRewrite"
    -> "RewriteRule direction (Dir): right-to-left"
  bistratal-overlapping-segment-representation "MultiTable"
    -> "CharacterDefinitionTable: more than one table, one per stratum"

None matched a row id, so those tags contributed exactly ZERO coverage --
silently. The fixtures looked right, nothing failed, and the rows just sat
Uncovered. `constructs.txt`'s own header explains how: the harness treats an
unknown `exercises:` value as "a soft warning... never a hard error."

LeftToRightRewrite had no tag anywhere. Now tagged on
mpr-gated-exception's `menulik` parse, chosen because BOTH its rewrite rules
genuinely fire (nasal assimilation then obstruent deletion, per the fixture's
own pre-existing derivation note) rather than being present-but-unused, and
because `load_rewrite_rule` gives a rule with no `multipleApplicationOrder`
attribute `Dir::LeftToRight` by default. Verified against the fixture's own
documented derivation, not assumed.

Only tag strings changed -- no signature, no `parses:`, no ground truth. Each
fixture's STAGING.md gained a "Coverage-tag correction" section; a stale line
in subrule-morphosyntactic-gating's STAGING.md saying the row had not landed
yet is corrected (it landed in sillsdev/machine#465).

NEW GATE, the actual deliverable: tests/exercises_tag_liveness.rs asserts every
`exercises:` tag (per-word and per-parse) across BOTH discovery roots is a
literal constructs.txt line, reports every offender at once with fixture + word
+ signature + offending string, and asserts it scanned a non-zero number of
tags so a format change fails loudly instead of going vacuous. It reuses the
existing shared `pg_conformance_fixtures::discover` rather than walking either
root a second time. Proven non-vacuous: reverting one tag to "MultiTable" fails
with the exact fixture/word/tag named; reverting the corruption passes again.
It deliberately does NOT check that a tag is the RIGHT tag -- that a fixture
genuinely exercises what it claims stays a human-authoring obligation, stated
as such.

Cross-check moves 20 rows / 16 Covered / 4 Uncovered / 0 Unmappable
-> 20 / 20 Covered / 0 Uncovered / 0 Unmappable. Independently re-run and
confirmed here, not taken on report.

NOT flipping the cross-check to build-breaking in this commit -- see the
shared-construct-id analysis landing next for why that is still one step away.

Verification: cargo test -p pg-foma green including the three coverage gates;
cargo clippy -p pg-foma --all-targets clean on the new file; run-conformance.sh
--skip-build at the 15+1 baseline; openspec validate --all --strict 27 passed.
One known workspace failure, pg-cli's trace_render golden, is from concurrent
in-flight tracing work in other crates and is not touched or caused by this
change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
johnml1135 added a commit to sillsdev/PanGloss that referenced this pull request Jul 27, 2026
…aking (the finish line)

tasks.md 6.2 / design.md D7 step 7: "This is the finish line, not a follow-on
cleanup step." Done.

The gate now asserts zero Uncovered AND zero Unmappable rows across all 20
CharacteristicKinds, each graded against its own EvidenceRequirement --
PassingFixture for Proven/ConfigPredicate/ConfirmOnly, RefusalWitness for
FailClosed (nothing compiles for a refused construct, so demanding a passing
analysis fixture for one would be incoherent).

Four fixes had to land first. I did not flip when the count first read 20/20,
because a green build-breaking gate that can silently start lying is worse than
an advisory report -- the green light is what gets cited:

  G9    Unmappable had to reach zero; 4 constructs.txt rows did not exist
        (sillsdev/machine#465)
  G8    the check had to cover all 20 rows, not the 6 Proven ones, and had to
        stop grading FailClosed rows against the passing-fixture set -- which
        let MprGroupOverwrite report Covered off a sibling's shared construct
        id with the refusal never exercised
  tags  exercises_tag_liveness.rs -- three fixtures tagged CHARACTERISTIC NAMES
        where a row id is required, so their evidence counted for nothing; an
        unknown tag is now a hard error, not constructs.txt's documented "soft
        warning"
  ids   structural_witness_gate.rs -- four row ids are each mapped by two
        characteristics, so the finer could report Covered on the coarser
        sibling's evidence; three now have a mechanized grammar-shape witness
        and the fourth pair is excluded by derivation

Plus coverage_citation_liveness.rs, which stops the RefusalWitness citations --
the one place a Covered verdict rests on a hand-written string -- from becoming
dangling pointers.

Failure messages are per-disposition rather than one undifferentiated count, so
a failure says what KIND of evidence is missing and therefore what would fix it,
and each names the two likely causes (a fixture whose words started failing, or
a tag that is not a literal row id). The full report still prints on every run.

Non-vacuity, proven not assumed: the entry assertion now requires the report to
enumerate EVERY CharacteristicKind, so a short report cannot make the gate pass
trivially. And sabotaging one Proven row's tag produces exactly:
  COVERAGE REGRESSION (Proven): [SubruleGating] are admission-filtered
  unconditionally yet have no passing conformance fixture tagging their
  construct id.
Reverted, verified clean by git diff, and all four coverage gates re-run green
(1 + 3 + 1 + 2 passed).

Stated in the code, not just here -- what this gate does NOT assert: that a
fixture tags the RIGHT construct (a human-authoring risk no string or shape
check closes in general); that Covered means Admit (ten rows are
ConfigPredicate, three ConfirmOnly -- D1 keeps ConfirmOnly -> Admit a separate
optional track); and that every CONFIGURATION inside a covered row is closed.
Row-level coverage and configuration-level completeness are different claims and
D7 requires both -- the open splits are recorded in
docs/conformance/circumfix-structural-composite-census.md,
needs-decision-resolutions.md, and multitable-shared-representation-design.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
johnml1135 added a commit to sillsdev/PanGloss that referenced this pull request Jul 27, 2026
….1/6.0/6.2 done

Audit 3a gains a "Resolved 2026-07-25 (later the same day)" block superseding the
older entries below it, for the four gaps that landed plus the overclaim found
while building G3.

tasks.md corrections, all of these were stale rather than open:
  2.1/2.2  constructs.txt rows -> sillsdev/machine#465, submodule pointer bumped.
           Recorded honestly that the PR is OPEN, not merged, so the pointer
           references a branch tip and must be re-pointed on merge.
  3.1      G8's widening, noting it fixed a real overclaim (MprGroupOverwrite
           Covered off a sibling's shared id) rather than only widening scope.
  6.0      structural witness gate, incl. the honest detail that narrowing the
           circumfix predicate to allomorph-0-only still passed, so census C1's
           preemption does not affect qualification today.
  6.2      THE FLIP, with the sabotage output that proves it bites.

Still open and unchanged: 6.1/6.3 (plan_interaction_coverage's own report and
flip) and 6.4 (D7's definition of done, which needs the configuration-level
splits closed too, not just row-level coverage).

openspec validate --all --strict: 27 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@johnml1135
johnml1135 merged commit 4560e9e into conformance-framework Jul 28, 2026
3 of 4 checks passed
@johnml1135
johnml1135 deleted the g9-add-missing-construct-rows branch July 28, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants