Skip to content

chore: one version, one schema — repository hygiene for 1.0 - #14

Merged
ivvmoreno merged 1 commit into
devfrom
chore/one-version-one-schema
Sep 8, 2026
Merged

ivvmoreno merged 1 commit into
devfrom
chore/one-version-one-schema

Conversation

@trustlayer-foundationuser

@trustlayer-foundationuser trustlayer-foundationuser commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

One version, one schema — repository hygiene for 1.0

The rule applied: the repository presents 1.0 as the version, and only one. With a single exception that is not history but validation authority: schema/aid-v1.2.json stays at its path while a credential in circulation declares it — today, every one issued — because a schema is what issued credentials validate against, and that path is cited from the W3C DID Method Registry. No document speaks of a "preview line" or of "legacy"; the pre-1.0 history lives in the CHANGELOG under its own heading and in the private bundle.

Removed

What Why
spec/legacy/ (2 files) Pre-1.0 prose. It is in the private bundle.
schema/aid-v1.1.json, schema/aid-v1.3.json No live credential declares 1.1; 1.3 was never issued against. (aid-v1.2.json stays: credentials in circulation declare it.)
examples/aid-example-v1.1.json Example of a schema with no live credentials. (aid-example-v1.2.json stays beside its schema.)
— The pre-1.0 CHANGELOG entries stay, under "Before 1.0 (pre-release)": a changelog is history and we do not rewrite it.

Renamed and rewritten

Before Now Detail
schema/aid-v1.2.json schema/aid-1.0.json $id and title at 1.0; spec_version const "1.0"; legalName as an organization name with the natural-person rule (COM-09, L0-03); descriptions without version numbers.
examples/aid-example-v1.2.json examples/aid-example.json spec_version: "1.0". Illustrative: its proof value does not verify, and the README says so.
test/fixtures/valid-aid-v15-compat.json valid-aid-pre-cutover.json Named for what it is rather than for an internal numbering.
SDK fixtures (7) regenerated with pnpm run generate-fixtures Re-signed with the test keys.
examples/atp-policy-example.txt rewritten Four ATP/1 examples: three-segment scopes, fresh=, enforce= mandatory, no qualify/ttl, rate marked informative.
schema/atp-policy-v1.json corrected ttl removed; fresh added (pattern, default 3600 s, floor 60 s); enforce required; req/deny with the three-segment grammar.
schema/intent-declaration-v1.json corrected principal_ref must be a DID (pattern ^did:), never a name — it said "DID or LEI", a neutrality leak inside a schema.
schema/enrollment-manifest-v1.json descriptions No version numbers; the ARIA canonicalisation rather than "JCS", which contradicted invariant 3.
examples/verify-example.ts req: ['commerce:order:*'] It used the dotted form.

Documents

  • README — one Version section, the schema and its example, holderKey required, credentialStatus set on every reissue, Evaluate against the configured policy, and a plain paragraph on what the two AID schemas are for.
  • spec/README — the 1.0 schema; the Legacy section removed.
  • INVARIANTS — §1 rewritten for aid-1.0.json; §11 carries the only rule that holds: the regime is decided by the issuer DID, never by spec_version (the ≥ 1.3 rule would have classified stable 1.0 credentials as pre-release); no link to a private path.
  • DEPRECATIONS — the version-label and file-name rows are gone; the MCP resource URIs are described by what the server serves.
  • CHANGELOG — [1.0.0] extended with this cleanup, and the earlier entries kept under Before 1.0.
  • CONTRIBUTING and CI — no spec/legacy; the neutrality guard excludes only .github, CHANGELOG and DEPRECATIONS.

Added

sdk/verify-ts/test/vector11.test.ts — ATP/1 vector 11 in the form that circulates: the test builds the production composite proofValue (u32be(len) ‖ ML-DSA ‖ Ed25519, base64url) from the fixtures and asserts that tampering with either half is rejected, plus a malformed-length case, and does the same over the separate-field branch the fixtures use. This is the first executable proof that "both halves must pass" is true.

