From 7ea1a88a6cc5283482bb1a32c53b7aa1a4150c99 Mon Sep 17 00:00:00 2001 From: Mihaela Mihaljevic Date: Mon, 29 Jun 2026 07:52:13 +0200 Subject: [PATCH] test(schema): reclassify schA2.i/schA5.i as contested; characterize the sch* tail (#380) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Tests/XSTSSuiteTests.swift | 24 ++++++++++++++++++++++-- docs/xsts-deviations.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Tests/XSTSSuiteTests.swift b/Tests/XSTSSuiteTests.swift index 650c7fb..f1f9060 100644 --- a/Tests/XSTSSuiteTests.swift +++ b/Tests/XSTSSuiteTests.swift @@ -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 = ["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 = ["anyURI_a004_1339.i", "schA2.i", "schA5.i"] @Test("Every XSTS case behaves: compile, reject, validate, invalidate") func test_suite() throws { diff --git a/docs/xsts-deviations.md b/docs/xsts-deviations.md index 905c4b1..ee24711 100644 --- a/docs/xsts-deviations.md +++ b/docs/xsts-deviations.md @@ -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