diff --git a/docs/sourceos-model-carry-ref.md b/docs/sourceos-model-carry-ref.md new file mode 100644 index 0000000..0c1589c --- /dev/null +++ b/docs/sourceos-model-carry-ref.md @@ -0,0 +1,55 @@ +# SourceOSModelCarryRef + +Status: additive carry-layer projection fixture + +## Purpose + +`SourceOSModelCarryRef` is the SourceOS typed-contract projection for an approved on-device reference to a governed model or model-service profile. It complements the existing `SourceOSCarryRef` service reference examples and the existing `LocalModelProfile` laptop-safe local model profiles. + +The object is intentionally reference-only. It must not embed mutable model weights, mutable adapters, credentials, user tuning data, or runtime authorization grants. + +## Current fixture + +```text +examples/sourceos-model-carry-ref.local-llama32-3b.json +``` + +This fixture links the local `llama32-3b` style profile into the broader Prophet Foundry path: + +```text +model-governance-ledger +→ model-router +→ sourceos-model-carry +→ agent-machine +→ agentplane +``` + +## Validation + +Run: + +```bash +python3 tools/validate_sourceos_model_carry_refs.py +``` + +The validator checks: + +- `type == SourceOSModelCarryRef` +- `id` uses `urn:srcos:model-carry-ref:` +- `specVersion == 2.1.0` +- `governanceRef` is present +- `routerProfileRef` uses `urn:srcos:model-router-profile:` +- `mutableModelState` is false +- release and fallback references use the expected URN namespaces + +## Boundary rules + +1. A carry reference is not a model promotion decision. +2. A carry reference is not a runtime route decision. +3. A carry reference is not a permission grant. +4. SourceOS may carry approved references, cache policy, launch profile references, fallback references, and evidence references. +5. SourceOS must not become authority for model lifecycle, model promotion, personal tuning authorization, or runtime side effects. + +## Follow-up + +After the SourceOS projection contracts stabilize, this validator should be wired into the default `make validate` target alongside existing carry-reference and CLI checks. diff --git a/examples/sourceos-model-carry-ref.local-llama32-3b.json b/examples/sourceos-model-carry-ref.local-llama32-3b.json new file mode 100644 index 0000000..3dbdef9 --- /dev/null +++ b/examples/sourceos-model-carry-ref.local-llama32-3b.json @@ -0,0 +1,15 @@ +{ + "id": "urn:srcos:model-carry-ref:local-llama32-3b-office-assist", + "type": "SourceOSModelCarryRef", + "specVersion": "2.1.0", + "modelRef": "urn:prophet:model:llama32-3b-local-office-assist", + "governanceRef": "urn:prophet:model-release-decision:local-llama32-3b-office-assist-20260504", + "routerProfileRef": "urn:srcos:model-router-profile:local-first-office-assist", + "releaseSetRefs": ["urn:srcos:release-set:sourceos-workstation-m2-20260504"], + "launchProfileRefs": ["urn:srcos:model-launch-profile:llama-cpp-local-office-assist"], + "fallbackRefs": ["urn:srcos:model-carry-ref:local-llama32-1b-router"], + "carryPolicy": "download-on-demand", + "cachePolicy": "weights-cache-allowed", + "mutableModelState": false, + "evidenceRefs": ["sha256:2e7f1c7f0a6a4bbd9ef000000000000000000000000000000000000000000"] +} diff --git a/tools/validate_sourceos_model_carry_refs.py b/tools/validate_sourceos_model_carry_refs.py new file mode 100644 index 0000000..ee1ad8e --- /dev/null +++ b/tools/validate_sourceos_model_carry_refs.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +"""Validate SourceOSModelCarryRef projection examples. + +This validator is intentionally lightweight and stdlib-only. Full JSON Schema +validation belongs in SourceOS-Linux/sourceos-spec; this repository validates the +carry-layer invariants it must preserve locally. +""" + +from __future__ import annotations + +import json +import sys +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parents[1] +EXAMPLES = sorted((ROOT / "examples").glob("sourceos-model-carry-ref.*.json")) + + +class ValidationError(Exception): + pass + + +def load_json(path: Path) -> Any: + try: + return json.loads(path.read_text(encoding="utf-8")) + except FileNotFoundError as exc: + raise ValidationError(f"missing file: {path.relative_to(ROOT)}") from exc + except json.JSONDecodeError as exc: + raise ValidationError(f"invalid JSON in {path.relative_to(ROOT)}: {exc}") from exc + + +def require(condition: bool, message: str) -> None: + if not condition: + raise ValidationError(message) + + +def validate_ref(path: Path, ref: dict[str, Any]) -> None: + rel = path.relative_to(ROOT) + require(ref.get("type") == "SourceOSModelCarryRef", f"{rel}: type must be SourceOSModelCarryRef") + require(str(ref.get("id", "")).startswith("urn:srcos:model-carry-ref:"), f"{rel}: id must be a model-carry-ref URN") + require(ref.get("specVersion") == "2.1.0", f"{rel}: specVersion must be 2.1.0") + require(ref.get("modelRef"), f"{rel}: modelRef is required") + require(ref.get("governanceRef"), f"{rel}: governanceRef is required") + require(str(ref.get("routerProfileRef", "")).startswith("urn:srcos:model-router-profile:"), f"{rel}: routerProfileRef must be a model-router-profile URN") + require(ref.get("carryPolicy") in {"reference-only", "download-on-demand", "preload-reference", "disabled"}, f"{rel}: invalid carryPolicy") + require(ref.get("cachePolicy") in {"none", "metadata-only", "weights-cache-allowed", "kv-cache-allowed", "embedding-cache-allowed"}, f"{rel}: invalid cachePolicy") + require(ref.get("mutableModelState") is False, f"{rel}: mutableModelState must be false") + for release_ref in ref.get("releaseSetRefs", []): + require(str(release_ref).startswith("urn:srcos:release-set:"), f"{rel}: releaseSetRefs entries must be release-set URNs") + for fallback_ref in ref.get("fallbackRefs", []): + require(str(fallback_ref).startswith("urn:srcos:model-carry-ref:"), f"{rel}: fallbackRefs entries must be model-carry-ref URNs") + + +def main() -> int: + if not EXAMPLES: + print("ERR: no SourceOSModelCarryRef examples found", file=sys.stderr) + return 2 + try: + for example in EXAMPLES: + validate_ref(example, load_json(example)) + print(f"ok: {example.relative_to(ROOT)}") + except ValidationError as exc: + print(f"ERR: {exc}", file=sys.stderr) + return 1 + print("SourceOSModelCarryRef validation passed") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())