Skip to content

OpenMOCA 0.6.0

Latest

Choose a tag to compare

@petecleary petecleary released this 11 Nov 12:17
· 2 commits to main since this release

Hardening from the 10 November 2026 specification review. 0.5.0 was a soft
launch; 0.6.0 is the first release published to npm, NuGet and PyPI.

Added (Sigstore conformance cases)

  • Attestations §6: a Reader may verify Sigstore offline only, against
    trustedRoot alone; hosts refresh it themselves. The Python and .NET
    Readers now verify Sigstore this way, so all three pass the sigstore-*
    cases.

  • Seven sigstore-* cases: signed, reviewed, an identity that is not listed,
    the wrong role, tampered content, a transparency-log entry that does not
    match, and an untrusted CA. The bundles are made against a self-made test
    Sigstore with INSECURE keys (scripts/sigstore-fixtures.py), verified
    offline with the trusted root in each fixture trust root, and checked with
    both sigstore-js and sigstore-python. Nothing is written to a public log.

  • A Sigstore smoke test against the public instance, ready for after the move
    to openmoca: sigstore-smoke/, scripts/sigstore-smoke.mjs and a
    hand-run workflow that signs only in the openmoca organisation. It is not a
    corpus case.

  • Cases can name the optional features they need (requires), and the
    runner skips them with --without <feature> for a Reader that names the
    feature as not implemented (Reader contract §14).

Changed (Ed25519 and Sigstore trust material)

  • Strict Ed25519 (attestations §5): A and R must be canonical points of prime
    order, and S < L, checked before any library verifies. Before, the three
    reference Readers' libraries disagreed on 4 of the 12 ed25519-speccheck
    vectors, and Python accepted a signature from a small-order key for any
    message. New cases signature-small-order-key and
    signature-mixed-order-key.
  • Sigstore trust material (attestations §6): a trust root may carry
    sigstore.trustedRoot; with it, Sigstore bundles are verified against it
    alone, offline. Issuer matching names the Fulcio extension OIDs; there are
    no patterns. An unusable trusted root is A003.

Changed (wording and structure)

  • Requirements that were written as description now use MUST or MUST NOT,
    and "throw" is replaced by a testable rule (contract §5). The terms table
    in package spec §2 adds digest, attestation, trust root, sidecar, overlay,
    backend, citation record and the gate, and states how codes are cited.
  • One name for each idea ("locale representation", "package source"),
    "Reader" capitalised, UK spellings, no hyperbole or informal wording.
  • The AG-UI document has the same header as the others and is no longer
    marked Draft. The sidecar table lists indexVersion and createdBy, and
    model is a MUST with its code. Package spec §13.1 points at the limits,
    and §1.1 at the ADRs for rationale.

Changed (small specification gaps)

  • The frontmatter block's grammar (package spec §5.1): BOM, the --- lines,
    LF and CRLF only, and ... never ends it. New cases
    frontmatter-close-after-cr and frontmatter-close-line-separator.
  • Strict mode's effect on validity; the record's profiles field; evidence
    source extensions compared in ASCII (Reader contract §7, §11).
  • Sidecars: indexType is lexical, dense or hybrid (sparse is gone);
    inline vector is accepted until 1.0.
  • AG-UI: an optional computedAt says when the trust flags were true.
  • Attestations §3 says the package predicate may give way to OpenSSF Model
    Signing. ADR-0009 notes that HTML and WebVTT are now normalised.
    composed and localized are explained.

Changed (characters, names and edge cases)

  • Package spec §2 says what digits, letters, white space, case-insensitive
    comparison, string order and the end of a string mean, everywhere in the
    set. Each Reader now follows it: Python and .NET regular expressions and
    trims had other meanings (non-ASCII digits in dates, a trailing newline in
    vendor keys, U+FEFF in type, a dotless ı in index.md).
  • M007 uses a snapshot of the IANA URN registry
    (data/urn-namespaces.json) and accepts
    informal namespaces.
  • A package id never contains #; the node reference's parsing rule is
    stated. relation.version must be a semantic version. A type of only
    white space fails the node schema too. Language tags are those that start
    with a language subtag.
  • Stored (uncompressed) archive entries are checked for size and CRC-32 like
    deflated ones. The x- key grammar, reserved-name matching, the evidence
    limit per representation, a BOM in evidence sources, Markdown marker
    indentation, an empty media start, hybrid weights and ties with no span are
    specified.
  • New cases archive-stored-size, date-non-ascii-digits,
    vendor-key-trailing-newline, reserved-name-ascii-only,
    type-white-space, manifest-id-fragment and
    relation-version-not-semver.

