test(schema): reclassify schA2.i/schA5.i as contested; characterize the sch* tail (#380)

The sch* schema-location cluster, dissected per case rather than swept. An
adversarial analysis separated the contested tests from the genuine deviations.

schA2.i and schA5.i are contested and now excluded (invalid-instances-accepted
10 -> 8). Each group's own documentation states the inline xsi:schemaLocation
hint "is ignored" and the instance "must conform to" the collection schema, but
under exactly that prescribed behavior the instances are valid: libxml2 validates
schA2.xml against its a.xsd and schA5.xml against its a.xsd+b.xsd collection. So
the suite's invalid expectation contradicts its own documentation. Reaching
invalid requires letting the instance's hint override a schema already loaded for
that namespace, which XSD 1.0 §4.3.2 makes optional (strategy 1: do nothing when a
schema for the namespace is already known) and which would be a direct false
positive for an IDE: an instance file forcing rejection against the project's own
schema. PureXML's policy (honor hints but keep the collection's declarations on
conflict) is conformant.

schA7.i is NOT excluded. The adversarial pass showed its invalid IS spec-grounded:
with hints ignored, the instance's b:e1 (namespace ns-b) has no declaration in the
a.xsd-only collection and is demanded by root's default-strict ##any wildcard, so
§3.10.4 makes it invalid. PureXML accepts it only by honoring the ns-b hint to
gap-fill, the other conformant §4.3.2 strategy. A genuine policy-dependent
deviation, left in the count and documented.

schU3.i/schU4.i/schU5.i are also left in the count, documented as a deferred
under-rejection in an underspecified area: circular redefine chains where an
attribute group is redefined to conflicting types across an include/redefine
cycle. The suite expects the int reading (so c1="a" is invalid); PureXML resolves
the laxer type and accepts. libxml2 does not support the construct at all (rejects
the schema: multiple redefinition not supported), so matching the suite means
out-resolving the reference on a construct whose cyclic composition order the spec
does not pin down.

Full XSTS in release now 0/8/0/8, both false-positive buckets at 0. No library
behavior change; reasoning recorded in code and docs/xsts-deviations.md.
This commit is contained in:
Mihaela Mihaljevic 2026-06-29 07:52:13 +02:00 committed by GitHub
parent 35e52f26cf
commit 7ea1a88a6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 2 deletions

View File

@ -81,7 +81,12 @@ struct XSTSSuiteTests {
/// 11 -> 10: anyURI_a004_1339.i reclassified as a contested test, not a bug (see
/// the excluded set below). PureXML's acceptance is spec-correct; the suite's
/// expectation is internally inconsistent.
private let knownInstanceInvalidAccepted = 10
/// 10 -> 8: schA2.i and schA5.i reclassified as contested (see the excluded set).
/// Their `invalid` expectation contradicts their own "ignore the inline hint"
/// documentation; under that prescribed behavior both instances are valid.
/// (schA7.i, which looks similar, is NOT excluded: its `invalid` is spec-grounded,
/// a genuine policy-dependent deviation tracked in docs/xsts-deviations.md.)
private let knownInstanceInvalidAccepted = 8
/// Instance tests excluded from the counts because their expected validity is not
/// authoritative, mirroring how the suite's own `status="queried"` entries are
/// skipped. Each must carry a spec-grounded justification; this is never a place to
@ -102,7 +107,22 @@ struct XSTSSuiteTests {
/// non-conformantly fails to compile the schema on the unresolvable include).
/// Matching the suite would mean rejecting a valid instance whenever an include
/// cannot be resolved, a false positive an IDE editing loop hits constantly.
private static let specDivergentInstances: Set<String> = ["anyURI_a004_1339.i"]
///
/// - `schA2.i`, `schA5.i`: schema-location precedence. Each group's documentation
/// states the inline `xsi:schemaLocation` hint "is ignored" and the instance
/// "must conform to" the collection schema, but under exactly that prescribed
/// behavior the instances are valid (libxml2 validates schA2.xml against its
/// `a.xsd`, and schA5.xml against its `a.xsd`+`b.xsd` collection), so the
/// `invalid` expectation contradicts the group's own documentation. Reaching
/// `invalid` requires letting the instance's hint override a schema already
/// loaded for that namespace, which XSD 1.0 §4.3.2 makes optional (strategy 1:
/// "do nothing ... because a schema ... is already known") and which would be a
/// direct false positive for an IDE (an instance file forcing rejection against
/// the project's own schema). PureXML's policy (honor hints but keep the
/// collection's declarations on conflict) is conformant. Confirmed by an
/// adversarial analysis that separated these from schA7.i, whose `invalid` IS
/// spec-grounded (a genuine policy deviation, left in the count).
private static let specDivergentInstances: Set<String> = ["anyURI_a004_1339.i", "schA2.i", "schA5.i"]
@Test("Every XSTS case behaves: compile, reject, validate, invalidate")
func test_suite() throws {

View File

@ -102,6 +102,34 @@ schema on the unresolvable include). Matching the suite would reject a valid
instance whenever an include cannot be resolved, a false positive an IDE hits
constantly. Recorded in `XSTSSuiteTests.specDivergentInstances`.
The `sch*` schema-location cluster, dissected per case (an adversarial analysis
separated the contested from the genuine):
- `schA2.i`, `schA5.i`: **contested**, reclassified (`invalid-instances-accepted`
10 -> 8). Each group's own documentation says the inline `xsi:schemaLocation`
hint "is ignored" and the instance "must conform to" the collection schema; under
exactly that behavior libxml2 validates the instance (schA2 against `a.xsd`, schA5
against `a.xsd`+`b.xsd`), so the `invalid` expectation contradicts the group's own
documentation. Reaching `invalid` needs the instance's hint to override a schema
already loaded for that namespace, which XSD 1.0 §4.3.2 makes optional (strategy 1)
and which would be a direct IDE false positive. Excluded in `specDivergentInstances`.
- `schA7.i`: **genuine, policy-dependent deviation, left in the count.** Here the
`invalid` IS spec-grounded: with hints ignored, the instance's `b:e1` (namespace
`ns-b`) has no declaration in the `a.xsd`-only collection and is demanded by
`root`'s default-`strict` `##any` wildcard, so §3.10.4 makes it invalid. PureXML
accepts it only by honoring the `ns-b` hint to gap-fill the wildcard, the other
conformant §4.3.2 strategy. A real divergence in schema-location policy, not a
suite bug; not excluded.
- `schU3.i`, `schU4.i`, `schU5.i`: **genuine under-rejection in an underspecified
area, deferred.** These are circular `redefine` chains where one attribute group
(`c-g1`) is redefined to conflicting types (`int` via one document, `string` via
another) across an include/redefine cycle. The suite expects the `int` reading, so
the instance's `c1="a"` is invalid; PureXML resolves to the laxer type and accepts.
libxml2 does not support this at all (it rejects the schema: "Multiple redefinition
of the same component is not supported"), so matching the suite means out-resolving
the reference on a construct whose composition order in a cycle the spec does not
pin down. Tracked as deferred scope, not excluded.
Takeaway: on the schema side, libxml2 parity is reached except the one case now
fixed; the remaining nine are a deliberate choice to exceed the reference. On the
instance side the Ethiopic-digit `\d`/`\D` and `\i`/`\c` name-class cases are now