Skip to content

State the validator's feed rules in SPEC.md and schema 0.1 - #141

Merged
thossullivan merged 2 commits into
mainfrom
fix/spec-schema-gaps
Oct 25, 2026
Merged

thossullivan merged 2 commits into
mainfrom
fix/spec-schema-gaps

Conversation

@thossullivan

Copy link
Copy Markdown
Owner

Fixes #131.

Summary

  • Schema 0.1, tightened in place with rules the validator already enforces: via length, control characters, and reserved names; http(s) source URLs and their length; text limits and the control-character ban; the tentative shape; the min_notice_days maximum; the generated length; unique aliases in one list; and RFC 3339 shape patterns for validators that skip format.
  • SPEC.md: a normative "Validation" section, the rules only code can check, and a non-normative "Reference checker behavior" section. Tentative dates keep scheduled, and the spec now says they must not fail a build and must be shown as tentative.
  • publisher-fallback wording in SPEC.md, README.md, and CONTRIBUTING.md now matches the code.
  • validate messages: for feeds, the code validator's errors come first, as in check. Control-character and length errors are no longer reported twice.

No verdict changes

Corpus Feeds Verdict changes
Committed feeds/ 6 0
Every historical feed in git 63 0
SPEC.md example 1 0
Feeds used by the test suites 172 0
Fuzz, with and without format 46,985 0

Tests

Parity tests in scripts/test-document-validation.mjs: for each rule, the schema and the validator both reject a feed and both accept a near miss. The reject tests fail on main. npm test passes.

🤖 Generated with Claude Code

A feed author who followed SPEC.md and the published 0.1 schema could
still write a feed that model-eol validate rejects. The maintainer
chose to tighten schema 0.1 in place with rules the validator already
enforces, keep the control-character ban (newline and tab included),
and keep the scheduled status for tentative dates while rewording the
spec.

Schema 0.1 now carries: via length, control characters, and the
reserved publisher and publisher-fallback names in any letter case;
http(s) sources with the URL length limit; the 4096 text limit and
control-character ban on note, notes, and replacement_note; the
tentative shape for models and distributions; the min_notice_days
maximum; the generated length; unique aliases within one list; and
RFC 3339 shape patterns on dates and generated for validators that
skip format. No feed changes verdict: 6 committed feeds, 63 historical
feeds, the SPEC example, 172 test-suite feeds, and a 46,985-case fuzz,
with and without format.

SPEC.md states the normative rules (uniqueness, exclusive replacement
fields, date order, the tentative shape, reserved via names, http(s)
sources, the RFC 3339 profile, string limits), lists the rules only
code can check, and adds a non-normative section on reference checker
behavior. The publisher-fallback wording in SPEC.md, README.md, and
CONTRIBUTING.md now matches the code: only when the publisher has a
shutdown or announced date.

validate reports the code validator's errors first for feeds, as the
loaders do, so its messages stay specific. walkStrings is removed: it
duplicated checks and reported control-character and length errors a
second time under a $.feed. path. A new checkText keeps rejecting
non-string text fields, the one case only walkStrings caught.

Fixes #131.

Implemented by an Opus subagent; reviewed by Claude.
The schema is published in place under the same $id, so it has to work
in validators other than the repo's helper.

- Write the control-character ranges as JSON escapes, so the decoded
  pattern holds the raw characters. Perl read the regex-level \u as a
  literal u and failed every committed feed; PCRE2 and RE2 reject it.
  Use [0-9] instead of \d, which Python matches against Unicode digits.
  The decoded character sets are unchanged.
- Drop the reserved-via lookahead added in the previous commit. RE2 has
  no lookahead. The validator still rejects the reserved names, and
  SPEC.md lists the rule as code-only and defines the comparison as the
  Unicode default lowercase mapping.
- Define shutdown in both tentative oneOf branches so ajv strict mode
  (strictRequired) compiles the schema.
- Print pattern errors with control characters escaped, so a decoded
  pattern never writes raw control characters to the terminal.

Validator messages:

- The root path is $ and unknown keys that are not plain names use
  bracket notation, so a top-level key named feed reports as $.feed and
  a key named $ as $["$"].
- Date errors no longer repeat the path.
- generated is checked with the same date-time rule as the schema's
  format (hours to 23, minutes and seconds to 59), so T24:00:00Z gets
  the validator's message instead of the raw pattern. The schema already
  rejected it, so no verdict changes.

SPEC.md now lists WHATWG URL parsing and UTF-16 length counting among
the rules the schema doesn't check, notes that validators whose $
matches before a final newline are looser and the reference validator
decides, names the config and per-path ways to request a channel, and
says an empty feeds directory exits 2.

No verdict change across committed feeds, every historical feed in git,
the SPEC example, every feed the test suites validate, a 46,985-case
differential fuzz (with and without format), and the reviewer's
code-point substitution, structure, and date sweeps.

Implemented by Claude Opus 5.5; reviewed by Claude Opus (adversarial review).
@thossullivan
thossullivan merged commit 714c991 into main Oct 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SPEC.md does not state several rules the validator enforces

1 participant