Changed (decisions on folding, digests and applications)

  • Path collisions use simple lowercase mapping, not Unicode case folding
    (package spec §6.3).
  • Digest strings keep their form; mocaVersion says which algorithm applies
    (ADR-0021).
  • Rules for applications and hosts are advice (SHOULD); the AG-UI client
    rules stay MUSTs (ADR-0022).

Changed (the document set, model handoff, privacy, traceability)

  • The document set (package spec §1.1): the status of each document, what it
    binds, and one order of precedence. Rules duplicated across documents now
    link to one home. What an implementation leaves out are "optional
    features", not "capabilities", and the Reader interface's "every case"
    matches the contract.
  • Handing content to a model (Reader contract §12): "package-supplied text"
    is every string from a package. It goes to a model inside an escaped
    envelope (JSON recommended). Applications link only http and https, and
    never load remote resources that package text names. An AG-UI service cites
    only records its Reader returned during the run.
  • Personal data (package spec §13.6): which fields can hold it, that a
    published version cannot be redacted, and pseudonymous identifiers.
  • Traceability (conformance/README.md): a table from each group of
    requirements to its cases, a list of rules the corpus cannot test, and
    scripts/check-traceability.mjs in npm run validate. New corpus options
    strict and expect.contested; new cases strict-promotes-warnings,
    strict-other-families, search-relation-conflict,
    search-relation-conflict-unauthorised, search-dense-version-mismatch
    and search-dense-dimension-mismatch.

Changed (versioning and schema patterns)

  • Versioning (package spec §14): the document set is versioned as one
    release, which is "the contract version". mocaVersion is compared
    numerically; M008 applies only below 0.4; a newer mocaVersion is read
    on a best-effort basis with the new M009_MOCA_VERSION_NEWER (warning). A
    table says when schemas/v1, the predicate types, indexVersion, the
    AG-UI version and the digest algorithm change.
  • Schema patterns mean the same in every regular-expression engine: [0-9]
    for \d, ECMAScript's white-space list for \s, and (?![\s\S]) for a
    final $ (package spec §2). Before, a trailing newline passed in Python and
    .NET, and non-ASCII digits passed in Python. New cases
    moca-version-newer, moca-version-leading-zeros,
    moca-version-trailing-newline, moca-version-non-ascii-digits and
    manifest-id-unicode-space.

Changed (structure, composition and retirement)

  • Composition (package spec §7.1.1): resolution order, the cycle rule behind
    R003 (keyed on id@version, checked before the resolver is called),
    member identity, trust and capabilities, and how a library adds members.
    New limits maxMemberDepth (8) and maxMembers (256): a member past
    either is not resolved (R001).
  • Retirement signals (package spec §5.5,
    ADR-0020): one table of
    what each signal sets and whether it is left out by default. Structure
    never hides content. supersedes means the whole target package.
  • Structure (Reader contract §10): the shape of the concept() result,
    traversal over cycles (each concept once, never the start), and overlays
    never change a package's capabilities, validity or diagnostics. Overlays
    add concepts and relations; "vocabulary" is dropped. New case
    structure-op-requires-cycle.

Removed

  • structure.json (ADR-0019):
    structure.ttl is the only structure file. A structure.json is an
    ordinary package file that no Reader checks. O004_STRUCTURE_VIEW_MISMATCH
    is retired. The corpus case structure-view-mismatch becomes
    structure-json-ordinary-file, and examples/service-catalogue no longer
    ships the file. structure.schema.json stays, as the shape of the view
    moca-lint structure prints.

Added (decision records)

  • ADR-0015 to ADR-0020 record the 0.6 decisions on relations, audience,
    reviews, ranking, structure.json and retirement signals.

