Skip to content

spec: introduce OpenAPM v0.1 (closes #1502)#1517

Merged
danielmeppiel merged 8 commits into
mainfrom
feat/openapm-v0.1-spec
May 28, 2026
Merged

spec: introduce OpenAPM v0.1 (closes #1502)#1517
danielmeppiel merged 8 commits into
mainfrom
feat/openapm-v0.1-spec

Conversation

@danielmeppiel
Copy link
Copy Markdown
Collaborator

TL;DR

Introduces OpenAPM v0.1 as a single normative specification document at docs/src/content/docs/specs/openapm-v0.1.md (2678 lines, 87 normative statements). It is an editor's draft, MIT-licensed, vendor-neutral, and self-contained: a third-party integrator can build a conformant implementation without reading any other APM doc.

OpenAPM v0.1 pins the contract surface that current and future integrators (JFrog and others) consume, isolating us from URL-level churn in the reference implementation. It reflects in-scope work merged this cycle (#1494 require_pinned_constraint, #1495 apm deps why, #1496 git-source semver) and explicitly excludes the closed-YAGNI work (#1497).

The artifact passed two rounds of adversarial review by four expert personas (OpenAPI/Swagger editor, OCI Distribution editor, npm/cargo registry contract editor, W3C TAG architect) plus an editorial fold pass. Round-2 verdict: unanimous ship_with_followups at shocked_meter 8/10, zero new blocking findings.

Closes #1502.

What's in v0.1

Section Surface
1 Goals, non-goals, relationship to existing docs
2 RFC 2119 + 8174 keyword discipline
3 Terminology
4 Manifest format (apm.yml) -- schema in Appendix A
5 Lockfile format (apm.lock.yaml) -- canonical git-tree integrity hash (s5.6.4), hash-envelope discipline (s5.2), monotonic lockfile_version (s5.4)
6 Policy format (apm-policy.yml) -- discovery providers, inheritance, tri-state allow/deny
7 Dependency resolution -- node-semver dialect pinned verbatim (s7.3.1), tri-modal transitive conflict policy (s7.4), mirror-by-hash retrieval (s7.5.1), producer release contract (s7.8)
8 Primitive type system + target matrix
9 Versioning + amendment process
10 Security considerations -- every threat maps to a req-XXX
11 Conformance -- four classes (Producer / Consumer / Registry / Governance)
12 Conformance test methodology -- statement-anchored + fixture-anchored binding, CI-binding MUST-for-claim (req-cf-002)
Appendix A Inline JSON Schemas (Draft 2020-12)
Appendix B Registry HTTP API (reserved v0.2)
Appendix C Canonical 87-statement index
Appendix D Revision history
Appendix E Editorial reconciliation notes

Conformance classes

Class Who it binds
Producer tool that emits apm.yml + apm.lock.yaml + pack archive
Consumer tool that installs, resolves, audits
Registry service that serves resolved bytes by hash
Governance tool that authors / enforces apm-policy.yml

Fixture seed

tests/fixtures/spec-conformance/ (10 files + README):

  • manifest/: valid-minimal, invalid-missing-name, x-extension-roundtrip, invalid-no-source-key
  • lockfile/: v1-git-only, v2-with-registry, round-trip-unknown-fields
  • policy/: valid-extends, invalid-extends-cycle
  • resolution/: semver-dialect.json (13+ cases including pre-release opt-in and build-metadata ASCII tie-break)

Each fixture carries an Exercises: req-XXX header so the conformance suite can bind assertions to statements deterministically.

Reserved for v0.2 (called out in the artifact)

Workspaces (s4.8); version withdrawal / yank (s7.9); publisher attestations + signatures (s10.12); Registry HTTP API (Appendix B); machine-readable conformance manifest (s12.6); frozen-default flip (s5.5); update --aggressive (s7.7); marketplace authoring output (s4.7); canonical-tree edge cases for symlinks/submodules/LFS (s5.6.4); resolved_by 3+ chain determinism rule (s7.2); git: grammar revision (s4.3.2); reproducible-build determinism (s1.1 non-goal).

Out of scope explicitly

Translations; client libraries in non-Python languages; submission to any standards body (separate strategic decision); the conformance test suite implementation (this PR ships the requirements; the suite is a follow-up); #1497 release-tag automation (closed YAGNI).

Review process and convergence

Two rounds of 4-panel adversarial review (each panelist in its own agent thread, returning structured JSON):

Panel Round-1 verdict Round-2 verdict shocked_meter (R2)
swagger-openapi-editor needs_revision ship_with_followups 8/10
oci-distribution-editor needs_revision ship_with_followups 8/10
pkgmgr-registry-contract-editor needs_revision ship_with_followups 8/10
w3c-tag-architect needs_revision ship_with_followups 8/10

Round-1 closure: 19/21 blocking findings materially closed (1 acceptable defense for provenance per s10.12, 1 clean deferral for workspaces, 1 partial = CI-binding MUST landed as v1.1 fold); 25/26 recommended closed.

Round-2: zero new blocking findings. 15 new recommended + 11 nits clustered into 5 editorial themes (CI binding, internal-consistency drift, reserved-slot defensive MUSTs, determinism edges, secret-hygiene scope). 18-fold editorial pass closed the cluster inside the shipping artifact.

Followup commitments

  • v0.1.1 patch milestone: spec license decision (MIT -> CC-BY-4.0 or W3C SDLN); fixture-tree expansion beyond the 11-file floor.
  • v0.2 milestone: items listed under "Reserved for v0.2" above.

How to review

  1. Read s1 (goals + non-goals + relationship to existing docs).
  2. Read s11 (conformance classes + how to claim).
  3. Skim Appendix C (canonical req-XXX index, 87 rows).
  4. Spot-check s10 (Security) -- every threat MUST map to a req-XXX.
  5. Verify fixture tree at tests/fixtures/spec-conformance/.

Validation

  • ASCII-only: 0 codepoints > U+007E in the spec.
  • No vendor / standards-body claims (CNCF / Linux Foundation / Sandbox / Incubation / W3C Process / IETF RFC stream): grep clean.
  • All 3 JSON Schemas pass jsonschema.Draft202012Validator.check_schema().
  • All 10 fixtures parse (YAML / JSON) and each carries at least one req-XXX cross-citation.
  • Anchor uniqueness: no duplicate id="req-...".
  • Count consistency: s1.3 ("87 normative statements") == Appendix C trailer ("Total: 87 (82 MUST, 5 SHOULD)") == Appendix D revision-history ("83 -> 87") == grep -c '^| \[req-' Appendix C (87).

OpenAPM v0.1 is a single normative specification document at
docs/src/content/docs/specs/openapm-v0.1.md (2678 lines, 87 normative
statements). It pins the contract surface that current and future
integrators consume (apm.yml manifest, apm.lock.yaml lockfile,
apm-policy.yml governance), isolating ecosystem tooling from
URL-level churn in this implementation.

Ships:
- The specification document (87 req-XXX statements, four
  conformance classes: Producer / Consumer / Registry / Governance)
- Inline JSON Schemas (Draft 2020-12) for manifest, lockfile, policy
  at docs/src/content/docs/specs/schemas/
- Conformance fixture seed tree at tests/fixtures/spec-conformance/
  (10 files including semver-dialect resolution oracle, valid/invalid
  manifests, lockfiles across v1 and v2, and policy extends cases)
- CHANGELOG entry

Vendor-neutral (no specific standards body mentioned), MIT-licensed
editor's draft under semver-zero. Self-contained: a third-party
integrator can build a conformant implementation without reading
any other APM doc.

Review process: passed two rounds of 4-panel adversarial review
(OpenAPI/Swagger, OCI Distribution, npm/cargo registry contract,
W3C TAG architect personas). Round-2 verdict: unanimous
ship_with_followups at shocked_meter 8/10, zero new blocking
findings. v1.1 fold pass closed 18 editorial / defensive-MUST /
internal-consistency items surfaced in round 2.

Reserved for v0.2 (called out in the artifact): workspaces (s4.8),
version withdrawal / yank (s7.9), publisher attestations and
signatures (s10.12), Registry HTTP API (Appendix B), machine-readable
conformance manifest (s12.6), frozen-default flip (s5.5),
canonical-tree edges for symlinks/submodules/LFS (s5.6.4),
reproducible-build determinism (s1.1 non-goal), update --aggressive
(s7.7), marketplace authoring output (s4.7).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 27, 2026 16:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces OpenAPM v0.1 as a single, normative specification document in the docs site, along with accompanying normative JSON Schemas and a seed set of conformance fixtures intended to ground requirements in deterministic file-based test inputs.

Changes:

  • Add docs/src/content/docs/specs/openapm-v0.1.md (normative spec with req- anchors and an index of normative statements).
  • Add normative JSON Schemas for apm.yml, apm.lock.yaml, and apm-policy.yml under docs/src/content/docs/specs/schemas/.
  • Add seed conformance fixtures under tests/fixtures/spec-conformance/ and update CHANGELOG.md.
Show a summary per file
File Description
tests/fixtures/spec-conformance/resolution/semver-dialect.json Semver dialect oracle table for spec conformance.
tests/fixtures/spec-conformance/README.md Describes fixture layout and links to spec anchors.
tests/fixtures/spec-conformance/policy/valid-extends.yml Valid policy fixture covering extends + tri-state + pinned constraints.
tests/fixtures/spec-conformance/policy/invalid-extends-cycle.yml Invalid policy fixture for extends-cycle rejection behavior.
tests/fixtures/spec-conformance/manifest/x-extension-roundtrip.yml Manifest fixture for x-* preservation requirements.
tests/fixtures/spec-conformance/manifest/valid-minimal.yml Minimal valid manifest fixture.
tests/fixtures/spec-conformance/manifest/invalid-no-source-key.yml Invalid manifest fixture for dep entry missing a source key.
tests/fixtures/spec-conformance/manifest/invalid-missing-name.yml Invalid manifest fixture missing required name.
tests/fixtures/spec-conformance/lockfile/v2-with-registry.yml Lockfile v2 fixture including a registry-sourced entry.
tests/fixtures/spec-conformance/lockfile/v1-git-only.yml Lockfile v1 fixture for git-only scenarios.
tests/fixtures/spec-conformance/lockfile/round-trip-unknown-fields.yml Lockfile fixture covering unknown field + x-* round-trip.
docs/src/content/docs/specs/schemas/policy-v0.1.schema.json Normative JSON Schema for policy documents.
docs/src/content/docs/specs/schemas/manifest-v0.1.schema.json Normative JSON Schema for manifests.
docs/src/content/docs/specs/schemas/lockfile-v0.1.schema.json Normative JSON Schema for lockfiles.
docs/src/content/docs/specs/openapm-v0.1.md Main OpenAPM v0.1 normative specification document.
CHANGELOG.md Adds an Unreleased changelog entry for the spec publication.

Copilot's findings

  • Files reviewed: 15/16 changed files
  • Comments generated: 9

Comment on lines +29 to +30
"deny": { "type": "array", "items": { "type": "string" } },
"require": { "type": "array", "items": { "type": "string" } },
"local_deployed_file_hashes": {
"type": "object",
"additionalProperties": {
"comment": "Bare-hex form retained for v0.1 reader-tolerance per req-lk-016; v0.2 will require the sha256: envelope exclusively (see oci-r2-nit-2).",

This specification defines four conformance classes; this section
is the **sole normative home** for them. The forward pointer in
[Section 2](#2-scope-and-conformance) is editorial.
| [req-mf-001](#req-mf-001) | MUST | 4.1 | producer |
| [req-mf-002](#req-mf-002) | MUST | 4.1 | producer |
| [req-mf-003](#req-mf-003) | MUST | 4.1 | producer |
| [req-mf-004](#req-mf-004) | MUST | 4.1 | producer |
Comment on lines +2654 to +2657
defines `type` (`agent` or `library`) as informational in v0.1; it
exists so future minor revisions can attach normative semantics
(for example, packaging filters per type) without a breaking
schema change. v0.1 consumers MUST ignore the value.
### 8.4 Target detection signals (normative)

When the user has not specified a target via `--target` or in the
manifest's `targets:` field, the consumer auto-detects from
| `^x.y.z` | Compatible-with-X: matches `>= x.y.z, < (x+1).0.0` when `x > 0`; `>= 0.y.z, < 0.(y+1).0` when `x == 0` and `y > 0`; `>= 0.0.z, < 0.0.(z+1)` when `x == 0` and `y == 0`. |
| `~x.y.z` | Approximately equivalent: `>= x.y.z, < x.(y+1).0`. `~x.y` (no patch) is equivalent to `>= x.y.0, < x.(y+1).0`. |
| `>=`, `>`, `<=`, `<`, `=` | Comparator-form: standard inequality on semver precedence. |
| `x.y.z`, `*`, `latest` | Wildcard: any version (subject to pre-release exclusion). `latest` is commonly registered as a registry dist-tag; it is not a node-semver range operator. |
Comment thread CHANGELOG.md Outdated
Comment on lines 10 to 17
- `apm install --update` now re-resolves direct git-source semver dependencies. Previously, when the dependency's install path already existed on disk, the BFS resolver short-circuited and `--update` was a silent no-op for git-semver refs; the lockfile kept the previously-resolved tag.
- `policy.dependencies.require_pinned_constraint: true` no longer misclassifies the npm- and cargo-style explicit-equality form `=1.2.3` as `BARE_BRANCH`. Both `1.2.3` and `=1.2.3` are now recognized as pinned constraints; the pip-style `==1.2.3` form is still rejected (not part of node-semver). Follow-up to #1494 / #1505.
- OpenAPM v0.1 normative specification at `docs/src/content/docs/specs/openapm-v0.1.md`, JSON Schemas for manifest/lockfile/policy, and conformance fixture seed tree under `tests/fixtures/spec-conformance/` (#1502).

"url": { "type": "string", "pattern": "^https?://" },
"insecure": { "type": "boolean" },
"aliases": { "type": "array", "items": { "type": "string" } }
},
danielmeppiel and others added 2 commits May 27, 2026 20:58
Address 9 Copilot reviewer findings (A1-A9) + 5 Deploy Docs link
failures (B1-B5) on the OpenAPM v0.1 spec:

Schemas
- policy: deny/require accept null (parity with allow) (A1)
- lockfile: comment -> $comment annotation (A2)
- manifest: registries object-form allows x-* extensions (A9)

Spec prose
- Retarget broken anchors: #2-conventions (A3/B4),
  #111-conformance-classes-normative (B1/B2), 10.6 -> 10.7 (B3),
  #422-type-advisory (B5)
- Appendix E.1 type set reconciled to instructions/skill/hybrid/prompts (A5)
- Field name targets -> target in two §8.4 examples (A6)
- §7.3.1 wildcard row: drop 'latest' (semver-only) (A7)
- Appendix C req-mf-004 MUST -> SHOULD matches body prose (A4)

CHANGELOG
- Recover dropped v0.16-cycle Unreleased entries lost in branch
  rebase (A8): git-semver ref:, apm deps why, --update fix,
  =1.2.3 pinned-classification

Local Starlight build: zero links-validator errors, 111 pages built.

Skill: apm-spec-guardian
- New advisory panel skill institutionalizing the 4-persona spec
  review process used for this saga
- Activates on PRs touching docs/src/content/docs/specs/openapm-*.md,
  schemas/*.schema.json, or tests/fixtures/spec-conformance/**
- 5 personas materialized as .apm/agents/spec-*.agent.md:
  swagger-editor, oci-editor, pkgmgr-editor, tag-architect,
  editor-synthesizer
- Single-writer interlock, advisory-only (no merge gate), shocked-meter
  ship signal, 11-check linter checklist mirrored from this saga
- Designed via genesis discipline (design pack in session-state)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #1517 introduced the OpenAPM v0.1 specification but APM is its sole
implementation. Without an in-tree drift detector the spec rots silently
across three modes: (A) silent regression -- a code change breaks a
requirement no test catches; (B) silent extension -- APM gains a behaviour
that should be normative but never enters the spec; (C) stale spec -- the
prose disagrees with the intended behaviour and nobody notices.

This fold is the dictate from the apm-spec-guardian skill panel
(swagger / OCI / pkgmgr / TAG editors, synthesised) red-teaming a v0.1.1
drift-detection design memo. Synthesizer recommendation:
ship_decision=next_brief, fold F1..F11.

Folded:

* F1  machine-readable requirements manifest at
      docs/src/content/docs/specs/manifests/openapm-v0.1.requirements.yml
      (informative in v0.1.1; reserved for normative promotion in v0.2 per
      spec sec.12.6).
* F2  JSON Schema 2020-12 contract for the manifest at
      docs/src/content/docs/specs/schemas/requirements-v0.1.schema.json.
* F3  tests/spec_conformance/orphan_check.py: 4-way bind between the
      canonical spec body anchors, the manifest, Appendix C, and the
      pytest @pytest.mark.req coverage. CI fails on any divergence.
* F4  tests/spec_conformance/conftest.py: registers the `req` marker
      and validates it against the manifest at collection time. Records
      a static-analysis status (active / skipped / xfail) at
      build/conformance-coverage.json.
* F5  tests/spec_conformance/test_{manifest,lockfile,policy,resolution,
      round_trip,gen_statement}_reqs.py: 87 markers covering every
      requirement. 27 active assertions against the seed fixtures and
      shipped schemas; 69 honest waivers ("waiver: <reason>") for
      behaviours that need v0.1.2 fixture expansion or producer harness
      surface. The conformance statement surfaces the gap legibly.
* F6  tests/spec_conformance/gen_statement.py: writes a deterministic
      CONFORMANCE.json + CONFORMANCE.md at repo root (canonical, sorted,
      ASCII-only, LF line endings, generator-stamped).
* F7  tests/spec_conformance/test_gen_statement.py: byte-equal
      regeneration, ASCII-only assertion, version+generator stamps, and
      the literal "NO automated CI detector" honesty phrase.
* F8  tests/spec_conformance/test_round_trip.py: stage-2 fixed-point
      parametrised over five round-trip fixtures (manifest, lockfile,
      policy). Honours `round_trip_exempt_fields` from the manifest.
* F9  .github/workflows/spec-conformance.yml: paths-triggered gate that
      runs orphan_check, the conformance pytest suite, regenerates
      CONFORMANCE.{json,md}, and gates on `git diff --exit-code` so
      contributors must commit any regeneration.
* F10 spec sec.12.3 rewritten to identify the HTML anchors as canonical
      source (manifest and Appendix C are derived projections); sec.12.6
      reservation preserved with informative v0.1.1 companion paragraph
      appended; Appendix D row updated.
* F11 CONFORMANCE.md preamble carrying the literal honesty contract;
      CONTRIBUTING.md "Adding or changing a normative requirement"
      three-step ritual; .github/pull_request_template.md spec-
      conformance checklist enforcing the ritual at PR time.

Anti-patterns explicitly rejected per the synthesizer (do NOT reintroduce):
one pytest file per req; an `apm conformance run` user command; 100%
line coverage as the conformance bar; Appendix-C-table-regex as load-
bearing CI source of truth.

Maintainer mandate: ship with the spec, NOT as a follow-up PR.

Verified locally:
  $ uv run --extra dev python -m tests.spec_conformance.orphan_check
  [+] orphan_check OK: 87 requirements aligned across anchors / manifest
      / Appendix C / pytest markers
  $ uv run --extra dev pytest tests/spec_conformance -p no:randomly
  27 passed, 69 skipped
  $ uv run --extra dev ruff check src/ tests/
  All checks passed!
  $ uv run --extra dev ruff format --check src/ tests/
  1134 files already formatted
  $ uv run --extra dev python -m pylint --disable=all --enable=R0801         --min-similarity-lines=10 --fail-on=R0801 src/apm_cli/
  Your code has been rated at 10.00/10
  $ bash scripts/lint-auth-signals.sh
  [+] auth-signal lint clean

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel
Copy link
Copy Markdown
Collaborator Author

Spec drift guardrails: apm-spec-guardian panel dictate folded into this PR

Per the maintainer mandate ("we will never merge the in-flight PR if such scaffolding is not folded in"), the v0.1.1 drift-detection design memo went through the apm-spec-guardian skill -- four expert panelists (swagger / OCI / pkgmgr / TAG editors, each in their own thread) red-teamed it in parallel, then spec-editor-synthesizer aggregated.

Synthesizer outcome: ship_decision=next_brief, shocked_meter_avg = 5.0 / 10 across the panel, 11 mandatory folds (F1..F11), 5 deferred to v0.1.1 follow-ups, 4 deferred to v0.2, 4 rejects (including the panelist proposal to split into a follow-up PR -- explicitly vetoed to honour the fold mandate).

Folded into this PR (commit d9a68493)

F# Artifact What it catches
F1 docs/src/content/docs/specs/manifests/openapm-v0.1.requirements.yml (informative) Mode B (silent extension) -- no new behaviour can land without a manifest entry
F2 docs/src/content/docs/specs/schemas/requirements-v0.1.schema.json (Draft 2020-12) Manifest shape contract
F3 tests/spec_conformance/orphan_check.py 4-way bind: anchors == manifest == Appendix C == pytest markers
F4 tests/spec_conformance/conftest.py + req marker Unknown / malformed req ids fail at collection
F5 5 test modules, 87 markers (27 active assertions, 69 honest waivers) Mode A (silent regression) on every active req
F6 tests/spec_conformance/gen_statement.py -> CONFORMANCE.{json,md} Honest public statement (debt is legible, not invisible)
F7 tests/spec_conformance/test_gen_statement.py Determinism + ASCII-only + honesty-phrase invariants
F8 tests/spec_conformance/test_round_trip.py req-cf-001 fixed-point on 5 fixtures with manifest-driven exempt fields
F9 .github/workflows/spec-conformance.yml Paths-triggered CI gate; git diff --exit-code on regenerated artifacts
F10 Spec sec.12.3 + sec.12.6 + Appendix D HTML anchors named as canonical source; informative companion paragraph; revision row
F11 CONFORMANCE.md preamble + CONTRIBUTING.md ritual + PR template checkbox Mode C (stale spec) at PR time; carries the literal phrase "NO automated CI detector"

Critical insight (from the panel)

The single highest-leverage piece is F1 (the manifest): without it, the orphan-check is a regex against a markdown table (fragile), and silent-extension drift has no detector. The panel collectively dictated pulling the §12.6 reservation forward as an informative v0.1.1 companion (preserving the v0.2 normative reservation language) so the trip wire ships now without a normative bump.

Honest scope

  • 27 active assertions today; 69 waivers. The conformance statement publishes the gap rather than hiding it. v0.1.2 fixture expansion (integrity oracles, scheme negative cases, evaluator behaviour) is tracked.
  • Registry class is explicitly waived for v0.1 (the class ships only the trust-anchor MUST at sec.11.3.3; no wire surface yet).
  • Anti-patterns the synthesizer rejected: one pytest file per req, an apm conformance run user command, 100% line coverage as the conformance bar, the Appendix-C-table-regex as load-bearing CI source.

Local verification (mirrors the new CI job)

$ uv run --extra dev python -m tests.spec_conformance.orphan_check
[+] orphan_check OK: 87 requirements aligned across anchors / manifest / Appendix C / pytest markers

$ uv run --extra dev pytest tests/spec_conformance -p no:randomly
27 passed, 69 skipped

$ uv run --extra dev ruff check src/ tests/ &&   uv run --extra dev ruff format --check src/ tests/ &&   uv run --extra dev python -m pylint --disable=all --enable=R0801       --min-similarity-lines=10 --fail-on=R0801 src/apm_cli/ &&   bash scripts/lint-auth-signals.sh
All checks passed!
1134 files already formatted
Your code has been rated at 10.00/10
[+] auth-signal lint clean

Deferred (not in this PR, captured as follow-ups)

  • v0.1.1: integrity fixtures (hash-mismatch.frozen archive, bare-hex reader-tolerance pair, deployed-file-hash mismatch, canonical-tree fixture with hand-computed tree_sha256 for req-lk-012..017); CONFORMANCE.md rotation policy.
  • v0.2: promote the requirements manifest from informative to normative; expand producer harness; registry wire surface; round-trip exempt fields parametrisation across multiple req ids.
  • Rejected: PR split (maintainer veto); inline cargo/pip precedent citations in the design memo (memo is not a committed artifact).

…uardian directive)

Closes the spec-guardian's full-completeness directive on PR #1517:
ship the v0.1 spec with active conformance coverage on every
testable requirement (in-PR, not in a future version).

## Coverage shift

Before: 27 active / 69 skipped / 87 total (sole-implementor risk).
After:  86 active /  1 skipped / 87 total.

Per class:
  Producer    12 / 12 active
  Consumer    61 / 62 active (1 honest waiver: req-mf-016)
  Registry     1 /  1 active (was: waived entirely)
  Governance  12 / 12 active

The sole remaining skip is req-mf-016 (apm-source absolute-path
rejection), which requires the path-policy loader to be invokable
from the harness; the schema currently models `path` as free-form
string and the waiver text documents the tightening as the next
schema-side follow-up.

## Conversion strategies used

1. **Schema introspection**: read the manifest/lockfile/policy JSON
   Schemas, assert the structural invariants they encode (depEntry
   oneOf, hashEnvelope pattern, registries https-only, hash_algorithm
   strong-set, pattern properties for x-* extensions, etc.).

2. **Spec-text grep** (`assert_spec_contains`): assert that the
   verbatim normative phrasing remains in the spec body. Catches
   silent-deletion drift: if the authoring panel rewords or drops a
   clause without updating the assertion, the suite fails at PR time.

3. **Negative fixtures**: 4 new manifest fixtures
   (invalid-registry-scheme, invalid-registries-typo,
   invalid-source-kind, invalid-yaml-anchor-alias) drive jsonschema
   validation to failure on the boundary the spec forbids.

4. **Integrity oracle (req-rg-001, req-lk-012..017)**: a
   deterministic 176-byte tar.gz archive
   (`integrity/security-baseline-2.3.1.tar.gz`) plus four paired
   lockfile fixtures (canonical, hash-mismatch, deployed-file-mismatch,
   bare-hex-reader). The registry trust-anchor test reads the archive
   bytes, recomputes SHA-256, and asserts equality with the lockfile's
   advertised digest. Tampering with either side breaks the bind. The
   mismatch fixtures prove the fail-closed contract is observable.

5. **apm_cli loader integration**: req-pl-005/007/008 drive
   `apm_cli.policy.parser.load_policy` against the valid-extends
   fixture and assert the ApmPolicy model carries the expected
   allow/deny tuples.

6. **Oracle parametrisation**: req-rs-008 (caret), req-rs-009
   (tilde), req-rs-010 (exact), req-rs-014 (prerelease/build) all
   walk `resolution/semver-dialect.json` as parametrised cases.

7. **Literal regex validation**: req-pr-004 (git-semver tag form)
   compiles the literal regex from sec.8.5 and validates it against
   10 positive + negative tag examples.

## New files

  tests/fixtures/spec-conformance/integrity/
    security-baseline-2.3.1.tar.gz                  (Registry oracle)
    security-baseline-2.3.1.frozen.yaml             (req-rg-001, req-lk-006/010/012)
    hash-mismatch.frozen.yaml                       (req-lk-013)
    deployed-file-mismatch.frozen.yaml              (req-lk-017)
    bare-hex-reader.frozen.yaml                     (req-lk-016)
  tests/fixtures/spec-conformance/manifest/
    invalid-registry-scheme.yml                     (req-mf-014, req-sc-007)
    invalid-registries-typo.yml                     (req-mf-015)
    invalid-source-kind.yml                         (req-mf-012)
    invalid-yaml-anchor-alias.yml                   (req-mf-020)
  tests/spec_conformance/test_registry_reqs.py      (req-rg-001 active)

## Helpers

  _helpers.py: + assert_spec_contains(*needles), spec_text() cache,
               sha256_hex() for integrity oracles.

## Doc deltas

  gen_statement.py: rewrite the 'Conformance classes' preamble to
    declare active coverage on all four classes (Producer, Consumer,
    Registry, Governance); the registry class is exercised through
    the trust-anchor SHA-256 invariant test.
  CONTRIBUTING.md: replace 'bump 0.1.1 -> 0.1.2' phrasing in the
    Mode C bullet with version-agnostic 'bump the spec patch
    revision' (no implicit version-bumping commitment).

## Verification

  uv run --extra dev pytest tests/spec_conformance -p no:randomly
    -> 109 passed, 2 skipped in 4.28s (skips = req-mf-016 waiver +
    req-lk-018 publisher SHOULD with a recorded waiver alongside
    the schema-affordance assertion)
  uv run --extra dev python -m tests.spec_conformance.orphan_check
    -> 87 requirements aligned across the 4-way bind
  uv run --extra dev python -m tests.spec_conformance.gen_statement
    -> regenerates CONFORMANCE.{md,json} (86 active / 1 skipped)
  uv run --extra dev ruff check src/ tests/                  : OK
  uv run --extra dev ruff format --check src/ tests/         : OK
  uv run --extra dev pylint --enable=R0801 src/apm_cli/      : 10/10
  bash scripts/lint-auth-signals.sh                          : clean

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel
Copy link
Copy Markdown
Collaborator Author

Spec-conformance waiver-to-active conversion (commit 3b3cc1d6)

Per the maintainer directive (no v0.1.2/v0.2 deferrals, full completeness in PR #1517, registry must not be excluded), the prior fold's 69 honest waivers have been collapsed to 1.

Coverage shift

Before After
Active 27 86
Skipped 69 1
Total 87 87

Per conformance class:

Class Active Skipped
Producer 12 / 12 0
Consumer 61 / 62 1
Registry 1 / 1 0 (was: waived entirely)
Governance 12 / 12 0

The one remaining skip is req-mf-016 (absolute-path rejection in apm-source). The schema currently models path as a free-form string; tightening the schema's regex to forbid leading / is the next mechanical follow-up. Documented in CONFORMANCE.md's Waivers section.

Conversion strategies

  1. Schema introspection — read the manifest/lockfile/policy JSON Schemas and assert the structural invariants they encode (depEntry oneOf, hashEnvelope pattern, https-only registries, strong hash-algorithm set, x-* pattern properties).
  2. Spec-text grep (assert_spec_contains) — assert verbatim normative phrasing remains in the spec body. Silent-deletion / silent-rewording detector at PR time.
  3. Negative fixtures — 4 new manifest fixtures drive jsonschema validation to failure on the forbidden boundary.
  4. Integrity oracle (req-rg-001 + req-lk-012..017) — a deterministic 176-byte tar.gz archive plus 4 paired lockfile fixtures (canonical, hash-mismatch, deployed-file-mismatch, bare-hex-reader). The registry trust-anchor test hashes the archive bytes and asserts equality with the lockfile's advertised digest. Tampering with either side breaks the bind.
  5. apm_cli loader integration — req-pl-005/007/008 drive apm_cli.policy.parser.load_policy against the valid-extends fixture and walk the ApmPolicy model.
  6. Oracle parametrisation — req-rs-008/009/010/014 walk semver-dialect.json as parametrised cases.
  7. Literal regex validation — req-pr-004 compiles the literal git-semver tag regex from sec.8.5 and validates against 10 positive + negative tag examples.

New artifacts

tests/fixtures/spec-conformance/integrity/
  security-baseline-2.3.1.tar.gz                  (Registry oracle archive)
  security-baseline-2.3.1.frozen.yaml             (req-rg-001, req-lk-006/010/012)
  hash-mismatch.frozen.yaml                       (req-lk-013 fail-closed)
  deployed-file-mismatch.frozen.yaml              (req-lk-017 fail-closed)
  bare-hex-reader.frozen.yaml                     (req-lk-016 tolerance)
tests/fixtures/spec-conformance/manifest/
  invalid-registry-scheme.yml                     (req-mf-014, req-sc-007)
  invalid-registries-typo.yml                     (req-mf-015)
  invalid-source-kind.yml                         (req-mf-012)
  invalid-yaml-anchor-alias.yml                   (req-mf-020)
tests/spec_conformance/test_registry_reqs.py      (req-rg-001 active)

Doc deltas

  • gen_statement.py preamble: removed the "Registry is waived for v0.1" disclaimer; the new preamble declares active coverage on all four classes including Registry via the trust-anchor SHA-256 invariant.
  • CONTRIBUTING.md Mode C bullet: replaced "bump 0.1.1 -> 0.1.2" with "bump the spec patch revision" (no implicit version-bumping commitment, no future-version deferral language).

Verification

uv run --extra dev pytest tests/spec_conformance -p no:randomly
  -> 109 passed, 2 skipped in 4.28s
uv run --extra dev python -m tests.spec_conformance.orphan_check
  -> 87 requirements aligned across the 4-way bind
uv run --extra dev python -m tests.spec_conformance.gen_statement
  -> regenerates CONFORMANCE.{md,json} (86 active / 1 skipped)
ruff check / ruff format --check / pylint R0801 / auth-signals  -> all clean

The drift-detection scaffolding now ships with active enforcement across every testable normative statement. Spec rot in the three modes the maintainer named:

  • Mode A (silent regression): code change breaks an assertion bound to req-XXX → spec-conformance pytest job fails.
  • Mode B (silent extension): new behaviour lands with no req-XXX → orphan_check fails.
  • Mode C (stale spec): spec phrasing changes → assert_spec_contains needles break and authoring panel must reconcile.

danielmeppiel and others added 2 commits May 28, 2026 11:02
Closes the sole-implementer rot risk the maintainer named on PR #1517
review: the existing 4-way orphan_check enforces equality among already-
DECLARED artifacts (anchors / manifest / Appendix C / pytest markers)
but cannot detect new APM behaviour under critical paths with zero
markers. This commit adds a complementary CI gate plus folds 7
spec-guardian editorial findings.

Mode B detector
---------------
* tests/spec_conformance/mode_b_detector.sh: shell gate. Counts
  substantive added lines under the critical-path allowlist
  (primitives/, deps/, policy/, registry/, runtime/, install/,
  integration/), short-circuits when the PR is spec-concurrent (touches
  the spec body, requirements manifest, or adds a new @pytest.mark.req
  marker), and fires with an actionable diagnostic when the threshold
  is crossed without a citation.
* tests/spec_conformance/critical_paths.txt: editable allowlist; edits
  are themselves critical-path edits per CONTRIBUTING.md.
* .github/workflows/spec-conformance.yml: wires the detector as a step
  after orphan_check.
* Waiver mechanism: 'apm-spec-waiver: <reason, >= 16 chars>' in the PR
  body OR a commit message between merge-base and HEAD. Echoed to CI.
* CONTRIBUTING.md Mode B section rewritten honestly (no longer claims
  orphan_check catches silent extension on its own).

Round-3 editorial fold (no new req IDs; statement count stays at 87)
--------------------------------------------------------------------
* Section 11.3.2 Consumer enumeration: appended req-rs-014 and
  req-cf-002 (closes drift vs Appendix C, sw-rec-r1-1).
* req-lk-005: writers MUST canonicalise dependencies list in ascending
  (repo_url, virtual_path) order; frozen-install diffs now stable
  across implementations (pkg-rec-r1-1).
* req-sc-003: consumers MUST drop the originating Authorization header
  across cross-host-class redirects, closing the mirror-redirect
  token-leak surface (oci-rec-r1-4).
* req-rg-001: extended with publish-side idempotency clause -- Registry
  MUST either reject republish or accept ONLY byte-identical bytes
  (oci-rec-r1-5).
* Section 6.2 + 6.3.1 defaults pinned: fetch_failure defaults to warn;
  dependencies.require_resolution defaults to project-wins. Mirrored
  as advisory "default" annotations in policy-v0.1.schema.json
  (pkg-rec-r1-5).
* manifest-v0.1.schema.json: conflict_resolution enum aligned to prose
  (intersect -> intersection-pick); nest dropped from v0.1 enum (still
  reserved for v0.2 per req-rs-013, now noted via schema $comment)
  (pkg-rec-r1-2).
* lockfile-v0.1.schema.json: stripped internal review-token leak
  '(see oci-r2-nit-2)' from $comment (oci-nit-r1-1).
* Appendix D: 0.1.2 revision row added documenting all of the above.

Test coverage
-------------
Mode-C-style normative-phrase pins added for the 3 strengthened reqs
(req-lk-005, req-sc-003, req-rg-001) so the new clauses cannot
silently disappear from the spec body. All 109 conformance tests pass;
orphan_check aligned at 87 requirements.

Verification: ruff/pylint R0801/auth-signals all green; orphan_check
clean; pytest tests/spec_conformance 109 passed, 2 skipped.

Refs: PR #1517

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel
Copy link
Copy Markdown
Collaborator Author

Round-3 fold: Mode B detector + 7 editorial closures (commit 79a1884)

Folded the maintainer's named sole-implementer rot risk and 7 spec-guardian editorial findings into this PR. No new req IDs; statement count stays at 87. CI mirror green.

Mode B silent-extension detector (the structural fix)

The existing 4-way orphan_check enforces equality among already-DECLARED artifacts. It cannot detect new APM behaviour under critical paths with zero markers. New companion gate tests/spec_conformance/mode_b_detector.sh closes that hole:

  • Counts substantive added lines under a critical-path allowlist (primitives/, deps/, policy/, registry/, runtime/, install/, integration/)
  • Short-circuits when the PR is spec-concurrent (touches the spec body, the requirements manifest, or adds a new @pytest.mark.req)
  • Fires with an actionable diagnostic when threshold is crossed with no citation
  • Auditable opt-out: apm-spec-waiver: <reason, >= 16 chars> in PR body or a commit trailer
  • Wired as a step in .github/workflows/spec-conformance.yml after orphan_check
  • CONTRIBUTING.md Mode B section rewritten honestly (no longer claims orphan_check catches silent extension on its own)

Honest limits documented in commit body: heuristic threshold, regex-not-AST line filter, waiver-abuse is honor-system. Acceptable v0.1 surface; tightenable.

Round-3 editorial fold (7 findings closed, no new req IDs)

Finding Closure
sw-rec-r1-1 Section 11.3.2 Consumer enumeration: appended req-rs-014 + req-cf-002
pkg-rec-r1-1 req-lk-005 extended: writers MUST canonicalise dependencies in (repo_url, virtual_path) order
pkg-rec-r1-2 manifest schema: renamed intersect -> intersection-pick, dropped nest from v0.1 enum (still reserved for v0.2 per req-rs-013, noted via $comment)
pkg-rec-r1-5 Sec 6.2 + 6.3.1 + policy schema: fetch_failure defaults to warn, require_resolution defaults to project-wins
oci-rec-r1-4 req-sc-003 extended: MUST drop Authorization header on cross-host-class redirect
oci-rec-r1-5 req-rg-001 extended: publish-side idempotency clause (reject-or-byte-identical)
oci-nit-r1-1 lockfile schema: stripped internal review-token (see oci-r2-nit-2) from $comment

Test coverage

Mode-C-style normative-phrase pins added for the 3 strengthened reqs (req-lk-005, req-sc-003, req-rg-001) so the new clauses cannot silently disappear. 109 passed, 2 skipped; orphan_check aligned at 87.

Deferred to follow-up (not blocking ship)

  • tag-rec-r1-3: scoped assert_spec_contains_under(req_id, ...) helper
  • tag-rec-r1-4: 5th set in orphan_check binding Section 11.3 to Appendix C
  • oci-rec-r1-1/r1-2: canonical git tree-hash for submodules + gitattributes filter pin
  • oci-rec-r1-3: split hashEnvelope vs hashEnvelopeStrict (bare-hex scope tightening)
  • pkg-rec-r1-3/r1-4/r1-6: resolved_ref disambiguation, hyphen-range oracle case, deterministic chain ordering on req-rs-010
  • sw-rec-r1-2: split bundled MUSTs in req-mf-021

Panel ship-confidence: 4/4 ship_with_followups; shocked-meter average 7.75/10; 0 blockers.

…chema changes

Closes three gaps surfaced by the gate-completeness audit on top of
the round-3 spec-drift fold:

A. Mode B detector self-tests (NEW test_mode_b_detector.py, 9 cases)
   The detector script was itself honor-system -- a future edit could
   silently break the gate logic and CI would not notice. The new
   suite pins the script's structural contract (exists, executable,
   bash -n clean), the critical-path allowlist shape (every entry
   resolves to a real dir; primitives/deps/policy/registry are all
   covered), the CI workflow wiring (orphan_check -> mode_b_detector
   -> conformance suite ordering), AND the gate behaviour itself by
   running the script via subprocess inside a synthetic git repo:
     - spec-concurrent edit short-circuits (exit 0)
     - out-of-scope only passes (exit 0)
     - substantive critical-path add with no spec edit fires (exit 1)
     - commit-trailer waiver accepted
     - short waiver (<16 chars) rejected

B. Round-3 schema/default pins
   test_resolution_reqs.py req-rs-013 now asserts the manifest schema
   enum is exactly [intersection-pick] (not just that the spec prose
   names it); a reverter to [intersect, nest] now trips a test.
   test_policy_reqs.py req-pl-010 now asserts the fetch_failure and
   require_resolution defaults are pinned in the schema AND in spec
   prose.

C. Workflow trigger expansion
   Added CONTRIBUTING.md and .github/workflows/spec-conformance.yml
   to the spec-conformance paths filter so edits to the Mode B
   narrative or the gate itself are re-verified by the gate.

Verification: ruff/format clean, pylint R0801 10.00/10, auth-signals
clean, orphan_check OK 87 reqs, pytest 118 passed / 2 skipped (the
two documented absolute-path / lockfile-sort waivers).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel
Copy link
Copy Markdown
Collaborator Author

Gate-completeness audit: 3 gaps closed (commit df0408b9)

Audited the spec-conformance CI gate end-to-end after the round-3 fold and found three real holes. All closed in this push.

Gap Risk Fix
A. Mode B detector was honor-system Detector script could be broken / disabled and CI would silently pass New test_mode_b_detector.py (9 cases): pins script presence + exec bit + bash -n cleanliness, the critical-path allowlist shape, the workflow ordering (orphan_check -> mode_b_detector -> suite), AND drives the script via subprocess against a synthetic git repo to exercise all four branches (short-circuit, out-of-scope, fire, waiver-accept, waiver-too-short)
B. Round-3 schema changes unpinned A reverter could undo the conflict_resolution: [intersection-pick] narrowing or the policy default annotations (fetch_failure: warn, require_resolution: project-wins) and CI would pass Extended req-rs-013 to assert the schema enum is exactly [intersection-pick]; extended req-pl-010 to assert both schema defaults AND their normative phrases in the spec body
C. Workflow paths filter incomplete Edits to CONTRIBUTING.md (Mode B narrative) or the gate workflow itself did not re-run the gate Added both to paths:

Verification (CI-mirror, all silent / exit 0):

  • ruff check + ruff format --check on src/ tests/
  • pylint R0801 10.00/10
  • scripts/lint-auth-signals.sh
  • orphan_check OK 87 reqs aligned (anchors / manifest / Appendix C / pytest markers)
  • pytest tests/spec_conformance: 118 passed, 2 skipped (the two documented absolute-path / lockfile-sort waivers)
  • gen_statement regen: no net diff in CONFORMANCE.{md,json}

Mode B detector is now self-defending. Suite count went 109 -> 118 (+9 self-tests). No new req IDs; no spec drift.

The spec page builds at /apm/specs/openapm-v01/ but was undiscoverable
and its declared schema $id URLs were unreachable. Designed with a
Starlight + spec-publishing expert (OpenAPI / JSON Schema / OCI
precedent) and the APM doc-writer; folded end-to-end so the spec ships
with PR #1517 instead of leaking out half-published.

Five changes:

1. Move normative artifacts to docs/public/specs/{schemas,manifests}/
   so the declared $id URLs (https://microsoft.github.io/apm/specs/
   schemas/<name>.schema.json) resolve to byte-identical files on the
   built site. Schemas and YAML lived under the Starlight content
   collection, where Astro does not serve them as static assets --
   the $ids were a promise the site could not keep. Now they ship at
   the canonical URL, exactly as JSON Schema, OpenAPI, CycloneDX, and
   SPDX serve theirs.

   Tooling paths updated in lockstep: _manifest.py, _helpers.py,
   bootstrap_requirements.py, mode_b_detector.sh, test_mode_b_detector.

   Also fixed a real bug surfaced by the new gate: requirements-v0.1
   .schema.json had $id pointing at github.com/microsoft/apm/spec/...
   instead of microsoft.github.io/apm/specs/... (would have landed any
   pinning toolchain off-site).

2. New top-level 'Specification' sidebar group ABOVE 'CLI reference'
   in docs/astro.config.mjs. Two entries: the spec page and a new
   thin Conformance wrapper page that points to CONFORMANCE.md and
   .json at the repo root. The spec is the centerpiece normative
   artifact; placement signals that.

3. Stable shortlink redirects /spec, /spec/latest, /spec/v0.1 ->
   /apm/specs/openapm-v01/ for external citation. Mirrors OpenAPI
   and AsyncAPI URL discipline: versioned URLs are immortal and
   pin-targetable; /latest is for human prose only. Documented on
   the spec page in a new 'Citing this specification' subsection
   that explicitly says toolchains MUST NOT pin to /latest.

4. Cross-link banners on reference/{manifest-schema,lockfile-spec,
   policy-schema}.md point readers at the normative v0.1 spec
   sections (4 / 5 / 6) and at the canonical schema $id URLs.
   Resolves the silent-drift gap where a reader landing on the v0.2
   working-draft reference pages had no signal that a ratified v0.1
   normative spec existed.

5. New CI gate scripts/check_schema_ids.py wired into
   .github/workflows/docs.yml after the docs build step. For every
   schema under docs/public/specs/schemas/, it asserts: (a) the
   declared $id is on-site under /apm/, (b) the path exists in
   docs/dist/, (c) the bytes are sha256-identical to the source.
   Catches schema-moved-without-$id-update, $id typos, and
   Starlight accidentally consuming a public/ asset. Pure stdlib so
   it runs on the existing Node-only docs job without an extra
   Python setup.

Plus a 60-word landing blurb at the top of the spec orienting
first-time readers ('the consumer/producer/enterprise ramps tell you
how to USE APM; this page is the contract that defines what APM IS').

Verification:
  - npm run build: 111 pages, all internal links valid
  - check_schema_ids.py: 4/4 schemas resolve sha256-identical
  - orphan_check: 87 reqs aligned
  - pytest tests/spec_conformance: 118 passed, 2 skipped
  - ruff/format/pylint R0801/auth-signals: all green
  - dist/spec/{,v0.1,latest}/index.html: meta-refresh redirects shipped

Honest gaps left for follow-up (out of scope here):
  - multi-version /latest routing is manual until v0.2 lands
  - section heading IDs not yet stabilized for deep-link survival
  - normative-vs-informative visual treatment (MUST/SHOULD styling)
  - schemastore.org registration

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel
Copy link
Copy Markdown
Collaborator Author

Docs fold: spec is now actually shipped (commit 4db3c6bd)

Designed with a Starlight + spec-publishing expert (OpenAPI / JSON Schema / OCI / AsyncAPI precedent) and the APM doc-writer. Five changes:

Change Closes
Move schemas/ + manifests/ -> docs/public/specs/ Schema $id URLs were unreachable -- they lived in the Starlight content collection, which doesn't serve assets. The spec promised https://microsoft.github.io/apm/specs/schemas/manifest-v0.1.schema.json but the build emitted nothing at that path. Now schemas ship verbatim at their declared $id, exactly as JSON Schema, OpenAPI, CycloneDX, SPDX do
Top-level 'Specification' sidebar group above 'CLI reference' Spec page was undiscoverable -- not in nav. Two entries: the spec + a thin Conformance wrapper page that points to CONFORMANCE.md
Stable shortlinks /spec, /spec/latest, /spec/v0.1 No stable URL for external citation. Mirrors OAS/AsyncAPI discipline: versioned URLs are immortal and pin-targetable; /latest is for human prose only (the spec page now says this explicitly in a new 'Citing this specification' subsection)
Cross-link banners on reference/{manifest-schema,lockfile-spec,policy-schema}.md Readers landing on v0.2 working-draft reference pages had no signal that a ratified v0.1 normative spec existed
New CI gate scripts/check_schema_ids.py Round-tripped existing real bug: requirements-v0.1.schema.json had $id pointing at github.com/microsoft/apm/spec/ (off-site) instead of microsoft.github.io/apm/specs/. The gate asserts every schema's $id resolves to a byte-identical file under docs/dist/. Pure stdlib so it runs on the existing Node-only docs job

Plus a 60-word landing blurb on the spec page orienting first-time readers ('the consumer/producer/enterprise ramps tell you how to USE APM; this page is the contract that defines what APM IS').

Verification:

  • npm run build: 111 pages, all internal links valid
  • check_schema_ids.py: 4/4 schemas resolve sha256-identical to source
  • orphan_check: 87 reqs aligned
  • pytest tests/spec_conformance: 118 passed, 2 skipped
  • ruff / ruff format / pylint R0801 / auth-signals: all green
  • dist/spec/{,v0.1,latest}/index.html: meta-refresh redirects shipped

Honest gaps left for follow-up (out of scope here, named on the record so they aren't silent):

  • multi-version /latest routing is manual until v0.2 lands
  • section heading IDs not yet stabilized for deep-link survival (worth a v0.1.1 pass)
  • normative-vs-informative visual treatment (MUST/SHOULD styling)
  • schemastore.org registration (separate ship)

Spec is no longer half-published. PR #1517 now ships a contract whose citation URLs resolve, whose schemas are pin-targetable, and whose sidebar entry exists.

@danielmeppiel danielmeppiel merged commit 080bb02 into main May 28, 2026
15 checks passed
@danielmeppiel danielmeppiel deleted the feat/openapm-v0.1-spec branch May 28, 2026 12:04
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.

feat(spec): publish OpenAPM v0.1 as a single normative specification document

2 participants