Gate: invalid schemas accepted, ratchet 8 to 0 #4
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Status (2026-07-05)
Open. Metric tracker, not an implementation task.
The enforced baseline in
Tests/XSTSSuiteTests.swiftisknownSchemaInvalidAccepted = 8on the settled (non-contested) XSTS 2006-11-06 archive. Every step of the burn-down from the first measurement is recorded as a per-rule delta inCHANGELOG.mdanddocs/xsts-deviations.md.Per
docs/release-hurdles.md, nearly all remaining cases route through one shared oracle's deliberate under-approximation:ParticleRestriction.violation(Sources/Schema/ParticleRestriction.swift), where a fix risks a false positive (the unrecoverable failure class), needs spec adjudication, or needs machinery not yet built.Protocol:
docs/schema-validity-burndown.md. Run the suite withswift test -c release --filter XSTS; per-case deviations land in the burn-down file the test writes. Ratchet the baseline down in the test with every closed case; a rising count is a regression.Ratchet: invalid-schemas-accepted 8 -> 6 (2026-07-05,
2e3d2e2)First conformance ratchet since the tracker rebuild. Two of the eight remaining false-negatives are closed by fixing the layer that owned the lost information, not by special-casing the test IDs.
The fix
elemZ026andparticlesV020both restrict a complex type by swapping an element reference for one of its substitution-group members. NameAndTypeOK (XSD 1.0 section 3.9.6, Elt:Elt clause 1) pairs the declared element declarations and requires the same {name} and {target namespace}; no clause grants substitution an allowance in particle restriction. We accepted the swap because the substitution-group expansion rewrites the compiled term (an abstract head is dropped, members join a synthetic choice), so the checker compared expanded names that happened to line up.The root-cause fix:
Particle.declaredReferencenow carries the pre-expansion identity of every<xs:element ref="..."/>particle through compilation, andParticleRestriction.validpairs the declared references before dispatching to the structural pairing table. Particles without a declared reference (local elements, inline groups) are unconstrained by this gate and fall through to their structural case as before.Adjudication: particlesZ008
particlesZ008is byte-for-byte the same construct aselemZ026but ships a settledvalidexpectation, directly contradicting elemZ026's settledinvalid. The two cannot both be honored by any checker. Adjudicated in favor of the spec text (clause 1 has no substitution allowance) and Z008 is reclassified as a spec-divergent schema test, with the full reasoning recorded inTests/XSTSSuiteTests.swift.Differential vs libxml2
libxml2 does not implement this edge (it accepts both cases), so
elemZ026is pinned as a stricter-than-libxml2 disagreement. Measured with the change stashed before recording: ten further baseline entries (addB070a,addB108,addB177,attO025,elemZ027_c,errC008,groupH021v,notatB005,notatE002,particlesEb040) reproduce without this change and are pre-existing drift from earlier main-line fixes, recorded separately. Baseline 231 -> 242, differential green.State after this ratchet
Remaining six, corrected against the suite's own failure report (the deviations-doc row this list first came from had gone stale:
particlesIk011was already closed at the 9 -> 8 step andschN12was missing):particlesHa161,particlesIg004,particlesIk025,particlesIk027(the disclosed cos-st-derived-ok 2.2.4 divergence),particlesM034, andschN12(multi-document composition, untriaged). Per-case triage is next. Full macOS gate green (1845 tests), regression tests inTests/XSDParticleSubstitutionRestrictionTests.swift.Ratchet: invalid-schemas-accepted 6 -> 3, and the bucket is now fully adjudicated (2026-07-05,
6a7bf78)Per-case triage of the remaining six, each decided by the manifest annotation plus the spec text, not by pattern-matching. One structural insight closed two cases at once.
The fix: two occurrence regimes for RecurseAsIfGroup against a choice
The effective-total-range approximation in
elementRestrictsChoiceexists for exactly one reason: the literal section 3.9.6 pairing cannot express occurrence counts accumulated across a repeating choice's iterations, and over-rejects W3C-read-valid schemas (particlesZ001, "ambiguous" per its own manifest). But that ambiguity is impossible when the choice cannot repeat: at{max occurs} = 1every accepted child comes from one traversal of one branch, so the literal rule governs with no tension. The checker now applies the literal pairing for non-repeating base choices and keeps the effective-range reading only where repetition makes it necessary.a{0,1}is not a pointwise NameAndTypeOK restriction of the required brancha{1,1}inchoice{0,1}(a|b).d1+cannot map into the branch(d1*, d2+); the requiredd2is unmapped and not emptiable, so the base language contains no pure-d1string.d2+, valid becaused1*is emptiable), and the Z001 shape. All are now regression tests inTests/XSDParticleChoiceRestrictionTests.swift.particlesIg004: excluded as spec-divergent
Base
block="#all"restricted toblock="substitution extension restriction", expected invalid. Section 3.3.2 maps both to the same {disallowed substitutions} set, so NameAndTypeOK clause 5's superset requirement holds; only a reading where#allis strictly larger than the complete explicit set reaches invalid, and no such value exists in the 1.0 blockSet grammar. Jointly unsatisfiable with the settled Ig001/002/003 (equal sets, valid) and Ig005 (#allcovers the triple, valid). Full adjudication inTests/XSTSSuiteExclusions.swift.schN12: adjudicated, stays in the count as a policy deviation
Now triaged (it was the untriaged multi-document case). It is a chameleon redefine whose original no-namespace group compiles with unqualified locals while the redefining document is
elementFormDefault="qualified", so src-redefine 6.2.2's restriction obligation fails NameAndTypeOK clause 1. The catch: 6.2.2 cannot be enforced uniformly, because mgO013's settled-VALID schema also violates 6.2.2 (all{e1(1,1)}redefiningall{e1(0,0)}). The two settled expectations admit no single conformant policy; enforcing 6.2.2 trades this false negative for a valid-schema-rejected false positive, the hardest floor. PureXML keeps the FP-safe policy, documented indocs/xsts-deviations.md(the schA7 precedent: honest deviation, left in the count).State
The remaining three (Ik025, Ik027, schN12) are all documented divergences with recorded adjudications, no open bugs. In the strict sense this bucket has reached its principled floor: driving it below 3 means either adopting the literal cos-st-derived-ok member-chain reading (Ik025/027, a defensible spec argument either way) or enforcing 6.2.2 non-uniformly (not defensible). Gates: full XSTS release suite green at 0/3/0/4, libxml2 differential green at 244 pinned entries (Ha161 and M034 newly pinned as stricter-than-libxml2, both verified compiling under libxml2), full local gate green.
Next per the roadmap: #5, the instance-side tail (schA7.i, schU3/4/5.i, all schema-location/redefine-composition policy cases).