Skip to content

Derive schema parity verdicts from a pinned Draft 2020-12 engine #106

Description

@dieterbaier

Problem

The build validates artifact metadata through the Ruby validator
(scripts/validate-metamodel.rb), not through a JSON Schema engine. The schema
in metamodel/artifact.schema.yaml is what consuming projects vendor, so the
two have to reach the same verdict on the same metadata.

#105 added outcome parity for the validity axis: SCHEMA_OUTCOMES in
test/validate_metamodel_test.rb runs fourteen present, empty, and null cases
through the validator and asserts the verdict the schema prescribes. But those
verdicts are written by hand from reading the schema. The test proves that
the validator agrees with a person's reading of the schema, not with the schema.
If the schema changes and the table is not updated, or the reading was wrong in
the first place, the test stays green.

The review of #105 accepted this as a documented limitation rather than a
blocker. This issue is what would remove it.

Why it was not solved in #105

The pinned toolchain (ghcr.io/docs-as-code-toolkit/docs-toolbox:v1.3.1)
declares no JSON Schema engine. It does carry ajv, but as version 6.12.6 at
/usr/share/nodejs/ajv — an incidental Debian package, not something the image
provides on purpose. It does not support Draft 2020-12, which the schema
declares, and it could disappear with any image bump. A guard built on it would
look deterministic while resting on nothing.

Goal

Compute the parity verdicts with a real Draft 2020-12 engine from a deliberately
pinned dependency, so a disagreement between the schema and the Ruby validator
fails the build without anyone having to predict it.

Options

Where the engine comes from

  • Add it to the docs-toolbox image (docs-as-code-toolkit/docs-toolbox), for
    example ajv 8 with its Draft 2020-12 entry point and ajv-formats, or the
    Ruby gem json_schemer. Keeps the reproducible container as the single
    toolchain, but needs a toolbox release and a tag bump here.
  • Declare it in this repository, for example a package.json with a pinned
    ajv. This repository currently runs its JS tests with node --test and no
    dependencies, so this would introduce the first one.

Consuming projects run the same toolbox image through
templates/scripts/build.sh, so the first option also reaches them; the second
does not.

How far to take it

  • Parity only: the engine computes the verdicts for the existing case table
    and the test compares them with the Ruby validator.
  • Schema as an executed contract: ./build.sh validate also runs every
    artifact's front matter through the engine. The Ruby validator would then only
    carry what the schema cannot express — retired_on not before created,
    risk-specific retirement reasons, relation targets that must exist — and the
    parity problem would mostly disappear instead of being tested for. Larger, and
    probably its own decision.

Things to decide along the way

  • format: date. In Draft 2020-12, format is an annotation by default.
    An engine only enforces it with format assertion enabled (for ajv, through
    ajv-formats). Without that, the engine would accept retired_on: "" while
    the Ruby validator rejects it — parity would fail for a reason that is a
    configuration choice, not a defect.
  • Local mode. With DOCS_TOOLBOX_LOCAL=1 the host toolchain may not have
    the engine. The test must then fail or skip with an explicit message. It must
    not silently pass, or it becomes a guard that reads like coverage and checks
    nothing.

Acceptance criteria

  • A Draft 2020-12 JSON Schema engine is available at a pinned version from a
    declared source, not an incidental one.
  • The parity test computes each case's verdict by running the engine against
    metamodel/artifact.schema.yaml and compares it with the Ruby validator's
    verdict. Hand-written expectations are gone, or kept only as readable
    documentation next to the computed ones.
  • Changing the schema so that a case's verdict flips fails the test without the
    test being edited, and changing the validator the same way fails it as well.
    Both are demonstrated, not assumed.
  • Format assertion for format: date is enabled, or the resulting mismatch is
    documented as a known exception with its reason.
  • Local-mode behaviour without the engine is explicit: a clear failure or a
    visible skip, never a silent pass.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions