Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/model-catalog-entry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: model-catalog-entry

on:
pull_request:
push:
branches: [main]
paths:
- "contracts/sourceos/**"
- "schemas/model-catalog-entry.v0.1.schema.json"
- "examples/model-catalog-entry.*.json"
- "tools/validate_model_catalog_entry.py"
- "tools/tests/test_model_catalog_entry.py"
- ".github/workflows/model-catalog-entry.yml"

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install test dependency
run: python3 -m pip install pytest
- name: Validate catalog entry examples
run: make validate-model-catalog-entry
- name: Run admission tests
run: python3 -m pytest tools/tests/test_model_catalog_entry.py -v
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: validate test emit-demo-decision release-dry-run validate-superconscious-reasoning-route validate-svf-receipt-state-routing validate-trust-chain-model-route-decision validate-prophet-mesh-model-routing
.PHONY: validate test emit-demo-decision release-dry-run validate-superconscious-reasoning-route validate-svf-receipt-state-routing validate-trust-chain-model-route-decision validate-prophet-mesh-model-routing validate-model-catalog-entry

validate: validate-superconscious-reasoning-route validate-svf-receipt-state-routing validate-trust-chain-model-route-decision validate-prophet-mesh-model-routing
validate: validate-superconscious-reasoning-route validate-svf-receipt-state-routing validate-trust-chain-model-route-decision validate-prophet-mesh-model-routing validate-model-catalog-entry
python3 tools/validate_route_examples.py

validate-superconscious-reasoning-route:
Expand All @@ -20,6 +20,12 @@ validate-prophet-mesh-model-routing:
python3 -m json.tool contracts/prophet-mesh/prophet-mesh-model-routing.v0.1.json >/dev/null
python3 tools/validate_prophet_mesh_model_routing.py

validate-model-catalog-entry:
python3 -m json.tool schemas/model-catalog-entry.v0.1.schema.json >/dev/null
python3 tools/validate_model_catalog_entry.py examples/model-catalog-entry.admitted.json
python3 tools/validate_model_catalog_entry.py examples/model-catalog-entry.denied.epistemic-rejected.json --expect-denied
python3 tools/validate_model_catalog_entry.py examples/model-catalog-entry.denied.steering-diff-unsupported.json --expect-denied

test:
python3 -m pytest -q tools/tests

Expand Down
173 changes: 173 additions & 0 deletions contracts/sourceos/model-catalog-entry.v0.1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/**
* SourceOS — Model/Adapter Catalog Entry Contract
* Target: model-router (authority for routing + catalog resolution)
*
* Design basis:
* - Apple Foundation Models delivery (observed): frozen base + LoRA adapter overlays,
* content-addressed encrypted assets, pre-stage + atomic swap, cache-delete GC governor.
* - Anthropic Claude Code / OpenAI Codex (forensic, 2026-06-10): versioned bundle delivery
* done well, lifecycle GC done badly (version accumulation, orphan LaunchServices rows),
* capability surface gated by runtime prompt rather than declared + policy-admitted.
* - SourceOS differentiators: SAE interpretability, guardrail-fabric policy-as-code,
* Ontogenesis ontologies, SCOPE-D epistemic labeling, TriTRPC provenance wire,
* no-invisible-authority (everything declared, nothing discovered at runtime).
*
* Invariant: a model-router MUST refuse to admit or load an entry that fails
* attestation, hash, capability-policy, or epistemic-label checks. Admission is the gate.
*/

// ── Enumerations ────────────────────────────────────────────────────────────

/** What kind of artifact this entry carries. Mirrors Apple's base/adapter split. */
export type ArtifactKind =
| "base" // full base model (the frozen general model)
| "adapter" // LoRA-style overlay bound to a specific base version
| "steering" // SAE steering vectors only (no weights)
| "guardrail"; // policy/classifier artifact only

/** SAE steering capability tier (from Noetica: full | local | none, never boolean). */
export type SteeringTier = "full" | "local" | "none";

/** SCOPE-D epistemic level. An entry is inadmissible without one. */
export type EpistemicLevel =
| "proved"
| "bounded"
| "empirical"
| "synthetic"
| "speculative"
| "rejected"; // rejected entries are retained for audit but never loadable

/** Transport wire. TriTRPC is the SourceOS default (AEAD, byte-exact, ternary-native). */
export type CarryWire = "tritrpc" | "https-fallback";

// ── Sub-records ─────────────────────────────────────────────────────────────

/** Exact base-version binding. Forces adapter re-delivery on base change (Apple discipline). */
export interface BaseBinding {
baseModelId: string; // e.g. "sourceos.base.v3"
baseVersion: string; // exact semver; adapter is INVALID against any other
baseContentHash: string; // sha256 of the base this entry was trained/verified against
}