Added

  • Conformance cases for unsafe and malformed paths (unsafe-path-absolute,
    resource-bad-escape), a trust root with empty roles, a 30,000-concept
    requires chain, unparseable dates and actorless entries, a log.md heading
    in a code block, moca.json that is not UTF-8, a top-level file named
    attestations, a package composing another version of itself, and the first
    T001, T002 and T003 cases (a missing target, a target with no
    moca.json, and archive entry and byte limits).
  • Attestation cases, one fault each: wrong payload type, a payload that is not
    JSON, a payload that is not an in-toto Statement, no signatures, a signature
    with no keyid, a statement naming another version, an untrusted and a
    trusted signature together (valid), base64url (valid), an unknown predicate
    type (ignored), and a review naming another package.
  • Date cases: a key at and one second before its expiry, window intersection,
    date-only bounds, a date-time without an offset and an inverted window. Every
    case with a trust root now sets options.now, so the corpus no longer
    starts failing when the fixture keys expire in 2031.
  • Relation authority cases: an unauthorised and an authorised relation, an
    unsigned, an out-of-scope and a no-boundary relation in search, and the host
    option. The search-policy/v2 fixture and the policy-corpus 2.0.0 example
    are now signed, and the publisher keys in the fixture and example trust
    roots have ids.
  • Audience cases: unlabelled, allowed unlabelled, malformed labels (a list and
    a number), the gate on its own, and a translation that inherits its label.
    The search-policy fixture's stale.md is now labelled public.
  • Review cases: an inaccurate review, the latest review winning, reviews in an
    unsigned package, a review dated in the future, and a reviewer the key may
    not sign as; the runner checks expect.reviewStatus.
  • A store case where a package is superseded after its records were ingested
    (ingestSeparately).
  • Cases for requireSignature (unsigned, tampered, signed) and an identity
    conflict; signature-tampered now expects A008.
  • Limit and archive cases: the evidence budgets, the directory entry limit,
    and zip fixtures for names that are not UTF-8 or hold NUL, empty and .
    segments, a duplicate entry, a symbolic link and bzip2 compression.
  • Determinism cases: an archive with %, #, CR and LF in paths, repeated keys in
    moca.json, a statement and frontmatter, and locale fallback for fr-CA,
    pt and a mixed-case tag.
  • A sidecar whose item text differs from the package, and a gate case for a
    node in several languages; a one-sided prefix is now S006. 166 cases in
    all.

