Commit Graph

7 Commits

Author SHA1 Message Date
97c07e91f4 feat(schema): locate composition/redefine-pass schema diagnostics
Convert the five composition/redefine compile checkers to located findings,
the last of the #169 burndown (#210-#217): a resolved schemaLocation whose
content is not a schema underlines the include/import/redefine reference, a
redefined type that does not restrict or extend itself underlines the
redefined type, a redefined group or attribute group with a malformed
self-reference underlines the offending reference or redefinition, and a
redefined attribute group or model group that does not restrict its original
underlines the redefinition.

To locate the referenced-schema rule, failedSchemaReferences carries the
referencing node, captured at the load-failure site in XSDContext. Only a
top-level reference's node belongs to the main schema tree the diagnostic
resolves against; a failure nested in a loaded sub-document is captured from
a throwaway parse, so it stays unlocated (the prior schema-root behavior)
rather than mis-resolve, a strict improvement.

Every predicate, aggregation order, and reason string is unchanged; only the
location each finding carries differs, verified conformance-neutral by the
full XSTS suite (14383 groups, pinned counts unchanged). The redefine
checkers had exactly one caller each, so each is renamed in place and the
.unlocated wrap dropped. Adds a located-diagnostics test per node-locatable
checker; the attribute-group and model-group restriction redefine checkers
share the same redefinition-node idiom and are exercised by the XSTS suite.
2026-06-21 19:41:31 +02:00
af5d7882b0 fix(schema): enforce model-group redefine restriction (cos-group-restrict)
A non-self-referencing model group redefined inside xs:redefine must be a valid
restriction of the group it redefines (cos-group-restrict / src-redefine 6.1.2),
so its content model may not widen the original's language. The check reuses the
particle-restriction oracle used for complex-type restriction, resolves the
original group by namespaced identity with a {}name chameleon fallback, and runs
post-compile where element type compatibility is available.

Now rejected: adding required content to an empty base (schZ006), dropping a
required all member (schL1), reordering an all (schL5/L6, the Recurse rule is
order-preserving even for all), growing to a superset (schL8), and the
multi-document/chained redefines schN4/5/6/7 and schL10. To stay
false-positive-free the check skips a redefinition carrying a self-reference and
declines to judge a base with a maxOccurs=0 pointless particle (the contested
case W3C accepts, mgO013); genuine restrictions (dropping an optional member, an
unchanged redefinition) are accepted.