/** Content-addressed, encrypted artifact reference carried over the wire. */
export interface ArtifactRef {
contentHash: string; // sha256 — admission rejects on mismatch (hard stop)
sizeBytes: number;
encoding: "appleencryptedarchive-equiv" | "tritpack243" | "raw";
encrypted: true; // encryption-at-rest is an INVARIANT, not a flag to toggle
wire: CarryWire;
}

/** Interpretability surface. Apple ships none of this; it is a SourceOS primitive. */
export interface InterpretabilitySurface {
saeFeatureDictRef?: string; // content hash of the SAE feature dictionary
steeringVectors?: string[]; // content hashes of steering vectors (Neuronpedia-governed)
steeringTier: SteeringTier; // governs whether/how SAE steering may be applied
// Hard rule carried from Noetica: when steering is applied, the steered-vs-baseline
// diff MUST be surfaced. This flag asserts the entry supports diff emission.
emitsSteeringDiff: boolean;
}

/** Governance bindings. Travel WITH the artifact, hash-bound — safety is part of identity. */
export interface GovernanceBinding {
guardrailPolicyRef: string; // policy-as-code admitted by guardrail-fabric
ontologyRef?: string; // Ontogenesis ontology for guided/constrained generation
}

/**
* Declared capability surface (forensic lesson #2).
* guardrail-fabric admits/denies on THIS, not on what a bundle registers at runtime.
* Nothing may exercise a capability absent from declaredCapabilities.
*/
export interface CapabilityManifest {
declaredCapabilities: string[]; // e.g. ["inference.text", "tool.read", "tool.computer-use"]
requiredPermissions: string[]; // e.g. ["fs.read:/scoped", "net.egress:none"]
highPrivilege: boolean; // true ⇒ guardrail-fabric requires explicit policy grant
}

/**
* Attestation (forensic lesson #3 — the codesign/TeamIdentifier analogue).
* Checked at admission. Hash-chain anchors provenance across the TriTRPC boundary.
*/
export interface Attestation {
signer: string; // signing identity (the SourceOS analogue of TeamIdentifier)
signature: string; // detached signature over {contentHash, hashChain, capabilityManifest}
hashChain: string[]; // ordered provenance hashes (assetId → content → policy → url)
hardenedRuntime: boolean; // mirrors the vendor hardened-runtime posture
}

/** Evaluation results. An entry without eval + epistemic label is inadmissible. */
export interface EvaluationRecord {
evalFabricRunRef: string; // content hash of the eval-fabric result set
epistemicLevel: EpistemicLevel;
evaluatedAt: string; // RFC 3339
}

/**
* Lifecycle (forensic lessons #1 and #4).
* The entry OWNS its install/uninstall and retention. Do not leave GC to the OS registry —
* that is exactly how Claude Code accumulated 15 versions and Codex left orphan LS rows.
*/
export interface Lifecycle {
installManifest: {
placements: string[]; // exact on-disk locations this entry writes
registryRows: string[]; // exact registry/route rows it creates (for clean removal)
};
retentionPolicy: {
keepVersions: number; // e.g. 2 — reap older (Apple cache-delete discipline)
reapOrphanRows: boolean; // deregister + remove on uninstall; never accumulate
};
}

// ── Top-level entry ─────────────────────────────────────────────────────────

export interface ModelCatalogEntry {
// Identity
id: string; // e.g. "sourceos.adapter.summarize"
version: string; // exact semver
displayName: string;
kind: ArtifactKind;

// Carry
baseBinding: BaseBinding; // omit baseModelId only when kind === "base"
artifact: ArtifactRef;

// SourceOS-distinct surfaces (strictly more than Apple's {weights, adapter, hash})
interpretability: InterpretabilitySurface;
governance: GovernanceBinding;
capability: CapabilityManifest;

// Provenance + admission gates
attestation: Attestation;
evaluation: EvaluationRecord;

// Operational
lifecycle: Lifecycle;
createdAt: string; // RFC 3339
sourceCommit?: string; // originating repo commit, if applicable
}

// ── Admission ───────────────────────────────────────────────────────────────

export type AdmissionDenialReason =
| "content_hash_mismatch"
| "attestation_invalid"
| "base_version_mismatch"
| "capability_not_granted"
| "missing_epistemic_label"
| "epistemic_rejected"
| "steering_diff_unsupported"; // entry claims steering but can't emit the diff

export interface AdmissionResult {
admitted: boolean;
entryId: string;
denials: AdmissionDenialReason[]; // empty iff admitted
evidenceRef?: string; // agentplane provenance URI for the admission decision
}

