docs: align stale figures with code and the enforced XSTS gate

- README, roadmap: XSTS status quad and gates table now read the enforced
  0/43/0/31 (Tests/XSTSSuiteTests.swift); test count 986/169 to 1448/258;
  encoding list and the remaining-work section reflect shipped reality;
  check-all expansion lists the validation and changelog gates
- GEMINI.md, onboarding-antigravity.md: valid-schemas-rejected 1 to 0 and the
  pinned baselines updated to current
- SECURITY.md: complete the reporting address
- Parsing.InputEncoding: doc comment lists the full shipped encoding set
- Schema.XSDParserUnion: guard the localName interpolation with ?? "" to match
  the same line and silence an optional-interpolation warning (internal dedup
  key, behavior preserving)
- CHANGELOG: Unreleased entries for the above
This commit is contained in:
Mihaela Mihaljevic 2026-06-19 21:28:31 +02:00
parent b73384bc2e
commit 8d30010e0d
8 changed files with 68 additions and 44 deletions

View File

@ -28,6 +28,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Silenced an optional-interpolation warning in the union dedup signature
(`XSDParserUnion`): the `localName` interpolation now guards with `?? ""` to
match the `name`-attribute interpolation on the same line. The signature is an
internal dedup key compared only against same-run signatures, so the change is
behavior-preserving (it removes the `Optional("…")` rendering, not any key
collisions).
- Documentation accuracy sweep: brought stale current-state figures into line with
the code and the enforced gate. The README test count (986/169 -> 1448/258) and
XSTS status quad, the roadmap gates table, and the Antigravity onboarding
baselines now read the enforced `0 / 43 / 0 / 31`; the encoding coverage (the
README feature list and the `Parsing.InputEncoding` doc comment) now lists the
full shipped set (the ISO-8859 family, Windows code pages 1250-1258, KOI8-R/U,
and the CJK multi-byte encodings) instead of a three-entry subset; the
"remaining parity" section now states that libxml2 documented-surface parity is
complete (epics #71/#74/#105 closed) with production readiness (#167) as the
remaining work; the README `check-all.sh` expansion lists the validation-coverage,
validation-field, and changelog gates; and the SECURITY.md reporting address is
corrected.
- Replaced XSD content-model occurrence unrolling with a counted automaton.
`ContentMatcher` now tracks occurrence counters in active configurations instead
of copying particle bodies into states, preserving exact finite `{m,n}` behavior

View File

@ -8,7 +8,7 @@ rule here and a guideline elsewhere conflict, this file wins.
PureXML is an XML/XSD validator. **Never reject a valid schema or a valid
document.** In the conformance counts this is `valid-schemas-rejected`; it is
**1** and must **never rise**. Under-rejecting (missing an invalid schema) is
**0** and must **never rise**. Under-rejecting (missing an invalid schema) is
acceptable; over-rejecting (rejecting a valid one) is a failure and must not be
merged. When unsure, do less.
@ -67,6 +67,6 @@ merged. When unsure, do less.
## Definition of done
All gates green; conformance differential shows invalid-accepted down and **no
other bucket up** (valid-rejected still 1); the critic found zero false
other bucket up** (valid-rejected still 0); the critic found zero false
positives; baseline/CHANGELOG/burndown updated. If you rejected even one valid
schema, the change is wrong regardless of how many invalid ones it caught.

View File

@ -100,7 +100,7 @@ flowchart TB
EncodingMismatch["#137 encoding-declaration mismatches: complete"]:::done
BaseURI["#138 per-entity base URIs: complete"]:::done
Epic122["#122 conformance suite maintenance: complete (#130 survivor)"]:::epic
XSTS["#129 XSTS runner shipped; gates #145-#148 at 1/264/173/155 (v0.2.0)"]:::review
XSTS["#129 XSTS runner shipped; gates #145-#148 at 0/43/0/31"]:::review
XSLTTS["#130 XSLT 1.0 suite (xalan-test): ~126 baseline failures"]:::review
Parity100["Behavioral parity closed: #141 top-level params, #142 public streaming, #143 XPath budget, #144 WASI runtime proof, pl/ru sort collation"]:::done
Epic139["#139 faster than libxml2, measured + streaming (benchmarks in docs/benchmarks.md; quadratics killed; unsafe authorized)"]:::epic
@ -139,11 +139,11 @@ flowchart TB
## Status
**Current focus:** production readiness for IDE use ([#167](https://github.com/mihaelamj/PureXML/issues/167)). XSTS settled baselines (v0.2.0): **1 / 264 / 173 / 155**. See [`docs/roadmap.md`](docs/roadmap.md) for milestones and open tasks.
**Current focus:** production readiness for IDE use ([#167](https://github.com/mihaelamj/PureXML/issues/167)). XSTS settled baselines (valid schemas rejected / invalid schemas accepted / valid instances rejected / invalid instances accepted), enforced in `Tests/XSTSSuiteTests.swift`: **0 / 43 / 0 / 31**. See [`docs/roadmap.md`](docs/roadmap.md) for milestones and open tasks.
PureXML is a working, dependency-free XML library today: parse, emit, validate,
query, and stream documents on macOS, Linux, Windows, and WASM. The test suite
currently runs **986 tests in 169 suites** (`swift test`).
currently runs **1448 tests in 258 suites** (`swift test`).
### Shipped (libxml2-aligned surface)
@ -156,8 +156,10 @@ currently runs **986 tests in 169 suites** (`swift test`).
(libxml2 `xmlTextReader`). Handles elements, attributes, text, predefined and
numeric entities, comments, CDATA, and processing instructions. Namespace
bindings (`xmlns`) are resolved to URIs on parse.
- **Encoding**: UTF-8/16/32 (with BOM sniffing), ISO-8859-1, and Windows-1252
from raw bytes or streaming byte input.
- **Encoding**: UTF-8/16/32 (with BOM sniffing) from raw bytes or streaming byte
input, plus the ISO-8859 single-byte family, the Windows code pages
(1250-1258), KOI8-R/U, and the CJK multi-byte encodings (Shift-JIS,
EUC-JP/KR/TW, GBK, GB18030, Big5, ISO-2022-JP).
- **DTD (opt-in)**: `<!DOCTYPE>` is **off by default** (`Limits.allowDoctype:
false`) to keep XXE and entity-expansion closed. When enabled, the internal
subset is parsed; internal general entities expand with a bounded cap; external
@ -206,25 +208,21 @@ subset validation or internal entities, and wire a resolver only for trusted,
in-memory replacements. Network fetching (`nanohttp`/`nanoftp`) and libxml2's
threading/memory infrastructure are deliberate non-goals.
### Remaining toward full libxml2 feature parity
### Remaining work
The original parity epics (the core I/O stack, query, transform, the schema
languages, the validation framework, and editor integration) are all shipped. The
remaining work is the depth gaps a read-only conformance audit surfaced, tracked
under epic **#71** (and its parser-breadth sub-epic **#74**):
Feature parity with libxml2's documented surface is **complete**: the core I/O
stack, the query and transform layers, all four schema languages, the validation
framework, editor integration, and the encoding set (the ISO-8859 family, the
Windows code pages, and the CJK multi-byte encodings) are shipped. The
beyond-parity audit epics (**#71**, its parser-breadth sub-epic **#74**) and the
parity-frontier epic (**#105**) are closed.
| Open work | Issues | What it adds |
|---|---|---|
| XSLT 1.0 breadth | #81 #82 | Missing top-level elements and functions, html output |
| HTML5 | #83 #84 | Full tree construction, tokenizer states, entity table |
| C14N | #85 | Node-subset canonicalization, `xml:*` inheritance, 2.0 prefix rewrite |
| Legacy encodings | #97 #99 #102 #103 | Single-byte, CJK multi-byte, full GB18030, and Big5 to-Unicode tables |
| Validator decomposition | #101 | Inner XSD/DTD validators as composable rules |
| Partial follow-ups | #79 #80 #86 #87 #88 #90 #91 | Remaining bullets on already-advanced areas |
Each open issue carries a checklist of done vs remaining bullets. The encoding
tables (#97, #99) are deferred until they can be vendored from authoritative
Unicode mapping files rather than transcribed.
The remaining distance is **production readiness for IDE use**, tracked under epic
**#167**: driving the XSTS conformance buckets toward zero (currently
**0 / 43 / 0 / 31**), located schema diagnostics (#169), the schema differential
oracle (#171), and cross-document composition (#161). The one active runner
burn-down is **#130** (the XSLT 1.0 xalan suite). See
[`docs/roadmap.md`](docs/roadmap.md).
## Usage
@ -287,6 +285,9 @@ That command expands to:
bash scripts/check-style.sh
bash scripts/check-namespacing.sh
bash scripts/check-forbidden-patterns.sh
bash scripts/check-validation-coverage.sh
bash scripts/check-validation-fields.sh
bash scripts/check-changelog-touched.sh
swiftformat . --config .swiftformat --lint
swiftlint --config .swiftlint.yml --strict
swift build

View File

@ -5,7 +5,7 @@
If you believe you have found a security issue in PureXML, please report it
privately. Do not open a public issue for security problems.
Email **mihaelamj.com** with:
Email **mihaelamj@gmail.com** with:
- A description of the issue and its impact.
- Steps to reproduce, or a proof of concept.

View File

@ -1,7 +1,8 @@
public extension PureXML.Parsing {
/// A character encoding PureXML can decode from raw bytes. Covers the
/// Unicode transformation formats plus the single-byte encodings (ISO-8859-1,
/// ISO-8859-5/9/15, and Windows-1252), toward libxml2 encoding parity.
/// A character encoding PureXML can decode from raw bytes. Covers the Unicode
/// transformation formats, the ISO-8859 single-byte family, the Windows code
/// pages (1250-1258), KOI8-R/U, and the CJK multi-byte encodings (Shift-JIS,
/// EUC-JP/KR/TW, GBK, GB18030, Big5, ISO-2022-JP), for libxml2 encoding parity.
enum InputEncoding: String, Equatable, Sendable {
case utf8
case utf16BigEndian

View File

@ -67,7 +67,7 @@ extension PureXML.Schema.XSDParser {
guard XSDNode.localName(tree) == "schema" else { return nil }
guard let namespace = XSDNode.attribute(tree, "targetNamespace"), !namespace.isEmpty else { return nil }
let components = XSDNode.elementChildren(tree)
.map { "\(XSDNode.localName($0)):\(XSDNode.attribute($0, "name") ?? "")" }
.map { "\(XSDNode.localName($0) ?? ""):\(XSDNode.attribute($0, "name") ?? "")" }
.sorted()
return "\(namespace)\u{1}\(components.joined(separator: "\u{1}"))"
}

View File

@ -20,7 +20,7 @@ PureXML is an XML/XSD validator. Its single most important quality is:
> **Never reject a valid schema or a valid document.**
In the conformance numbers (Section 5) this is the bucket
`valid-schemas-rejected`. It is currently **1** and must **never go up**. A
`valid-schemas-rejected`. It is currently **0** and must **never go up**. A
change that fixes ten bad schemas but wrongly rejects one good schema is a
**failure** and must not be merged. When in doubt, do less: it is always
acceptable to *miss* an invalid schema (under-reject); it is never acceptable to
@ -133,10 +133,10 @@ top of that file:
| Constant | Meaning | Current value | Direction |
|---|---|---|---|
| `knownSchemaValidRejected` | valid schemas we wrongly **reject** | **1** | must NEVER rise; drive toward 0 |
| `knownSchemaInvalidAccepted` | invalid schemas we wrongly **accept** | **390** | drive DOWN |
| `knownInstanceValidRejected` | valid instances we wrongly **reject** | **180** | must not rise; drive toward 0 |
| `knownInstanceInvalidAccepted`| invalid instances we wrongly accept | **160→158** (158) | drive down |
| `knownSchemaValidRejected` | valid schemas we wrongly **reject** | **0** | must NEVER rise; hold at 0 |
| `knownSchemaInvalidAccepted` | invalid schemas we wrongly **accept** | **43** | drive DOWN |
| `knownInstanceValidRejected` | valid instances we wrongly **reject** | **0** | must not rise; hold at 0 |
| `knownInstanceInvalidAccepted`| invalid instances we wrongly accept | **31** | drive down |
The runner asserts these counts **exactly**. So:
@ -406,12 +406,12 @@ Representative existing checks to imitate (read these as templates):
---
## 11. Current state (snapshot, post v0.1.0)
## 11. Current state (snapshot, post v0.2.0)
- Pinned baselines: **valid-schemas-rejected 1**, **invalid-schemas-accepted
390**, **valid-instances-rejected 180**, **invalid-instances-accepted 158**.
(v0.1.0 was tagged at invalid-accepted 394; the count has since dropped to
390. Always read the live constants in `Tests/XSTSSuiteTests.swift`.)
- Pinned baselines: **valid-schemas-rejected 0**, **invalid-schemas-accepted
43**, **valid-instances-rejected 0**, **invalid-instances-accepted 31**.
(These ratchet down as conformance work lands; always read the live constants
in `Tests/XSTSSuiteTests.swift`.)
- The clean structural / applicability rule families are largely **done**:
facet validity, structural content-model, UPA determinism, content order,
identity-constraint XPath subset, wildcard namespace, final/block value space,

View File

@ -13,14 +13,16 @@ Parallel: **#130** (XSLT suite), **#139** (performance epic; tasks [#175](https:
**M1 done:** #171 schema differential harness (closed; opt-in; 231 XSTS oracle disagreements pinned) + generative fuzz + validation framework (#92).
## XSTS gates (v0.2.0 baselines)
## XSTS gates (current enforced baselines)
These mirror the ratchet asserted in `Tests/XSTSSuiteTests.swift`; update both together.
| Gate | Now | Issue |
|---|---|---|
| Valid schemas rejected | 1 | [#148](https://github.com/mihaelamj/PureXML/issues/148) |
| Invalid schemas accepted | 261 | [#145](https://github.com/mihaelamj/PureXML/issues/145) |
| Valid instances rejected | 99 | [#146](https://github.com/mihaelamj/PureXML/issues/146) |
| Invalid instances accepted | 147 | [#147](https://github.com/mihaelamj/PureXML/issues/147) |
| Valid schemas rejected | 0 | [#148](https://github.com/mihaelamj/PureXML/issues/148) |
| Invalid schemas accepted | 43 | [#145](https://github.com/mihaelamj/PureXML/issues/145) |
| Valid instances rejected | 0 | [#146](https://github.com/mihaelamj/PureXML/issues/146) |
| Invalid instances accepted | 31 | [#147](https://github.com/mihaelamj/PureXML/issues/147) |
Gates are **metric trackers**, not implementation tasks. Pick up **task** issues; ratchet baselines in `Tests/XSTSSuiteTests.swift` when counts fall.