-
Notifications
You must be signed in to change notification settings - Fork 0
feat(schemas): Model Plane store manifests (T7-2, resolves #242) #245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # ADR-0016: Model Plane store manifests (Tranche 7, T7-2) | ||
|
|
||
| **Date:** 2026-08-02 | ||
| **Status:** `Accepted` | ||
|
|
||
| --- | ||
|
|
||
| ## Context | ||
|
|
||
| Tranche 7 (T7-2) calls for `ModelManifest` and `AdapterManifest` — the content-addressed store manifests the Model Plane spec §IV places beside the weights (`/var/lib/sourceos/models/{base,adapters}/sha256-<digest>/manifest.json` + `signature.sig`). ADR-0015 deferred this pending two reconciliations (tracked as issue #242): | ||
|
|
||
| 1. The store manifest appears to overlap `SourceOSModelCarryRef`. | ||
| 2. "AdapterManifest" collides in name/concept with the existing `AdapterDescriptor`, which types **connector/actuation** adapters (api/cli/sdk/event/file). | ||
|
|
||
| ## Decision | ||
|
|
||
| Add two new schemas, `ModelManifest` and `ModelAdapterManifest`. | ||
|
|
||
| - **`ModelManifest`** — the content-addressed manifest for base-model weights at rest: `modelDigest` (the store key), architecture, quantization, format, tokenizer digest, context length, default tier, modalities, `license`, and a required `signature` descriptor. | ||
| - **`ModelAdapterManifest`** — the LoRA adapter manifest: `adapterDigest`, the `baseModelDigest` it binds to, task, rank, alpha, target modules, format, `license`, a required `signature`, and an optional `evalReportDigest`. | ||
|
|
||
| **Naming:** the adapter manifest is `ModelAdapterManifest`, **not** `AdapterManifest`, so it does not collide with `AdapterDescriptor`. This resolves reconciliation (2). | ||
|
|
||
| **Relationship to `SourceOSModelCarryRef`:** the manifest and the carry-ref are complementary, not duplicative. The manifest is the store-level content-addressed truth about what the weights *are*; `SourceOSModelCarryRef` is the governance/policy wrapper about how the OS may *carry/prepare* a model reference (carryPolicy, cachePolicy, `mutableModelState: false`, router/governance refs). A carry-ref's `modelRef` points at a manifest digest; the manifest's optional `carryRefs` back-link to carry-refs. This resolves reconciliation (1). | ||
|
|
||
| **Teeth (schema `if/then`/required, verified both ways):** | ||
| - SEAM-014 — a `ModelManifest` is invalid without a `signature` (no model loads without signature verification). | ||
| - SEAM-017 — a `ModelAdapterManifest` is invalid without `baseModelDigest` (rejected on mismatch) and without a `signature`. | ||
| - MIT/Apache-only estate rule — both require an SPDX `license`, so the rule is checkable before wiring; non-SPDX licenses use `LicenseRef-<name>` (e.g. `LicenseRef-Gemma`, `LicenseRef-Llama-Community`), which are visibly NOT Apache/MIT. This closes Model Plane spec OQ3 at the contract layer. | ||
|
|
||
| ## Alternatives considered | ||
|
|
||
| | Alternative | Reason not chosen | | ||
| |-------------|------------------| | ||
| | Name it `AdapterManifest` per the spec text | Collides with `AdapterDescriptor` (connector adapters) — a downstream-mapping hazard. | | ||
| | Extend `SourceOSModelCarryRef` instead of new manifests | The carry-ref is a governance reference with policy, not a content-addressed store record; conflating them would overload one type with two concerns. | | ||
| | Reuse `ArtifactManifest`/`PackageManifest` | Generic artifact/package manifests do not carry model-specific fields (architecture, quantization, LoRA rank/alpha, base-model binding). | | ||
| | Put signature/license as optional | Then SEAM-014/017 and the MIT/Apache rule would not be enforceable at the contract layer. | | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Positive: `AdapterPromotionDecision` (ADR-0015) `candidateAdapterDigest`/`baseModelDigest` now reference real manifest digests; SEAM-014/017 and the license rule are contract-enforced. | ||
| - Positive: the store layout in source-os T7-11 (`modelplaned`) now has typed manifests to read/verify. | ||
| - Follow-up (SHACL, ontogenesis T7-8): the cross-document invariant `ModelAdapterManifest.baseModelDigest == ModelManifest.modelDigest` (when `baseModelManifestRef` is set) and `carryRef.modelRef == manifest.modelDigest` are cross-document and cannot be expressed in JSON Schema `if/then`. | ||
|
|
||
| ## References | ||
|
|
||
| - SourceOS Model Plane — Architecture Specification v0.1, §IV, §IX (SEAM-014/017), §XIV (T7-2) | ||
| - ADR-0015 — Model Plane inference-provenance schemas (deferred T7-2 here) | ||
| - Issue #242 (this decision); epic #241 | ||
| - Reused/related: `schemas/SourceOSModelCarryRef.json`, `schemas/AdapterDescriptor.json`, `schemas/AdapterPromotionDecision.json` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "id": "urn:srcos:model-adapter-manifest:summarization-v3", | ||
| "type": "ModelAdapterManifest", | ||
| "specVersion": "2.1.0", | ||
| "adapterDigest": "sha256:8888888888888888888888888888888888888888888888888888888888888888", | ||
| "displayName": "summarization-v3", | ||
| "baseModelDigest": "sha256:1111111111111111111111111111111111111111111111111111111111111111", | ||
| "baseModelManifestRef": "urn:srcos:model-manifest:generalist-3b-q4k", | ||
| "task": "summarization", | ||
| "rank": 16, | ||
| "alpha": 32, | ||
| "targetModules": ["q_proj", "v_proj", "o_proj"], | ||
| "format": "safetensors", | ||
| "tokenizerDigest": null, | ||
| "license": "Apache-2.0", | ||
| "signature": { | ||
| "algorithm": "ed25519", | ||
| "keyId": "srcos-model-signing-2026", | ||
| "signatureDigest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" | ||
| }, | ||
| "evalReportDigest": "sha256:6666666666666666666666666666666666666666666666666666666666666666", | ||
| "evidenceRefs": ["urn:srcos:adapter-promotion-decision:2026-06-10-summ-v3"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "id": "urn:srcos:model-manifest:generalist-3b-q4k", | ||
| "type": "ModelManifest", | ||
| "specVersion": "2.1.0", | ||
| "modelDigest": "sha256:1111111111111111111111111111111111111111111111111111111111111111", | ||
| "displayName": "generalist-3b", | ||
| "architecture": "llama", | ||
| "parameterCount": 3200000000, | ||
| "format": "gguf", | ||
| "quantization": "q4_k_m", | ||
| "tokenizerDigest": "sha256:3333333333333333333333333333333333333333333333333333333333333333", | ||
| "contextLength": 8192, | ||
| "defaultTier": "T1", | ||
| "modalities": ["text"], | ||
| "license": "Apache-2.0", | ||
| "signature": { | ||
| "algorithm": "ed25519", | ||
| "keyId": "srcos-model-signing-2026", | ||
| "signatureDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | ||
| }, | ||
| "carryRefs": ["urn:srcos:model-carry-ref:generalist-3b-q4k"], | ||
| "evidenceRefs": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$id": "https://schemas.srcos.ai/v2/ModelAdapterManifest.json", | ||
| "title": "ModelAdapterManifest", | ||
| "description": "Content-addressed store manifest for a LoRA (model) adapter in the Model Plane store (Tranche 7, T7-2). Sits at /var/lib/sourceos/models/adapters/sha256-<digest>/manifest.json. Named ModelAdapterManifest — NOT AdapterManifest — to avoid collision with AdapterDescriptor, which types connector/actuation adapters (api/cli/sdk), an unrelated sense of \"adapter\". A valid adapter manifest MUST declare the base-model digest it binds to (SEAM-017: rejected on mismatch) and MUST carry signature info (SEAM-017 signature verification). Referenced by AdapterPromotionDecision via candidateAdapterDigest / baseModelDigest.", | ||
| "type": "object", | ||
| "additionalProperties": false, | ||
| "required": [ | ||
| "id", | ||
| "type", | ||
| "specVersion", | ||
| "adapterDigest", | ||
| "baseModelDigest", | ||
| "task", | ||
| "rank", | ||
| "alpha", | ||
| "targetModules", | ||
| "format", | ||
| "license", | ||
| "signature" | ||
| ], | ||
| "properties": { | ||
| "id": { "type": "string", "pattern": "^urn:srcos:model-adapter-manifest:", "description": "Stable URN identifier. Pattern: urn:srcos:model-adapter-manifest:<local-id>" }, | ||
| "type": { "const": "ModelAdapterManifest", "description": "Discriminator constant — always \"ModelAdapterManifest\"." }, | ||
| "specVersion": { "type": "string", "description": "Spec version of this document, e.g. \"2.1.0\"." }, | ||
| "adapterDigest": { "type": "string", "pattern": "^sha256:[a-fA-F0-9]{64}$", "description": "Content address of the adapter weights — the directory key in the content-addressed store." }, | ||
| "displayName": { "type": ["string", "null"], "description": "Human-readable adapter name, e.g. \"summarization-v3\"." }, | ||
| "baseModelDigest": { "type": "string", "pattern": "^sha256:[a-fA-F0-9]{64}$", "description": "Digest of the base model this adapter binds to. Loading against a base whose digest differs is rejected (SEAM-017)." }, | ||
| "baseModelManifestRef": { "type": ["string", "null"], "pattern": "^urn:srcos:model-manifest:", "description": "Optional URN of the ModelManifest for the base model; its modelDigest must equal baseModelDigest." }, | ||
| "task": { "type": "string", "description": "Task the adapter specializes, e.g. summarization, translation-de-en, agent_classification." }, | ||
| "rank": { "type": "integer", "minimum": 1, "description": "LoRA rank (r)." }, | ||
| "alpha": { "type": "number", "exclusiveMinimum": 0, "description": "LoRA scaling factor (alpha)." }, | ||
| "targetModules": { "type": "array", "minItems": 1, "uniqueItems": true, "description": "Attention/MLP submodules the adapter targets, e.g. q_proj, v_proj, o_proj, gate_proj. Required and non-empty — an adapter that does not declare its target modules is not applicable by a consumer.", "items": { "type": "string" } }, | ||
| "format": { "type": "string", "enum": ["safetensors", "gguf", "mlx"], "description": "On-disk adapter format." }, | ||
| "tokenizerDigest": { "type": ["string", "null"], "pattern": "^sha256:[a-fA-F0-9]{64}$", "description": "Tokenizer digest if the adapter changes tokenization; null to inherit the base model's tokenizer." }, | ||
| "license": { "type": "string", "description": "SPDX license identifier for the adapter weights (e.g. Apache-2.0, MIT). Required so the MIT/Apache-only rule is checkable; a distilled adapter also inherits any base-model license constraint." }, | ||
| "signature": { | ||
| "type": "object", | ||
| "additionalProperties": false, | ||
| "required": ["algorithm", "keyId", "signatureDigest"], | ||
| "description": "Detached-signature descriptor. Required — no adapter loads without signature verification (SEAM-017).", | ||
| "properties": { | ||
| "algorithm": { "type": "string", "description": "Signature algorithm, e.g. ed25519, ecdsa-p256, rsa-pss-sha256." }, | ||
| "keyId": { "type": "string", "description": "Trust-store key identifier that must verify this signature." }, | ||
| "signatureDigest": { "type": "string", "pattern": "^sha256:[a-fA-F0-9]{64}$", "description": "Digest of the detached signature blob stored beside the manifest." } | ||
| } | ||
| }, | ||
| "evalReportDigest": { "type": ["string", "null"], "pattern": "^sha256:[a-fA-F0-9]{64}$", "description": "Content-addressed digest of the eval report produced at training time; referenced by the AdapterPromotionDecision that promotes this adapter." }, | ||
| "evidenceRefs": { "type": "array", "description": "Evidence URNs or content hashes for training provenance, contributing override events, and eval.", "items": { "type": "string" } } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.