Skip to content

feat(interop): classify third-party gap rows; ratchet SPAR-DEFECT count exactly (#427) - #429

Merged
avrabe merged 1 commit into
mainfrom
feat/interop-gap-classify-427
Aug 20, 2026
Merged

feat(interop): classify third-party gap rows; ratchet SPAR-DEFECT count exactly (#427)#429
avrabe merged 1 commit into
mainfrom
feat/interop-gap-classify-427

Conversation

@avrabe

@avrabe avrabe commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Closes #427 (a)+(b) — the two "cheap suggestions", plus the separate-count assertion. Does not fix the three underlying parser defects, and does not decide whether the conflict-marker files stay in the corpus (both are separate maintainer moves the issue lays out).

The defect #427 measured

test-data/interop/baseline/third-party-gaps.txt ratchets 14 vendored models spar fails to parse. Read as a number that looks like 14 units of debt. #427 opened all 14 against the source and measured that it is 3:

class n is spar wrong?
UPSTREAM-INVALID — committed git-conflict markers 7 no
AADLV1 — unnamed connections (OSATE rejects them too, #421) 2 no
MALFORMED-V2 — missing properties / implementation keyword 2 no
SPAR-DEFECT — EMV2-qualified owners (2) + two-token reference(virtual processor) (1) 3 yes

Bundling three genuine defects with eleven files no parser accepts is how "14" invites being driven to zero by relaxing the parser onto invalid input, or absorbing a real regression into the mixed pile.

What this PR changes

  • third-party-gaps.txt — a CLASS token on every row (path\tCLASS\tfirst-diagnostic), header rewritten to define the four classes.
  • crates/spar-cli/tests/third_party_corpora.rs — two tests:
    • every_baseline_entry_is_classified — reds any row missing a recognised class token, so a new gap must be classified before it can be ratcheted in (the moment someone actually looks).
    • spar_defect_count_matches_ratchet — asserts SPAR-DEFECT == MAX_SPAR_DEFECT (3) two-sided, same shape as MAX_TOO_PERMISSIVE in three_way_conformance.rs: above the floor reds a new too-strict rejection; below reds until the constant is walked back. The other three classes stay in the file as documentation but are not counted as debt.
  • artifacts/{requirements,verification}.yamlREQ-PLUGFEST-CORPUS-CLASSIFY-001 (traces-to REQ-PLUGFEST-007) + TEST-PLUGFEST-CORPUS-CLASSIFY with executable fields.steps.

Non-vacuity (executed, not asserted in prose)

Three baseline mutations, each reddening a distinct assertion, run before land:

  1. reclassify one SPAR-DEFECT row → UPSTREAM-INVALID: count drops → below-floor branch reds;
  2. write an unrecognised class token: classifier reds;
  3. append a fabricated SPAR-DEFECT row: count rises → above-floor branch reds.

Restoring the file greens all four tests. MAX_SPAR_DEFECT is a fixed literal, so neither bound is vacuous.

Verification

  • cargo test -p spar --test third_party_corpora → 4 passed
  • cargo fmt --all --check clean; cargo clippy --workspace --all-targets -- -D warnings clean
  • rivet validate0 broken cross-refs, new REQ visible (its lone missing: design-decision warning is the repo-wide baseline shape)
  • Independent clean-room pass re-derived every row's class from file content, re-ran all three non-vacuity mutations, and confirmed no over-claim in the artifact prose.

🤖 Generated with Claude Code


Generated by Claude Code

…nt exactly (#427)

third-party-gaps.txt ratcheted 14 vendored models spar fails to parse.
Read as a number that looks like 14 units of debt; #427 opened all 14 and
measured that it is 3. The other 11 are files no parser should accept
(7 with committed git-conflict markers), AADLv1 unnamed connections that
OSATE rejects too (2), or malformed AADLv2 (2).

Give each row a CLASS token (SPAR-DEFECT / UPSTREAM-INVALID / AADLV1 /
MALFORMED-V2) so the count is no longer read as raw debt, and split the
one number that names debt spar owes from the pile that does not:

- every_baseline_entry_is_classified reds any row without a recognised
  class, so a NEW gap must be classified before it can be ratcheted in.
- spar_defect_count_matches_ratchet asserts SPAR-DEFECT == MAX_SPAR_DEFECT
  (3) two-sided, same shape as MAX_TOO_PERMISSIVE: a new too-strict
  rejection reds above the floor; a fixed defect reds below until the
  constant is walked back.

Non-vacuity executed, not asserted: three baseline mutations each red a
distinct assertion (reclassify a SPAR-DEFECT row -> below-floor; unknown
class token -> classifier; bogus SPAR-DEFECT row -> above-floor);
restoring greens all four tests.

Does not fix the three underlying parser defects (#427 names them) and
does not decide whether the 7 conflict-marker files stay in the corpus —
both are separate moves called out in the issue.

Traces: REQ-PLUGFEST-CORPUS-CLASSIFY-001, TEST-PLUGFEST-CORPUS-CLASSIFY.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

Rivet verification gate

20/20 passed

count
Passed 20
Failed 0
Skipped (no steps) 0

Filter: (and (= type "feature") (or (has-tag "v093") (has-tag "v0100")))

Failed artifacts

(none)

Updated automatically by tools/post_verification_comment.py. Source of truth: artifacts/verification.yaml.

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.

3 of the 14 ratcheted third-party gaps are spar defects; 7 of the rest are files with git conflict markers in them

2 participants