Four corrections made while reviewing this change

The policy schema forbade what ATP/1 requires be ignored. Dropping qualify and ttl while keeping additionalProperties: false turns a reservation into a rejection: a policy carrying qualify= became invalid, where §3 says an unknown parameter is ignored unless written with a leading !, and DEPRECATIONS.md repeats that in this same change. The schema now permits additional properties, declares qualify as reserved so the name stays visible, and states the rule in its own description. ttl stays out: it is retired, not reserved.

The legalName rule was not enforceable and was presented as if it were. aid-1.0.json is the v1.2 shape with a different const: same fields, same required list. The prohibition for natural-person principals lived in a description, with no if/then and nothing a validator reads — and invariant 1 says the schema is the authority and the prose is description. It is now stated as what it is: an issuance rule, with the reason JSON Schema cannot express it (nothing in the document distinguishes an organization from a person), who enforces it, and what a schema-valid but non-conformant document means.

No fixture had the shape the registry issues. The seven regenerated ones declare 1.0, the compatibility fixture declares none, and production issues 1.2 with a composite proofValue. The generator now emits valid-aid-production-form.json in that exact shape, and three tests exercise it: that it verifies, that parseCredential reads the real spec_version, and that revocationStatus comes back unknown. Suite: 51 passing. This absorbs the follow-up the change document left for a separate pull request.

The stable schema is published as a draft, not frozen. Nothing declares 1.0; the Verification Requirements it serves are still v1.3-draft with ten decisions open at TrustLayer Foundation; and fields already planned — a designated successor principal among them — have no place in it. Because credentialSubject declares additionalProperties: false, admitting one later costs a new file and a new spec_version. It is published to be implemented against and freezes the day the first credential declares 1.0. Stated in the file's _status, in invariant 1 and in the README.

No _comment was added to the example: the schema root declares additionalProperties: false and it would have made the example invalid. The warning that its proof does not verify lives in the README.

Kept on purpose, and why it is not stale

