Namespace Policy
Every package name in the index is always two-level: <namespace>/<package>. This page documents what a namespace identifies, its charset, the reserved segments, and how claims and disputes are handled. Design authority: adr_namespace_policy.md.
What a Namespace Identifies
A namespace names an identity — an organisation, business, or open-source project — never a hosting location, registry, or physical repository path. It is host-irrelevant: kitware/cmake stays kitware/cmake even if the physical mirror moves to a different registry entirely.
A namespace should preferably match a GitHub org the vendor controls, or another online identity the vendor demonstrably holds, but this is a preference a reviewer weighs at claim time, not a hard rule enforced by CI — there is no automatable check for "this real-world entity approves of this namespace".
There is no privileged root namespace (no Docker Hub library-style bare tier). Every package always has a two-segment name, so no namespace ever gets opaque, un-auditable admission.
Charset and Shape
Two distinct regexes exist and are never interchangeable:
OCX package-id regex (governs the logical <namespace>/<package> name — the entry's name field and its p/<namespace>/<package>.json source path): exactly two lowercase segments, one / separator, total string length ≤ 140 characters. Validation is length-cap-then-fullmatch.
- namespace segment: lowercase-folded GitHub-login pattern,
^[a-z0-9](?:-?[a-z0-9])*$, 1–39 characters. - package segment: the OCI distribution-spec repository-component grammar,
[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*, ≤ 100 characters. - 39 + 1 (
/) + 100 = 140 — the combined cap is the sum of the two segment caps, not an arbitrary number.
OCI repository regex (governs the physical repository field, e.g. ghcr.io/ocx-contrib/cmake): the full distribution-spec grammar, [a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(\/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*, which permits N segments, not two.
Both grammars are ASCII-only in v1 — there is no identity provider here to justify the homograph-attack surface Unicode namespaces would open.
Reserved Segments
The following values are rejected at claim time, checked against both the namespace and the package position. Claim time is literal: the check fires when a PR adds a p/<namespace>/<package>.json that does not exist on main. A later PR that only refreshes an already-committed entry's tags is not a claim and is not re-gated — ownership of an existing entry is enforced by its owners[], which is the control that belongs there. Changing an existing entry's repository, owners, status, deprecated_message, or a yank marker is neither a claim nor a refresh: those stay blocked for anyone without write access to this repository.
| Category | Segments | Why reserved |
|---|---|---|
| Control paths | p, o, c, docs, assets, config, schema, api, static, data | Top-level directories in the index git tree and/or top-level URL paths on the colocated index.ocx.sh deployment. o specifically is the CAS-objects marker inside every package's own subtree — a namespace or package segment equal to o would make that path ambiguous to a tool doing prefix matching. c is the top-level enumeration-index segment (/c/index.json) — reserved for the same routing-collision reason. |
| Brand | ocx, ocx-sh, ocx-contrib, ocx-rs | OCX's own project and org identities. |
| Generic/ambiguous | admin, root, system, std, core, official, public, test, example, internal | Words whose plain-English meaning implies a privileged or non-existent-vendor status the two-level model refuses to grant. |
This list is deliberately small and collision-driven, not an exhaustive trademark denylist — it blocks what actually collides with the wire contract or the site; everything else is adjudicated case by case (see Dispute Policy below).
First-Claim Governance
A new namespace is claimed by opening a PR that adds the first p/<namespace>/<package>.json entry under it. This is a mandatory human review, blocking auto-merge (see Governance Contracts G-04). No new CI check exists beyond the schema/semantic validation every entry gets — the reviewer's job is to judge whether the claimed namespace plausibly fits the identity it names.
Registry-write ownership (does the physical registry content match what the entry claims) is a separate, fully automated check — it proves physical control, not real-world vendor identity, which is why the human step stays load-bearing. See Claim a Namespace for the step-by-step procedure.
Dispute Policy
Adopted from the crates.io/npm precedent, verbatim, no new workflow:
- First-come, first-claim. No reservation system, no pre-claim application process.
- Squatting test: a claim with no genuine function (dead entry, name held with no package behind it) is treated as squatting on request — the current owner is contacted first; a maintainer adjudicates if that fails.
- No proactive squatting police. Reviewers do not preemptively hunt for or block plausible future namespace claims; disputes are handled reactively, on complaint.
- Transfer goes through the always-human-reviewed
owners[]field path — the same review gate as any other ownership-affecting change. - No rename primitive. A namespace is immutable once claimed. Migrating a package to a different namespace means claiming the new
<namespace>/<package>entry fresh (subject to the same first-claim review) and deprecating the old one (status: deprecated+deprecated_messagepointing at the new name). The old namespace is not reclaimable by moving it.
owners[].github_id
Mandatory, not optional, on every entry. The numeric id survives GitHub username renames and account takeovers of a since-freed login; the login string alone does not. github still exists for human-readable display; the id is what any ownership check keys on.
Upstream Attribution
The upstream object (org, optional repository_url, optional disclaimer) is mandatory on every entry whose namespace names a real vendor identity mirrored by a third party — in practice, every one of OCX's own seed entries. A claim PR namespacing a package under a real vendor without a populated upstream object fails review. The object is omitted only for OCX's own first-party namespaces (ocx/*), where there is no third-party identity to attribute. See Entry Schema for the exact object shape.