Changed

  • Attestations §7 is now a numbered verification algorithm with one outcome
    for each step. A003 means only that a check was not possible (no trust root,
    or for Sigstore no identities or no Sigstore support); a key or identity that
    is unlisted or has the wrong role is A002, as the corpus already expected.
    The signer string, the base64 and base64url rules, Ed25519's S check and
    the one-valid-signature rule are written down.
  • Sidecars and search (ADR-0018): a sidecar item's text
    must be the package's bytes at its span, inside the body (S004), and
    search reads only the package; a one-sided embedding prefix is S006; the
    built-in lexical tokeniser and the default ontologyGuided hook are
    specified; the gate keeps one result per representation and span, and
    limit defaults to 5; Reciprocal Rank Fusion is now the informative
    reference hybrid backend, with the digest as the last tie-break; sidecar
    §5.1 is "Embedders the MOCA tools support"; sidecar §5.2 adds security
    considerations and §6 defers to the store-backend rules.
  • Determinism: digest lines sort by the NFC path before
    percent-encoding (as the Readers already did); moca.json and statements
    are I-JSON (repeated member names are M001 and A001), and repeated
    frontmatter keys are C002; OKF v0.2 is pinned to a commit; links and
    resources resolve relative to the node file, with the rules written down;
    locale fallback follows RFC 4647 Lookup, then the lowest longer tag, case-
    insensitively; evidence quotes are normalised like their sources, and a
    position selector alone is not checked; contract §7 gains a table of how
    each record field is derived and says consumers ignore unknown fields;
    P003's wording matches the package spec; ADR-0004 no longer claims
    capabilities are in the record.
  • Limits and archives (Reader contract §3, review B9 and M6): every source
    has the entry and byte limits, directories included, and a host source's
    bytes are counted as read. Evidence work is bounded per package (new
    maxEvidenceChecksPerPackage and maxEvidenceBytesPerPackage), each source
    is normalised once, and a quote is matched in one pass: a few kilobytes of
    archive can no longer keep a Reader busy for hours. Archive rules are
    normative: UTF-8 names, no NUL, empty or . segments, duplicates collide,
    links are unsupported, only stored and deflated entries are read, entries
    never inflate past their declared size. The limits table names each option,
    and its outcomes are normative. Package spec §2 says how a MUST maps to a
    diagnostic's severity, and §6.2 forbids writing or extracting hidden
    entries.
  • Identity and tampering (review M2, M3): a library refuses a second digest
    for one id@version (new L001_IDENTITY_CONFLICT); an attestation for this
    id@version with another digest is A008_PACKAGE_DIGEST_MISMATCH; a resolved
    member must match its pin's id and version; readPackage takes
    requireSignature (new A009_SIGNATURE_REQUIRED, which invalidates). Package
    spec §13.5 covers rollback, frozen copies and two digests for one version.
  • Store search (contract §9.4, review B2): a store search takes the loaded
    packages' states, not bare digests, and recomputes supersession, contest,
    signatures and reviews at query time. Before, a package superseded after
    ingest, or a key removed from the trust root, was still served as current or
    signed. The store is declared a trusted component.
  • Reviews (ADR-0017): reviewed needs a signed package with every
    reviewed page approved. Citation records gain trust.reviewStatus
    (approved, disputed, unverified, none) and each review's
    packageVerified; review outcome is an enum in the record schema. The
    latest review from each signer counts, a review dated after the clock is
    ignored (new A007_REVIEW_DATE_FUTURE), and trust-root entries may list the
    reviewers they may sign as. Attestations §4 says that a missing review is
    not evidence, and recommends listing cited evidence files as subjects.
  • Audience (Reader contract §8, ADR-0016): under a host audience set,
    unlabelled content is left out unless the host sets allowUnlabelled, and a
    malformed label (now marked audienceInvalid in the citation record) never
    matches. A translation with no label has its default-language
    representation's. Reader interface §7: bindings apply the audience set and
    the default policy to every record they hand to a model or user, and the
    opt-ins are host configuration, never tool arguments.
  • Relations (package spec §7.2, ADR-0015): supersedes and
    conflictsWith take effect only when the declaring package has a valid
    package attestation from a key or Sigstore identity whose new ids cover the
    target's id; otherwise they are reported (R004_RELATION_UNAUTHORISED,
    info) and have no effect. A host option, off by default, applies unsigned
    relations. Before, any loaded package, signed or not, could remove another
    publisher's content from default search.
  • Dates (package spec §4.4): a full date means 00:00Z; a date-time needs an
    offset, and one without is reported and ignored rather than read in some
    time zone; validFrom is inclusive and validUntil exclusive. A node's
    window is the intersection with its package's, and an inverted window is
    ignored. Keys expire at the instant of expires against the host clock,
    which readPackage now takes (Reader interface §3); attestations §6 states
    the trade-off and the advice to re-sign.
  • Trust roots: roles is required on every key and identity (an empty list
    trusts nothing), keyids are unique, and Sigstore issuer and subject match
    exactly (MIGRATIONS.md).
  • SECURITY.md no longer describes a skills gate: MOCA has no skills mechanism
    since 0.4, and package content is never loaded as skills, prompts or tools.
  • Every specification document now defines its requirement key words
    (RFC 2119 and RFC 8174) and points to the package specification's terms. The
    AG-UI citations document has the same header as the others.
  • Reader contract §4 states its prohibitions as MUST NOT requirements.
  • Worked examples in the attestations, sidecar and Reader contract documents
    use the real support-kb values: its digest, signer names and spans.
  • Sidecar specification §6 is called "Store backends", as in the Reader
    contract and interface.
  • Smaller wording fixes: two garbled sentences, UK spellings, and terse table
    entries.