Item Reason
context/v1.jsonld with "@version": 1.1 The JSON-LD 1.1 processing mode, a W3C standard, not an ARIA version. Changing it would break the context.
sdk/verify-ts/package.json at 1.1.0 The npm package's semver, independent of the protocol; npm does not allow going backwards.
schema/*-v1.json v1 is the schema's major version, consistent with ARIA 1.0.
schema/aid-v1.2.json and its example Validation authority for the credentials in circulation; the path is cited by the W3C. Retired when the last one expires or is revoked.
pre-cutover comments in the SDK Production still issues the earlier spec_version until the cutover, and the verifier has to keep accepting those credentials.
termsVersion and privacyVersion in the example Versions of the registry's Terms and Privacy Policy, not of the protocol.

Dependency on the backend

The 1.0 schema declares spec_version: "1.0"; production still issues "1.2", and those credentials validate against aid-v1.2.json, which stays published. The SDK accepts both. On the day of the cutover, issuance moves to 1.0 with no change here; the 1.2 schema is retired when the last credential declaring it expires or is revoked.

Checks

Five green. Suite 51 passing. Neutrality guard clean.

The repository presented four AID schemas, a legacy prose directory and a
changelog whose first entries described labels that were reclassified as
previews. It now presents 1.0, with one exception that is not history but
validation authority: aid-v1.2.json stays at its path while credentials in
circulation declare it, because a schema is what issued credentials validate
against and that path is cited from the W3C registry.

Retired: the 1.1 and 1.3 schemas and the 1.1 example, which no live credential
declares; spec/legacy, whose prose is not validation authority. The changelog
keeps its history under Before 1.0.

Corrected in artefacts nobody had opened since they were written: the policy
schema carried qualify and ttl, the intent schema let principal_ref be a name
rather than a DID, the manifest schema said JCS where the canonicalisation is
not JCS, and the policy example used dotted scopes.

Four things came out of reviewing the change itself. The policy schema, having
dropped qualify while keeping additionalProperties false, turned a reserved
name into a rejected one - ATP/1 ignores what it does not understand unless the
name is critical, and DEPRECATIONS says so in this same commit. The legalName
prohibition was presented as a schema rule while living in a description that
no validator reads; it is an issuance rule and now says why the schema cannot
express it. No fixture had the shape the registry issues, so the generator now
emits one with the composite proofValue and the spec_version production
declares, and three tests exercise it. And aid-1.0.json is published as a draft
until the cutover: nothing declares 1.0, the requirements it serves are still a
draft with ten decisions open, and additionalProperties false means a planned
field arriving later costs a new file and a new version.

Vector 11 is now a test rather than something two people ran by hand: a
credential with one half of the composite signature altered is rejected, in
both directions, in the production form and in the fixture form. Suite 51.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>
@ivvmoreno
ivvmoreno merged commit 29c1f84 into dev Sep 8, 2026
5 checks passed
ivvmoreno pushed a commit that referenced this pull request Sep 8, 2026
* release: one version, one schema, and the schema corrections

Publishes what was reviewed in #14. Two artefacts on the default branch said
things the specification does not: schema/intent-declaration-v1.json described
principal_ref as a 'DID or LEI', naming a commercial entity-credential scheme
inside a schema, and schema/atp-policy-v1.json still declared qualify and ttl as
ordinary parameters where one is reserved and the other retired.

The repository now presents 1.0, keeping schema/aid-v1.2.json at its path
because credentials in circulation declare it and that path is cited from the
W3C registry. aid-1.0.json is published as a draft until the cutover and says so
in the file. The legalName prohibition is stated as an issuance rule, since
nothing in the document distinguishes an organization from a person and no
validator can enforce it. The fixture generator emits the composite proofValue
shape the registry actually issues, and vector 11 is a test rather than
something two people ran by hand.

Branched from main rather than merged from dev: main carries #13 as a squashed
commit, so dev's original commits are not its ancestors and a merge conflicts on
history that is already published. The trees are identical to dev.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* fix(ci): let release branches pass the naming check

The convention names the branches where work happens. A release pull request
comes from dev or from release/<topic> and failed the check every time, which
is a red cross on the one pull request that publishes.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

---------

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>
ivvmoreno pushed a commit that referenced this pull request Sep 8, 2026
* release: documentation aligned with the published specification, dependency bot retired (#13)

* docs: correct the issuer regime rule and five claims in the README

INVARIANTS 11 said the regime was determined by spec_version, with 1.3 and
above meaning the stable line. The stable line carries 1.0, numerically below
the preview line's 1.2, so that rule classified stable credentials as previews.
The regime is determined by the issuer DID in the accreditation list, which is
what the README already said twice and what verifiers must use.

INVARIANTS 1 listed aid-v1.3.json alongside the two schemas that describe
credentials that exist. It is a draft from the earlier numbering that nothing
was ever issued against; the stable file is aid-1.0.json, re-cut at the
cutover. The README schema table now carries the same row.

INVARIANTS 12 documented that the reference SDK checks revocation per DID
rather than through the aggregate Status List. It now says what that costs: a
per-DID call tells the registry which agent a verifier is asking about, which
is the phone-home the specification warns against. Moving the SDK to the
aggregate list is [PLANNED]; both endpoints keep answering meanwhile.

INVARIANTS 4 linked to a private path from a public document.

README: the classical half is Ed25519, not ECDSA, so the sunset is the end of
the composite mode. The holder key is generated by the controller on its own
machine, never delivered by the registry - the code path that would have
delivered it exists and has no callers. The holder proof cannot be checked
today, so it says so. Superseded and revoked are different states sharing one
bit. The receiver evaluates its configured policy, the one it publishes. The
seven days is the freshness of the sanctions lists, not of the sanction. The
Interaction Log is in section 7 and is planned, not section 05 of a numbering
that no longer exists.

The neutrality guard now catches ECDSA on its own, not only ecdsa-p256.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* chore: remove the scheduled dependency bot

Adding it opened eight pull requests in one minute, among them major bumps of
both cryptographic dependencies - a bot proposing to change the signature suite
that INVARIANTS fixes and that credentials already signed depend on. Narrowing
the configuration reduced that to one grouped pull request, which is better and
still not what this repository needs.

Three runtime dependencies do not need a schedule. Security advisories arrive
through Dependabot alerts, which are enabled; version updates become a pull
request with a reason, like every other change. CONTRIBUTING says so.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* fix(ci): check the author's commits, not the merge commit

On a pull request, github.sha is the ephemeral merge commit GitHub builds. It
carries no Signed-off-by because nobody wrote it, so the guard failed every
pull request for the absence of a trailer on a commit that has no author. It
now walks the head ref.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* chore(sdk): raise vitest to 3.2.7, closing the critical advisory

Enabling security alerts surfaced thirteen, all of them in the test toolchain
and none in what the package ships: the three runtime dependencies are the
@noble libraries and they are clean. The critical one is a Vitest UI server
that reads arbitrary files, fixed in 3.2.6.

Raised to the minimum that closes it rather than to latest, which is a major
and would be a decision of its own. Four advisories remain in the vite and
postcss chain below vitest; they reach a developer running the test server, not
a consumer of the published package. Test suite green at 42.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* docs: read every document in the repository against the published site

The SDK README is the npm front page and it was the worst of them: FINANCIAL
asks for L2 and SOVEREIGN for L3, not L1 and L2 as the table said; the presets
were presented as based on named regulatory standards, which is a conformance
claim we do not make; the policy example showed maxOfflineAge null, the setting
that lets a revoked credential keep passing; a real company was named as the
impersonation example; and nothing on the page told a reader that valid says
nothing about revocation. The trust level table now carries PLANNED, because
only L0 is issued and a preset asking for L1 rejects every credential that
exists.

conformance/README.md listed a manifest-validation vector file and a harness
directory that do not exist, and said the case set already keeps four
independent SDK implementations byte-identical. There is one published SDK. The
missing files are now listed as missing, the composite-signature vector among
them, and the same sentence in INVARIANTS 3 is corrected.

spec/README.md said 27 sections and cited section 05; the specification has 12
normative sections and 5 appendices and ATP is section 8. DEPRECATIONS pointed
Trust Seals at section 26, retired in the restructure. SECURITY said the
Technical Steering Committee ratifies emergency fixes; it is not seated until Q4
2026. The last identity-assurance-level equivalence left in the SDK is gone.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

---------

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* release: one version, one schema, and the schema corrections (#16)

* release: one version, one schema, and the schema corrections

Publishes what was reviewed in #14. Two artefacts on the default branch said
things the specification does not: schema/intent-declaration-v1.json described
principal_ref as a 'DID or LEI', naming a commercial entity-credential scheme
inside a schema, and schema/atp-policy-v1.json still declared qualify and ttl as
ordinary parameters where one is reserved and the other retired.

The repository now presents 1.0, keeping schema/aid-v1.2.json at its path
because credentials in circulation declare it and that path is cited from the
W3C registry. aid-1.0.json is published as a draft until the cutover and says so
in the file. The legalName prohibition is stated as an issuance rule, since
nothing in the document distinguishes an organization from a person and no
validator can enforce it. The fixture generator emits the composite proofValue
shape the registry actually issues, and vector 11 is a test rather than
something two people ran by hand.

Branched from main rather than merged from dev: main carries #13 as a squashed
commit, so dev's original commits are not its ancestors and a merge conflicts on
history that is already published. The trees are identical to dev.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

* fix(ci): let release branches pass the naming check

The convention names the branches where work happens. A release pull request
comes from dev or from release/<topic> and failed the check every time, which
is a red cross on the one pull request that publishes.

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

---------

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>

---------

Signed-off-by: TrustLayer Foundation <github@trustlayer.foundation>
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.

2 participants