/**
* Reference admission contract. Implementation lives in model-router; guardrail-fabric
* owns the capability/policy verdict. Every check here is a hard gate — a single failure
* denies. The decision itself is emitted as provenance (no silent admission).
*/
export type AdmitEntry = (entry: ModelCatalogEntry) => Promise<AdmissionResult>;
63 changes: 63 additions & 0 deletions examples/model-catalog-entry.admitted.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"id": "sourceos.adapter.summarize.v1",
"version": "1.0.0",
"displayName": "SourceOS Summarization Adapter v1",
"kind": "adapter",
"baseBinding": {
"baseModelId": "sourceos.base.v3",
"baseVersion": "3.0.0",
"baseContentHash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
},
"artifact": {
"contentHash": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"sizeBytes": 524288000,
"encoding": "tritpack243",
"encrypted": true,
"wire": "tritrpc"
},
"interpretability": {
"steeringTier": "local",
"emitsSteeringDiff": true,
"saeFeatureDictRef": "cafe1234cafe1234cafe1234cafe1234cafe1234cafe1234cafe1234cafe1234",
"steeringVectors": [
"1111111111111111111111111111111111111111111111111111111111111111"
]
},
"governance": {
"guardrailPolicyRef": "guardrail-fabric:policy:summarize-safe-v1",
"ontologyRef": "ontogenesis:summarization-domain:v1"
},
"capability": {
"declaredCapabilities": ["inference.text"],
"requiredPermissions": ["fs.read:none", "net.egress:none"],
"highPrivilege": false
},
"attestation": {
"signer": "sourceos.release.authority",
"signature": "3045022100f3a2b1c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2",
"hashChain": [
"sourceos.adapter.summarize.v1",
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"guardrail-fabric:policy:summarize-safe-v1",
"tritrpc://sourceos.artifacts/adapters/summarize.v1.0.0.pack"
],
"hardenedRuntime": true
},
"evaluation": {
"evalFabricRunRef": "eval-fabric:run:summarize-v1-20260610:abc123def456",
"epistemicLevel": "empirical",
"evaluatedAt": "2026-06-10T00:00:00Z"
},
"lifecycle": {
"installManifest": {
"placements": ["/var/sourceos/adapters/summarize.v1.0.0/"],
"registryRows": ["model-router:adapters:sourceos.adapter.summarize.v1"]
},
"retentionPolicy": {
"keepVersions": 2,
"reapOrphanRows": true
}
},
"createdAt": "2026-06-10T00:00:00Z",
"sourceCommit": "9431a9a"
}
58 changes: 58 additions & 0 deletions examples/model-catalog-entry.denied.epistemic-rejected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"_comment": "Denial reason: epistemic_rejected — epistemicLevel is 'rejected'; entry retained for audit only, never loadable.",
"id": "sourceos.adapter.summarize.v0-failed-eval",
"version": "0.9.0",
"displayName": "SourceOS Summarization Adapter v0 (failed eval)",
"kind": "adapter",
"baseBinding": {
"baseModelId": "sourceos.base.v3",
"baseVersion": "3.0.0",
"baseContentHash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
},
"artifact": {
"contentHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"sizeBytes": 524288000,
"encoding": "tritpack243",
"encrypted": true,
"wire": "tritrpc"
},
"interpretability": {
"steeringTier": "none",
"emitsSteeringDiff": false
},
"governance": {
"guardrailPolicyRef": "guardrail-fabric:policy:summarize-safe-v1"
},
"capability": {
"declaredCapabilities": ["inference.text"],
"requiredPermissions": ["fs.read:none", "net.egress:none"],
"highPrivilege": false
},
"attestation": {
"signer": "sourceos.release.authority",
"signature": "3045022100f3a2b1c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2",
"hashChain": [
"sourceos.adapter.summarize.v0-failed-eval",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"guardrail-fabric:policy:summarize-safe-v1",
"tritrpc://sourceos.artifacts/adapters/summarize.v0.9.0.pack"
],
"hardenedRuntime": true
},
"evaluation": {
"evalFabricRunRef": "eval-fabric:run:summarize-v0-20260601:failed001",
"epistemicLevel": "rejected",
"evaluatedAt": "2026-06-01T00:00:00Z"
},
"lifecycle": {
"installManifest": {
"placements": ["/var/sourceos/adapters/summarize.v0.9.0/"],
"registryRows": ["model-router:adapters:sourceos.adapter.summarize.v0-failed-eval"]
},
"retentionPolicy": {
"keepVersions": 2,
"reapOrphanRows": true
}
},
"createdAt": "2026-06-01T00:00:00Z"
}
Loading
Loading