XSTS invalid-schemas-accepted 64 -> 51, no false positive (valid-schemas-rejected
and valid-instances-rejected held at 0; an over-rejection of mgO013 surfaced by
the gate was fixed before commit, and an adversarial critic confirmed FP-safety),
no other bucket moved. Disclosed under-rejections: self-referencing redefinitions
(schN10) and maxOccurs=0-base redefines.
2026-06-18 18:24:58 +02:00
be9ba9fc1e fix(schema): a redefined attribute group keeps required and re-prohibits prohibited attributes; invalid-schemas-accepted 67 to 65 (#145, #161)
A redefinition of an attribute group restricts the original (src-redefine /
cos-ct-restricts), so it may neither eliminate a required attribute the original
declares (attgZ002) nor re-introduce a prohibited one as usable (attgZ003).
redefineAttributeGroupRestrictionErrors compares the redefinition to the original
attribute group and reports either violation.

False positives the verification caught and the rule guards against: re-declaring
a base prohibited attribute AS prohibited keeps it prohibited and is valid (the
check requires a non-prohibited use); the drop-required check is skipped when the
redefinition pulls attributes back via a nested attributeGroup reference; and the
base is matched by NAMESPACED identity ({target}name), so a same-local-name
attribute group imported from a different namespace is never mistaken for the base
(the same namespace guard the redefine self-reference rule uses).

invalid-schemas-accepted 67 to 65, no false positive (valid-schemas-rejected and
valid-instances-rejected held at 0). The gate caught a re-prohibition false
positive and an adversarial review caught a cross-namespace collision false
positive; both are fixed and covered by tests.
2026-06-18 17:46:54 +02:00
0f90b3a4d3 fix(schema): generalize redefine self-reference to attributeGroups + bound the walk; invalid-schemas-accepted 75 to 74 (#161)
Extends the redefine self-reference rule (redefineSelfReferenceErrors, moved to
SchemaRedefineSelfReference.swift) to attribute groups: a group or attributeGroup
inside xs:redefine may reference itself at most once (src-redefine.6.1.1 /
7.2.1), and a group self-reference must occur exactly once. Catches a redefined
attributeGroup with two self-references (attgC044).

Fixes a latent false positive an adversarial review found in the group case: the
search now uses a BOUNDED walk (boundedSelfReferenceNodes) that stops at nested
element/complexType scopes, matching the established cycle-rule boundary. The
prior unbounded walk would miscount a recursive group reference inside a nested
element's content (a data-structure recursion, legal) as a redefinition
self-reference. attributeGroup content has no such nesting, so it is unaffected.

XSTS: invalid-schemas-accepted 75 to 74 (attgC044), valid-schemas-rejected held
at 0, no other bucket moved. The validation description broadened accordingly
(configuration pin updated).
2026-06-18 01:15:16 +02:00
880137a955 fix(schema): a redefined group's self-reference must occur exactly once (src-redefine.6.1.2); invalid-schemas-accepted 79 to 77 (#161)
A group inside xs:redefine may reference itself (the group being redefined) at
most once, and that self-reference must have minOccurs = maxOccurs = 1. A
self-reference with minOccurs="0", maxOccurs="unbounded", or a count above 1 is
invalid. redefineGroupSelfReferenceErrors flags it, surfaced by the pre-compile
Validation redefineGroupSelfReferencesAreUnit.

The self-reference is matched by NAMESPACE (referenceNamespace == the redefining
schema's targetNamespace), not local name alone, so a redefined group that
references an imported group merely sharing its local name is correctly left
unconstrained -- the false-positive boundary an adversarial review flagged
before merge, mirroring the namespace guard the sibling redefine/cycle rules use.

XSTS: invalid-schemas-accepted 79 to 77 (schR3, schR4), valid-schemas-rejected
held at 0, no other bucket moved.
2026-06-18 00:52:40 +02:00
059763f5e9 refactor(schema): surface facet/pattern validity as a Validation, not a parse-time report (#161)
The convergence audit for "validators everywhere" found the one remaining XSD
schema-validity verdict reported outside the Validator framework: facet
definition validity and pattern syntax validity were reported straight to the
diagnostics collector during simple-type compilation (validation folded into
parsing, which validation-rules.md forbids).

These checks genuinely need the resolved base type, computed during compilation,
so the finding is gathered into a context finding sink (XSDContext
.facetFindingSink) during type resolution and surfaced by the named post-compile
Validation simpleTypeFacetsAreValid -- located findings preserved, now pinned in
the configuration test and removable by identity like every other rule.

Re-sweep confirms the XSD path has converged: the only remaining throws are
notASchema (a not-a-schema precondition) and inconsistent (the framework's own
surfacing throw); no validity verdict bypasses the framework. No bucket change
(invalid-schemas-accepted 81, valid-schemas-rejected 0); full suite + fuzz pass.
2026-06-18 00:02:20 +02:00
4def6a2c07 refactor(schema): redefine self-derivation as a Validation; drop the redundant all-group throw (#161)
Continues incorporating every schema-validity check into the Validator framework
(Rules/universal/validation-rules.md) rather than ad-hoc parse-pipeline throws.

- checkRedefine (src-redefine.5: a redefined type restricts or extends itself)
  becomes the pre-compile Validation redefinitionsDeriveFromThemselves;
  redefineDerivationErrors returns findings instead of throwing.

- checkAllGroups is removed entirely: every check it made is already produced by
  Validations -- "a member must be an element" by schemaStructureValid
  (allowedChildren[all]), and the occurrence limits by allGroupLimitedErrors
  (cos-all-limited.2). Verified redundant and not load-bearing: an empirical
  probe with the calls removed left invalid-schemas-accepted at 81 unchanged,
  the fuzz suite's "compile and validation never crash or hang" still passes
  (the NFA builder's own guards hold), and false positives stayed 0.

compileRule is now internal so composition Validations can live in their own
file (SchemaCompositionValidations.swift). Both new pre-compile rules are pinned
in ValidationConfigurationTests. The pre-existing public SchemaError.invalidAllGroup
case is kept (released API) though no longer thrown. No bucket change
(invalid-schemas-accepted 81, valid-schemas-rejected 0); full suite + fuzz pass.
2026-06-17 23:49:30 +02:00