PureYAML/docs/rules-conformance.md
Mihaela M 44abc12e80 docs: record rules conformance, import contract, and round-trip law
Add docs/rules-conformance.md documenting how the repo conforms to the
vendored canon, the documentation.md vs dependency-free conflict and its
scoped resolution, the domain-mismatched rules that do not apply, and the
conscious deviations. Add docs/package-import-contract-status.md. State
the round-trip law (Lambda1/Lambda2) in DESIGN.md.
2026-06-26 06:14:24 +02:00

4.2 KiB

Rules conformance

This records how PureYAML conforms to the vendored Swift rules canon (docs/rules-swift/, mirror of rules-swift), including the few places where a canon rule does not apply to a dependency-free YAML library or conflicts with a project non-negotiable. Per docs/rules-swift/core/rules.md, conflicts are resolved by scope: the condition under which each rule applies is named, so exactly one governs any case.

Conformant (applicable rules)

Every applicable rule passes its acceptance check. Mechanically verified: check-style, check-namespacing (now namespace-aware, catches one-type-per-file inside extension blocks), check-forbidden-patterns, check-changelog-touched, check-roadmap, swiftformat --lint, swiftlint --strict, swift build, swift test (277 tests). Concurrency, dependency-injection, cross-platform, framework-policy, namespacing (anchor choice), folder-grouping, domain-first, and the no-shortcuts mechanical tells are all clean.

Conflict: documentation.md Rule 1 vs the dependency-free non-negotiable

documentation.md Rule 1 mandates a DocC catalog plus swift-docc-plugin as a package dependency. PureYAML's binding non-negotiable (CLAUDE.md, AGENTS.md) is no external SwiftPM dependencies (dependencies: []). Both cannot hold. Resolution by scope: the dependency-free invariant is the higher-stability project contract and wins. PureYAML is therefore exempt from documentation.md Rule 1's plugin requirement. API documentation lives in source /// comments and docs/. If a maintainer later accepts a build-time plugin dependency, this exemption is revisited.

Not applicable: domain-mismatched canon files

Several canon files describe other domains (OpenAPIKit data parsing, an After-Effects-style tool, app startup, UI). Their domain-specific clauses do not bind a dependency-free YAML library; the transferable clauses are satisfied.

  • parsing-rules.md: the CSV/XML/Excel/Codable-record and multi-encoding Data clauses are N/A; the applicable parse-then-validate separation and enum-with-associated-values clauses pass.
  • validation-rules.md: the OpenAPI component-store / $ref / type-erasure and "validate-or-exclude every public type" coverage-gate clauses are N/A (the input model is the 5-case Model.Value enum, handled exhaustively, so no input is silently dropped). The applicable rule/validator/issue-path clauses pass.
  • business-rules-and-constraints.md: entirely N/A (no external services, auth, PII, or compliance surface in an offline library).
  • ui/*, openapi-generated.md, exp/app-target.md: N/A (no UI, not generated, no app target).

Conscious deviations (intent met another way)

  • core/round-trip-transformation.md "by construction" (one ParserPrinter): PureYAML keeps a hand-written parser and emitter rather than a single invertible algebra, because a bijective ParserPrinter is not a faithful model of full YAML (block/flow, anchors, tags, chomping, comments; surface-to-model is many-to-one). The law it protects is enforced by a fixed-point gate: parse(dump(parse(x))) == parse(x) over the corpus and generated documents, plus the empty-collection adversarial regression. The round-trip law is stated in docs/DESIGN.md.
  • code-style.md file-naming: the repo uses folder-based bare names in some folders (Parsing/) and dotted <Namespace>.<Type>.swift in others (Tagged/, Validation/). Both are blessed patterns; the standing convention is dotted for new namespaced files. A full rename to one pattern is deferred as disproportionate churn against the highest-stability rename surface.
  • documentation.md Rule 14 (/// on every public decl): the non-trivial public entry points are documented; the remaining gap is the MAY-skip categories (Codable conformance members, CustomStringConvertible.description, self-describing data fields). Tracked, not blanket-filled.

Historical commits

A few commits that predate the commit-message hook have non-Conventional or over-72-character subjects. They are already on origin/main; rewriting pushed history is out of scope. The commit-msg hook now enforces Conventional Commits and the 72-character subject limit going forward.