diff --git a/.github/workflows/sourceos-interaction-reference-flow.yml b/.github/workflows/sourceos-interaction-reference-flow.yml new file mode 100644 index 0000000..416230e --- /dev/null +++ b/.github/workflows/sourceos-interaction-reference-flow.yml @@ -0,0 +1,35 @@ +name: SourceOS Interaction Reference Flow + +on: + pull_request: + branches: ["main"] + paths: + - "examples/interaction-flow/noetica-superconscious-agentplane-agentterm.flow.json" + - "docs/contract-additions/sourceos-interaction-reference-flow.md" + - "tools/validate_interaction_flow_reference.py" + - ".github/workflows/sourceos-interaction-reference-flow.yml" + push: + branches: ["main", "work/sourceos-interaction-reference-packet"] + paths: + - "examples/interaction-flow/noetica-superconscious-agentplane-agentterm.flow.json" + - "docs/contract-additions/sourceos-interaction-reference-flow.md" + - "tools/validate_interaction_flow_reference.py" + - ".github/workflows/sourceos-interaction-reference-flow.yml" + +permissions: + contents: read + +jobs: + validate-interaction-reference-flow: + name: Validate interaction reference flow + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Validate reference flow packet + run: python tools/validate_interaction_flow_reference.py diff --git a/docs/contract-additions/sourceos-interaction-reference-flow.md b/docs/contract-additions/sourceos-interaction-reference-flow.md new file mode 100644 index 0000000..6794e49 --- /dev/null +++ b/docs/contract-additions/sourceos-interaction-reference-flow.md @@ -0,0 +1,63 @@ +# SourceOS Interaction Reference Flow v0.1 + +Status: Informational reference packet +Manifest: `examples/interaction-flow/noetica-superconscious-agentplane-agentterm.flow.json` + +## Purpose + +This reference packet pins the current end-to-end SourceOS interaction substrate path: + +```text +Noetica emits SourceOSInteractionEvent + -> Superconscious binds the interaction at the task/cognition boundary + -> AgentPlane attaches execution evidence and replay refs + -> AgentTerm renders and records the governance trace +``` + +The packet exists to make the current multi-repo implementation auditable as one governed interaction path, without moving authority into a new plane. + +## Authority map + +| Plane | Authority | +| --- | --- | +| `SourceOS-Linux/sourceos-spec` | Canonical schema and generated contract artifacts. | +| `SocioProphet/Noetica` | Browser chat, model-selection, steering UX, and inline governance-trail surface. | +| `SocioProphet/superconscious` | Task/cognition coordination boundary. | +| `SocioProphet/agentplane` | Execution evidence, run artifacts, validation artifacts, placement artifacts, and replay artifacts. | +| `SourceOS-Linux/agent-term` | Terminal/operator rendering and local event-recording surface. | +| Policy Fabric | Policy admission authority. | +| Agent Registry | Identity, grants, sessions, and revocation authority. | +| Memory Mesh | Durable memory and context-pack authority. | + +## Pinned implementation commits + +The reference manifest records the exact downstream commits that completed the first implementation wave: + +| Repository | Commit | Role | +| --- | --- | --- | +| `SourceOS-Linux/sourceos-spec` | `c7f8c2d9e42a56e1127c2f9b85649cbea0f0a9fa` | Canonical schema/codegen/catalog. | +| `SocioProphet/Noetica` | `2a73b44338335a39283bcf65b4e072e29b8946a3` | Emitter and TypeScript contract-sync check. | +| `SourceOS-Linux/agent-term` | `076db5f0ebd6acae665a0b3b90e56c88735bc301` | Renderer/recorder and Python contract-sync check. | +| `SocioProphet/superconscious` | `a4742b092584432871a7a15da49e15f054b8d393` | Task-boundary binding. | +| `SocioProphet/agentplane` | `e9797a8358405475fc12eb94d5c6b00547bd0ddf` | Evidence/replay binding. | + +## Payload posture + +The reference packet is ref-oriented. It must not contain raw secrets, credentials, unrestricted browser history, unrestricted shell output, unrestricted transcripts, private chain-of-thought, private reasoning, or raw execution logs. + +## Validation + +Run: + +```bash +python tools/validate_interaction_flow_reference.py +``` + +The validator checks: + +- required repository roles are present; +- pinned commits are present; +- interaction event refs use the canonical `urn:srcos:interaction-event:` prefix; +- the authority map preserves separation of concerns; +- forbidden payload categories are recorded; +- validation references include downstream sync/boundary/evidence checks. diff --git a/examples/interaction-flow/noetica-superconscious-agentplane-agentterm.flow.json b/examples/interaction-flow/noetica-superconscious-agentplane-agentterm.flow.json new file mode 100644 index 0000000..ff1ee26 --- /dev/null +++ b/examples/interaction-flow/noetica-superconscious-agentplane-agentterm.flow.json @@ -0,0 +1,158 @@ +{ + "schemaVersion": "sourceos.interaction-flow-reference.v0.1", + "flowId": "urn:srcos:interaction-flow:noetica-superconscious-agentplane-agentterm-0001", + "specVersion": "2.0.0", + "description": "Canonical reference packet linking Noetica emission, Superconscious task-boundary binding, AgentPlane evidence binding, and AgentTerm rendering over SourceOSInteractionEvent references.", + "sourceosSpec": { + "repo": "SourceOS-Linux/sourceos-spec", + "pinnedCommit": "c7f8c2d9e42a56e1127c2f9b85649cbea0f0a9fa", + "schemaRef": "schemas/SourceOSInteractionEvent.json", + "exampleRef": "examples/sourceos-interaction-event.json", + "generatedTypeRefs": [ + "generated/typescript/sourceos-interaction-event.ts", + "generated/python/sourceos_interaction_event.py" + ] + }, + "interactionEvents": { + "noeticaEmitted": "urn:srcos:interaction-event:noetica-standalone-complete-0001", + "superconsciousAccepted": "urn:srcos:interaction-event:superconscious-boundary-accepted-0001", + "agentplaneCompleted": "urn:srcos:interaction-event:agentplane-run-completed-0001", + "agenttermRendered": "urn:srcos:interaction-event:agentterm-rendered-governance-trace-0001" + }, + "repositories": [ + { + "repo": "SocioProphet/Noetica", + "role": "browser-chat-surface", + "pinnedCommit": "2a73b44338335a39283bcf65b4e072e29b8946a3", + "obligations": [ + "emit SourceOSInteractionEvent from standalone and SourceOS chat lifecycle", + "show inline governance trace", + "sync-check generated TypeScript contract artifact" + ], + "sourceRefs": [ + "SocioProphet/Noetica#16", + "SocioProphet/Noetica#17", + "SocioProphet/Noetica#18" + ], + "ownsAuthority": [ + "browser chat UX", + "model-selection UX", + "steering UX" + ], + "doesNotOwnAuthority": [ + "policy admission", + "agent grants", + "durable memory writeback", + "AgentPlane execution evidence", + "SourceOSInteractionEvent schema" + ] + }, + { + "repo": "SocioProphet/superconscious", + "role": "task-cognition-coordinator", + "pinnedCommit": "a4742b092584432871a7a15da49e15f054b8d393", + "obligations": [ + "accept or emit SourceOSInteractionEvent references at the task boundary", + "preserve policy/grant/memory/evidence refs", + "reject authority drift into policy, grant, memory, routing, or evidence ownership" + ], + "sourceRefs": [ + "SocioProphet/superconscious#60" + ], + "ownsAuthority": [ + "task/cognition coordination" + ], + "doesNotOwnAuthority": [ + "policy admission", + "agent grants", + "durable memory writeback", + "model routing", + "AgentPlane evidence", + "SourceOSInteractionEvent schema" + ] + }, + { + "repo": "SocioProphet/agentplane", + "role": "execution-evidence-replay-authority", + "pinnedCommit": "e9797a8358405475fc12eb94d5c6b00547bd0ddf", + "obligations": [ + "attach run/evidence/replay refs to SourceOSInteractionEvent governance traces", + "require hash-qualified artifact refs", + "reject raw execution log, credential, secret, transcript, shell-output, or private-reasoning leakage" + ], + "sourceRefs": [ + "SocioProphet/agentplane#253" + ], + "ownsAuthority": [ + "execution evidence", + "run artifacts", + "replay artifacts", + "validation artifacts", + "placement artifacts" + ], + "doesNotOwnAuthority": [ + "policy admission", + "agent grants", + "Memory Mesh semantics", + "Noetica UI state", + "AgentTerm terminal state", + "SourceOSInteractionEvent schema" + ] + }, + { + "repo": "SourceOS-Linux/agent-term", + "role": "terminal-operator-surface", + "pinnedCommit": "076db5f0ebd6acae665a0b3b90e56c88735bc301", + "obligations": [ + "ingest/render/record SourceOSInteractionEvent governance traces", + "use generated Python contract artifact", + "sync-check generated Python contract artifact" + ], + "sourceRefs": [ + "SourceOS-Linux/agent-term#46", + "SourceOS-Linux/agent-term#47", + "SourceOS-Linux/agent-term#48" + ], + "ownsAuthority": [ + "terminal operator rendering", + "operator event recording surface" + ], + "doesNotOwnAuthority": [ + "cognition loop", + "policy admission", + "agent grants", + "durable memory writeback", + "AgentPlane evidence", + "SourceOSInteractionEvent schema" + ] + } + ], + "authorityBoundaries": { + "sourceosSpec": "canonical schema and generated artifact authority", + "noetica": "browser chat/model/steering surface", + "superconscious": "task/cognition coordination boundary", + "agentplane": "execution evidence and replay authority", + "agentTerm": "terminal/operator rendering surface", + "policyFabric": "policy admission authority", + "agentRegistry": "identity, grants, sessions, and revocation authority", + "memoryMesh": "durable memory and context-pack authority" + }, + "forbiddenPayloads": [ + "raw secrets", + "credentials", + "unrestricted browser history", + "unrestricted shell output", + "unrestricted transcripts", + "private chain-of-thought", + "private reasoning", + "raw execution logs" + ], + "validationRefs": [ + "tools/validate_sourceos_interaction_examples.py", + "tools/validate_interaction_flow_reference.py", + "SocioProphet/Noetica/.github/workflows/sourceos-contract-sync.yml", + "SourceOS-Linux/agent-term/.github/workflows/sourceos-contract-sync.yml", + "SocioProphet/superconscious/scripts/check_sourceos_interaction_boundary.py", + "SocioProphet/agentplane/tools/validate_sourceos_interaction_evidence_binding.py" + ] +} diff --git a/tools/validate_interaction_flow_reference.py b/tools/validate_interaction_flow_reference.py new file mode 100644 index 0000000..2e9112e --- /dev/null +++ b/tools/validate_interaction_flow_reference.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +"""Validate the SourceOS interaction reference-flow packet.""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parents[1] +FLOW = ROOT / "examples" / "interaction-flow" / "noetica-superconscious-agentplane-agentterm.flow.json" + +REQUIRED_REPOS = { + "SocioProphet/Noetica": "browser-chat-surface", + "SocioProphet/superconscious": "task-cognition-coordinator", + "SocioProphet/agentplane": "execution-evidence-replay-authority", + "SourceOS-Linux/agent-term": "terminal-operator-surface", +} + +REQUIRED_AUTHORITY_KEYS = { + "sourceosSpec", + "noetica", + "superconscious", + "agentplane", + "agentTerm", + "policyFabric", + "agentRegistry", + "memoryMesh", +} + +REQUIRED_FORBIDDEN_PAYLOADS = { + "raw secrets", + "credentials", + "unrestricted browser history", + "unrestricted shell output", + "unrestricted transcripts", + "private chain-of-thought", + "private reasoning", + "raw execution logs", +} + +REQUIRED_VALIDATION_REF_FRAGMENTS = { + "validate_sourceos_interaction_examples.py", + "validate_interaction_flow_reference.py", + "sourceos-contract-sync.yml", + "check_sourceos_interaction_boundary.py", + "validate_sourceos_interaction_evidence_binding.py", +} + +INTERACTION_EVENT_PREFIX = "urn:srcos:interaction-event:" + + +def load(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("flow reference root must be a JSON object") + return data + + +def main() -> int: + flow = load(FLOW) + + require_equal(flow.get("schemaVersion"), "sourceos.interaction-flow-reference.v0.1", "schemaVersion") + require_prefix(flow.get("flowId"), "urn:srcos:interaction-flow:", "flowId") + require_equal(flow.get("specVersion"), "2.0.0", "specVersion") + + sourceos_spec = require_object(flow, "sourceosSpec") + require_equal(sourceos_spec.get("repo"), "SourceOS-Linux/sourceos-spec", "sourceosSpec.repo") + require_nonempty(sourceos_spec.get("pinnedCommit"), "sourceosSpec.pinnedCommit") + require_equal(sourceos_spec.get("schemaRef"), "schemas/SourceOSInteractionEvent.json", "sourceosSpec.schemaRef") + require_nonempty_list(sourceos_spec.get("generatedTypeRefs"), "sourceosSpec.generatedTypeRefs") + + interaction_events = require_object(flow, "interactionEvents") + for key, value in interaction_events.items(): + require_prefix(value, INTERACTION_EVENT_PREFIX, f"interactionEvents.{key}") + + repositories = flow.get("repositories") + if not isinstance(repositories, list): + raise ValueError("repositories must be a list") + by_repo = {entry.get("repo"): entry for entry in repositories if isinstance(entry, dict)} + + for repo, role in REQUIRED_REPOS.items(): + if repo not in by_repo: + raise ValueError(f"missing repository binding: {repo}") + entry = by_repo[repo] + require_equal(entry.get("role"), role, f"repositories[{repo}].role") + require_nonempty(entry.get("pinnedCommit"), f"repositories[{repo}].pinnedCommit") + require_nonempty_list(entry.get("obligations"), f"repositories[{repo}].obligations") + require_nonempty_list(entry.get("sourceRefs"), f"repositories[{repo}].sourceRefs") + require_nonempty_list(entry.get("ownsAuthority"), f"repositories[{repo}].ownsAuthority") + require_nonempty_list(entry.get("doesNotOwnAuthority"), f"repositories[{repo}].doesNotOwnAuthority") + + authority_boundaries = require_object(flow, "authorityBoundaries") + missing_authorities = REQUIRED_AUTHORITY_KEYS - set(authority_boundaries) + if missing_authorities: + raise ValueError("missing authority boundaries: " + ", ".join(sorted(missing_authorities))) + + forbidden_payloads = set(flow.get("forbiddenPayloads") or []) + missing_forbidden = REQUIRED_FORBIDDEN_PAYLOADS - forbidden_payloads + if missing_forbidden: + raise ValueError("missing forbidden payload classes: " + ", ".join(sorted(missing_forbidden))) + + validation_refs = flow.get("validationRefs") + if not isinstance(validation_refs, list) or not validation_refs: + raise ValueError("validationRefs must be a non-empty list") + validation_text = "\n".join(str(item) for item in validation_refs) + for fragment in REQUIRED_VALIDATION_REF_FRAGMENTS: + if fragment not in validation_text: + raise ValueError(f"validationRefs missing fragment: {fragment}") + + print("OK: SourceOS interaction reference flow validated") + return 0 + + +def require_object(parent: dict[str, Any], key: str) -> dict[str, Any]: + value = parent.get(key) + if not isinstance(value, dict): + raise ValueError(f"{key} must be an object") + return value + + +def require_equal(actual: Any, expected: Any, label: str) -> None: + if actual != expected: + raise ValueError(f"{label}: expected {expected!r}, got {actual!r}") + + +def require_prefix(value: Any, prefix: str, label: str) -> None: + if not isinstance(value, str) or not value.startswith(prefix): + raise ValueError(f"{label} must be a string starting with {prefix!r}") + + +def require_nonempty(value: Any, label: str) -> None: + if not isinstance(value, str) or not value: + raise ValueError(f"{label} must be a non-empty string") + + +def require_nonempty_list(value: Any, label: str) -> None: + if not isinstance(value, list) or not value: + raise ValueError(f"{label} must be a non-empty list") + + +if __name__ == "__main__": + raise SystemExit(main())