From ce46cc374ae6fd63129f0bc0d9df590182872593 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 30 May 2026 12:46:57 -0400 Subject: [PATCH 1/5] Add SourceOS interaction type generator --- tools/generate_sourceos_interaction_types.py | 326 +++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 tools/generate_sourceos_interaction_types.py diff --git a/tools/generate_sourceos_interaction_types.py b/tools/generate_sourceos_interaction_types.py new file mode 100644 index 0000000..a2e6324 --- /dev/null +++ b/tools/generate_sourceos_interaction_types.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python3 +"""Generate SourceOSInteractionEvent TypeScript and Python type mirrors. + +This is intentionally focused on the SourceOS interaction substrate instead of a +general-purpose JSON Schema compiler. The canonical source remains +schemas/SourceOSInteractionEvent.json. Downstream repos may vendor the generated +artifacts or run this script from a pinned sourceos-spec revision. +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Any + + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA_PATH = ROOT / "schemas" / "SourceOSInteractionEvent.json" +TS_OUT = ROOT / "generated" / "typescript" / "sourceos-interaction-event.ts" +PY_OUT = ROOT / "generated" / "python" / "sourceos_interaction_event.py" + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check", action="store_true", help="Fail if generated artifacts are stale.") + args = parser.parse_args() + + schema = load_schema() + ts_content = generate_typescript(schema) + py_content = generate_python(schema) + + outputs = { + TS_OUT: ts_content, + PY_OUT: py_content, + } + + if args.check: + stale = [path for path, content in outputs.items() if not path.exists() or path.read_text(encoding="utf-8") != content] + if stale: + for path in stale: + print(f"stale generated artifact: {path.relative_to(ROOT)}") + return 1 + return 0 + + for path, content in outputs.items(): + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + print(f"wrote {path.relative_to(ROOT)}") + + return 0 + + +def load_schema() -> dict[str, Any]: + with SCHEMA_PATH.open("r", encoding="utf-8") as handle: + schema = json.load(handle) + if schema.get("title") != "SourceOSInteractionEvent": + raise SystemExit("unexpected schema title; expected SourceOSInteractionEvent") + return schema + + +def prop(schema: dict[str, Any], *path: str) -> dict[str, Any]: + cursor: Any = schema + for key in path: + cursor = cursor[key] + if not isinstance(cursor, dict): + raise TypeError(f"schema path does not resolve to object: {'.'.join(path)}") + return cursor + + +def enum_values(schema: dict[str, Any], *path: str) -> list[str]: + values = prop(schema, *path).get("enum") + if not isinstance(values, list) or not all(isinstance(item, str) for item in values): + raise TypeError(f"schema path does not expose string enum: {'.'.join(path)}") + return values + + +def ts_union(values: list[str]) -> str: + return " | ".join(json.dumps(value) for value in values) + + +def py_literal(values: list[str]) -> str: + return "Literal[" + ", ".join(repr(value) for value in values) + "]" + + +def generated_header(comment: str) -> str: + return f"""{comment} Generated from schemas/SourceOSInteractionEvent.json. +{comment} Do not edit by hand. Run: python tools/generate_sourceos_interaction_types.py + +""" + + +def generate_typescript(schema: dict[str, Any]) -> str: + event_classes = ts_union(enum_values(schema, "properties", "eventClass")) + surface_kinds = ts_union(enum_values(schema, "properties", "surface", "properties", "surfaceKind")) + modes = ts_union(enum_values(schema, "properties", "mode")) + actor_kinds = ts_union(enum_values(schema, "properties", "actor", "properties", "actorKind")) + participant_roles = ts_union(enum_values(schema, "properties", "participants", "items", "properties", "role")) + task_statuses = ts_union(enum_values(schema, "properties", "task", "properties", "status")) + steering_kinds = ts_union(enum_values(schema, "properties", "steeringIntent", "properties", "steeringKind")) + steering_statuses = ts_union(enum_values(schema, "properties", "steeringIntent", "properties", "status")) + payload_modes = ts_union(enum_values(schema, "properties", "payloadMode")) + required = ", ".join(schema["required"]) + + return generated_header("//") + f"""export const SOURCEOS_INTERACTION_EVENT_REQUIRED = {json.dumps(schema["required"], indent=2)} as const + +export type SourceOSInteractionEventClass = {event_classes} +export type SourceOSInteractionSurfaceKind = {surface_kinds} +export type SourceOSInteractionMode = {modes} +export type SourceOSInteractionActorKind = {actor_kinds} +export type SourceOSInteractionParticipantRole = {participant_roles} +export type SourceOSInteractionTaskStatus = {task_statuses} +export type SourceOSSteeringKind = {steering_kinds} +export type SourceOSSteeringStatus = {steering_statuses} +export type SourceOSInteractionPayloadMode = {payload_modes} + +export interface SourceOSInteractionSurface {{ + surfaceKind: SourceOSInteractionSurfaceKind + sourcePlane: string + clientRef?: string | null +}} + +export interface SourceOSInteractionSession {{ + sessionId: string + conversationRef?: string | null + roomRef?: string | null + threadRef?: string | null + workroomRef?: string | null + topicRef?: string | null + opsHistoryEventRef?: string | null +}} + +export interface SourceOSInteractionActor {{ + actorRef: string + actorKind: SourceOSInteractionActorKind + agentRegistryRef?: string | null + onBehalfOfRef?: string | null +}} + +export interface SourceOSInteractionParticipant {{ + role: SourceOSInteractionParticipantRole + participantRef: string + agentRegistryRef?: string | null +}} + +export interface SourceOSInteractionTask {{ + taskRef?: string | null + status?: SourceOSInteractionTaskStatus + modelHint?: string | null + modelRouted?: string | null + provider?: string | null + latencyMs?: number | null +}} + +export interface SourceOSSteeringIntent {{ + steeringKind?: SourceOSSteeringKind + featureRef?: string | null + strength?: number | null + status?: SourceOSSteeringStatus +}} + +export interface SourceOSGovernanceTrace {{ + policyAdmitted: boolean + policyRef?: string | null + policyDecisionRefs?: string[] + grantRefs?: string[] + memoryScopeRef?: string | null + memoryWritten: boolean + contextPackRefs?: string[] + requestHash?: string | null + evidenceHash?: string | null + providerRouteEvidenceRef?: string | null + agentPlaneRunRef?: string | null + evidenceRefs?: string[] + replayRef?: string | null +}} + +export interface SourceOSInteractionIntegrity {{ + eventHash?: string | null + signature?: string | null +}} + +export interface SourceOSInteractionEvent {{ + interactionEventId: string + type: "SourceOSInteractionEvent" + specVersion: string + eventClass: SourceOSInteractionEventClass + occurredAt: string + surface: SourceOSInteractionSurface + mode: SourceOSInteractionMode + session: SourceOSInteractionSession + actor: SourceOSInteractionActor + participants?: SourceOSInteractionParticipant[] + task?: SourceOSInteractionTask | null + steeringIntent?: SourceOSSteeringIntent | null + governanceTrace: SourceOSGovernanceTrace + payloadMode: SourceOSInteractionPayloadMode + payload?: Record | null + sourceEventRefs?: string[] + redactionRefs?: string[] + integrity?: SourceOSInteractionIntegrity | null +}} + +// Required top-level fields in the canonical schema: {required} +""" + + +def generate_python(schema: dict[str, Any]) -> str: + event_classes = py_literal(enum_values(schema, "properties", "eventClass")) + surface_kinds = py_literal(enum_values(schema, "properties", "surface", "properties", "surfaceKind")) + modes = py_literal(enum_values(schema, "properties", "mode")) + actor_kinds = py_literal(enum_values(schema, "properties", "actor", "properties", "actorKind")) + participant_roles = py_literal(enum_values(schema, "properties", "participants", "items", "properties", "role")) + task_statuses = py_literal(enum_values(schema, "properties", "task", "properties", "status")) + steering_kinds = py_literal(enum_values(schema, "properties", "steeringIntent", "properties", "steeringKind")) + steering_statuses = py_literal(enum_values(schema, "properties", "steeringIntent", "properties", "status")) + payload_modes = py_literal(enum_values(schema, "properties", "payloadMode")) + + return generated_header("#") + f"""from __future__ import annotations + +from typing import Any, Literal, NotRequired, TypedDict + + +SOURCEOS_INTERACTION_EVENT_REQUIRED = {schema["required"]!r} + +SourceOSInteractionEventClass = {event_classes} +SourceOSInteractionSurfaceKind = {surface_kinds} +SourceOSInteractionMode = {modes} +SourceOSInteractionActorKind = {actor_kinds} +SourceOSInteractionParticipantRole = {participant_roles} +SourceOSInteractionTaskStatus = {task_statuses} +SourceOSSteeringKind = {steering_kinds} +SourceOSSteeringStatus = {steering_statuses} +SourceOSInteractionPayloadMode = {payload_modes} + + +class SourceOSInteractionSurface(TypedDict): + surfaceKind: SourceOSInteractionSurfaceKind + sourcePlane: str + clientRef: NotRequired[str | None] + + +class SourceOSInteractionSession(TypedDict): + sessionId: str + conversationRef: NotRequired[str | None] + roomRef: NotRequired[str | None] + threadRef: NotRequired[str | None] + workroomRef: NotRequired[str | None] + topicRef: NotRequired[str | None] + opsHistoryEventRef: NotRequired[str | None] + + +class SourceOSInteractionActor(TypedDict): + actorRef: str + actorKind: SourceOSInteractionActorKind + agentRegistryRef: NotRequired[str | None] + onBehalfOfRef: NotRequired[str | None] + + +class SourceOSInteractionParticipant(TypedDict): + role: SourceOSInteractionParticipantRole + participantRef: str + agentRegistryRef: NotRequired[str | None] + + +class SourceOSInteractionTask(TypedDict, total=False): + taskRef: str | None + status: SourceOSInteractionTaskStatus + modelHint: str | None + modelRouted: str | None + provider: str | None + latencyMs: int | None + + +class SourceOSSteeringIntent(TypedDict, total=False): + steeringKind: SourceOSSteeringKind + featureRef: str | None + strength: float | None + status: SourceOSSteeringStatus + + +class SourceOSGovernanceTrace(TypedDict): + policyAdmitted: bool + memoryWritten: bool + policyRef: NotRequired[str | None] + policyDecisionRefs: NotRequired[list[str]] + grantRefs: NotRequired[list[str]] + memoryScopeRef: NotRequired[str | None] + contextPackRefs: NotRequired[list[str]] + requestHash: NotRequired[str | None] + evidenceHash: NotRequired[str | None] + providerRouteEvidenceRef: NotRequired[str | None] + agentPlaneRunRef: NotRequired[str | None] + evidenceRefs: NotRequired[list[str]] + replayRef: NotRequired[str | None] + + +class SourceOSInteractionIntegrity(TypedDict, total=False): + eventHash: str | None + signature: str | None + + +class SourceOSInteractionEvent(TypedDict): + interactionEventId: str + type: Literal["SourceOSInteractionEvent"] + specVersion: str + eventClass: SourceOSInteractionEventClass + occurredAt: str + surface: SourceOSInteractionSurface + mode: SourceOSInteractionMode + session: SourceOSInteractionSession + actor: SourceOSInteractionActor + payloadMode: SourceOSInteractionPayloadMode + governanceTrace: SourceOSGovernanceTrace + participants: NotRequired[list[SourceOSInteractionParticipant]] + task: NotRequired[SourceOSInteractionTask | None] + steeringIntent: NotRequired[SourceOSSteeringIntent | None] + payload: NotRequired[dict[str, Any] | None] + sourceEventRefs: NotRequired[list[str]] + redactionRefs: NotRequired[list[str]] + integrity: NotRequired[SourceOSInteractionIntegrity | None] +""" + + +if __name__ == "__main__": + raise SystemExit(main()) From 1430380f19fbc60ed1fdd5a3ff598db615bb41b7 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 30 May 2026 12:47:21 -0400 Subject: [PATCH 2/5] Add generated TypeScript interaction types --- .../typescript/sourceos-interaction-event.ts | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 generated/typescript/sourceos-interaction-event.ts diff --git a/generated/typescript/sourceos-interaction-event.ts b/generated/typescript/sourceos-interaction-event.ts new file mode 100644 index 0000000..16f34e1 --- /dev/null +++ b/generated/typescript/sourceos-interaction-event.ts @@ -0,0 +1,115 @@ +// Generated from schemas/SourceOSInteractionEvent.json. +// Do not edit by hand. Run: python tools/generate_sourceos_interaction_types.py + +export const SOURCEOS_INTERACTION_EVENT_REQUIRED = [ + "interactionEventId", + "type", + "specVersion", + "eventClass", + "occurredAt", + "surface", + "mode", + "session", + "actor", + "payloadMode", + "governanceTrace" +] as const + +export type SourceOSInteractionEventClass = "interaction.session_started" | "interaction.message_posted" | "interaction.task_submitted" | "interaction.task_stream_delta" | "interaction.task_completed" | "interaction.task_failed" | "interaction.governance_trace" | "interaction.steering_intent" | "interaction.memory_scope_bound" | "interaction.context_pack_bound" | "interaction.policy_decision" | "interaction.approval_requested" | "interaction.approval_recorded" | "interaction.redacted" +export type SourceOSInteractionSurfaceKind = "noetica" | "agent-term" | "matrix" | "prophet-workspace" | "superconscious" | "agentplane" | "api" | "other" +export type SourceOSInteractionMode = "standalone" | "sourceos" | "dry-run" | "replay" +export type SourceOSInteractionActorKind = "human" | "agent" | "service" | "bot" | "system" +export type SourceOSInteractionParticipantRole = "user" | "assistant" | "operator" | "agent" | "provider" | "tool" | "observer" +export type SourceOSInteractionTaskStatus = "submitted" | "streaming" | "success" | "failure" | "blocked" | "unavailable" | "not_configured" +export type SourceOSSteeringKind = "none" | "neuronpedia_feature" | "local_sae" | "sourceos_local" | "other" +export type SourceOSSteeringStatus = "requested" | "applied" | "noop" | "not_configured" | "blocked" +export type SourceOSInteractionPayloadMode = "metadata-only" | "summary" | "ref-only" | "inline-bounded" | "redacted" + +export interface SourceOSInteractionSurface { + surfaceKind: SourceOSInteractionSurfaceKind + sourcePlane: string + clientRef?: string | null +} + +export interface SourceOSInteractionSession { + sessionId: string + conversationRef?: string | null + roomRef?: string | null + threadRef?: string | null + workroomRef?: string | null + topicRef?: string | null + opsHistoryEventRef?: string | null +} + +export interface SourceOSInteractionActor { + actorRef: string + actorKind: SourceOSInteractionActorKind + agentRegistryRef?: string | null + onBehalfOfRef?: string | null +} + +export interface SourceOSInteractionParticipant { + role: SourceOSInteractionParticipantRole + participantRef: string + agentRegistryRef?: string | null +} + +export interface SourceOSInteractionTask { + taskRef?: string | null + status?: SourceOSInteractionTaskStatus + modelHint?: string | null + modelRouted?: string | null + provider?: string | null + latencyMs?: number | null +} + +export interface SourceOSSteeringIntent { + steeringKind?: SourceOSSteeringKind + featureRef?: string | null + strength?: number | null + status?: SourceOSSteeringStatus +} + +export interface SourceOSGovernanceTrace { + policyAdmitted: boolean + policyRef?: string | null + policyDecisionRefs?: string[] + grantRefs?: string[] + memoryScopeRef?: string | null + memoryWritten: boolean + contextPackRefs?: string[] + requestHash?: string | null + evidenceHash?: string | null + providerRouteEvidenceRef?: string | null + agentPlaneRunRef?: string | null + evidenceRefs?: string[] + replayRef?: string | null +} + +export interface SourceOSInteractionIntegrity { + eventHash?: string | null + signature?: string | null +} + +export interface SourceOSInteractionEvent { + interactionEventId: string + type: "SourceOSInteractionEvent" + specVersion: string + eventClass: SourceOSInteractionEventClass + occurredAt: string + surface: SourceOSInteractionSurface + mode: SourceOSInteractionMode + session: SourceOSInteractionSession + actor: SourceOSInteractionActor + participants?: SourceOSInteractionParticipant[] + task?: SourceOSInteractionTask | null + steeringIntent?: SourceOSSteeringIntent | null + governanceTrace: SourceOSGovernanceTrace + payloadMode: SourceOSInteractionPayloadMode + payload?: Record | null + sourceEventRefs?: string[] + redactionRefs?: string[] + integrity?: SourceOSInteractionIntegrity | null +} + +// Required top-level fields in the canonical schema: interactionEventId, type, specVersion, eventClass, occurredAt, surface, mode, session, actor, payloadMode, governanceTrace From 3d20d389309578045bf9c16c2f3e476e8b431f69 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 30 May 2026 12:50:34 -0400 Subject: [PATCH 3/5] Add generated Python interaction types --- .../python/sourceos_interaction_event.py | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 generated/python/sourceos_interaction_event.py diff --git a/generated/python/sourceos_interaction_event.py b/generated/python/sourceos_interaction_event.py new file mode 100644 index 0000000..64e5585 --- /dev/null +++ b/generated/python/sourceos_interaction_event.py @@ -0,0 +1,106 @@ +# Generated from schemas/SourceOSInteractionEvent.json. +# Do not edit by hand. Run: python tools/generate_sourceos_interaction_types.py + +from __future__ import annotations + +from typing import Any, Literal, NotRequired, TypedDict + + +SOURCEOS_INTERACTION_EVENT_REQUIRED = ['interactionEventId', 'type', 'specVersion', 'eventClass', 'occurredAt', 'surface', 'mode', 'session', 'actor', 'payloadMode', 'governanceTrace'] + +SourceOSInteractionEventClass = Literal['interaction.session_started', 'interaction.message_posted', 'interaction.task_submitted', 'interaction.task_stream_delta', 'interaction.task_completed', 'interaction.task_failed', 'interaction.governance_trace', 'interaction.steering_intent', 'interaction.memory_scope_bound', 'interaction.context_pack_bound', 'interaction.policy_decision', 'interaction.approval_requested', 'interaction.approval_recorded', 'interaction.redacted'] +SourceOSInteractionSurfaceKind = Literal['noetica', 'agent-term', 'matrix', 'prophet-workspace', 'superconscious', 'agentplane', 'api', 'other'] +SourceOSInteractionMode = Literal['standalone', 'sourceos', 'dry-run', 'replay'] +SourceOSInteractionActorKind = Literal['human', 'agent', 'service', 'bot', 'system'] +SourceOSInteractionParticipantRole = Literal['user', 'assistant', 'operator', 'agent', 'provider', 'tool', 'observer'] +SourceOSInteractionTaskStatus = Literal['submitted', 'streaming', 'success', 'failure', 'blocked', 'unavailable', 'not_configured'] +SourceOSSteeringKind = Literal['none', 'neuronpedia_feature', 'local_sae', 'sourceos_local', 'other'] +SourceOSSteeringStatus = Literal['requested', 'applied', 'noop', 'not_configured', 'blocked'] +SourceOSInteractionPayloadMode = Literal['metadata-only', 'summary', 'ref-only', 'inline-bounded', 'redacted'] + + +class SourceOSInteractionSurface(TypedDict): + surfaceKind: SourceOSInteractionSurfaceKind + sourcePlane: str + clientRef: NotRequired[str | None] + + +class SourceOSInteractionSession(TypedDict): + sessionId: str + conversationRef: NotRequired[str | None] + roomRef: NotRequired[str | None] + threadRef: NotRequired[str | None] + workroomRef: NotRequired[str | None] + topicRef: NotRequired[str | None] + opsHistoryEventRef: NotRequired[str | None] + + +class SourceOSInteractionActor(TypedDict): + actorRef: str + actorKind: SourceOSInteractionActorKind + agentRegistryRef: NotRequired[str | None] + onBehalfOfRef: NotRequired[str | None] + + +class SourceOSInteractionParticipant(TypedDict): + role: SourceOSInteractionParticipantRole + participantRef: str + agentRegistryRef: NotRequired[str | None] + + +class SourceOSInteractionTask(TypedDict, total=False): + taskRef: str | None + status: SourceOSInteractionTaskStatus + modelHint: str | None + modelRouted: str | None + provider: str | None + latencyMs: int | None + + +class SourceOSSteeringIntent(TypedDict, total=False): + steeringKind: SourceOSSteeringKind + featureRef: str | None + strength: float | None + status: SourceOSSteeringStatus + + +class SourceOSGovernanceTrace(TypedDict): + policyAdmitted: bool + memoryWritten: bool + policyRef: NotRequired[str | None] + policyDecisionRefs: NotRequired[list[str]] + grantRefs: NotRequired[list[str]] + memoryScopeRef: NotRequired[str | None] + contextPackRefs: NotRequired[list[str]] + requestHash: NotRequired[str | None] + evidenceHash: NotRequired[str | None] + providerRouteEvidenceRef: NotRequired[str | None] + agentPlaneRunRef: NotRequired[str | None] + evidenceRefs: NotRequired[list[str]] + replayRef: NotRequired[str | None] + + +class SourceOSInteractionIntegrity(TypedDict, total=False): + eventHash: str | None + signature: str | None + + +class SourceOSInteractionEvent(TypedDict): + interactionEventId: str + type: Literal["SourceOSInteractionEvent"] + specVersion: str + eventClass: SourceOSInteractionEventClass + occurredAt: str + surface: SourceOSInteractionSurface + mode: SourceOSInteractionMode + session: SourceOSInteractionSession + actor: SourceOSInteractionActor + payloadMode: SourceOSInteractionPayloadMode + governanceTrace: SourceOSGovernanceTrace + participants: NotRequired[list[SourceOSInteractionParticipant]] + task: NotRequired[SourceOSInteractionTask | None] + steeringIntent: NotRequired[SourceOSSteeringIntent | None] + payload: NotRequired[dict[str, Any] | None] + sourceEventRefs: NotRequired[list[str]] + redactionRefs: NotRequired[list[str]] + integrity: NotRequired[SourceOSInteractionIntegrity | None] From a055c5fe269f909764ccaf4815c277db01cf9cbd Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 30 May 2026 13:22:15 -0400 Subject: [PATCH 4/5] Add interaction codegen validation workflow --- .../sourceos-interaction-codegen.yml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/sourceos-interaction-codegen.yml diff --git a/.github/workflows/sourceos-interaction-codegen.yml b/.github/workflows/sourceos-interaction-codegen.yml new file mode 100644 index 0000000..1a10f3f --- /dev/null +++ b/.github/workflows/sourceos-interaction-codegen.yml @@ -0,0 +1,42 @@ +name: SourceOS Interaction Codegen + +on: + pull_request: + branches: ["main"] + paths: + - "schemas/SourceOSInteractionEvent.json" + - "generated/typescript/sourceos-interaction-event.ts" + - "generated/python/sourceos_interaction_event.py" + - "tools/generate_sourceos_interaction_types.py" + - ".github/workflows/sourceos-interaction-codegen.yml" + - "docs/contract-additions/sourceos-interaction-catalog.md" + push: + branches: ["main", "work/interaction-codegen-116"] + paths: + - "schemas/SourceOSInteractionEvent.json" + - "generated/typescript/sourceos-interaction-event.ts" + - "generated/python/sourceos_interaction_event.py" + - "tools/generate_sourceos_interaction_types.py" + - ".github/workflows/sourceos-interaction-codegen.yml" + - "docs/contract-additions/sourceos-interaction-catalog.md" + +permissions: + contents: read + +jobs: + validate-interaction-codegen: + name: Validate generated interaction types + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Check generated files are current + run: python tools/generate_sourceos_interaction_types.py --check + + - name: Compile generated Python type module + run: python -m py_compile generated/python/sourceos_interaction_event.py From 9d632cf0d04fdca47015683a7dbb6e6e437a865b Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 30 May 2026 15:02:42 -0400 Subject: [PATCH 5/5] Document interaction type generation path --- .../sourceos-interaction-catalog.md | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/docs/contract-additions/sourceos-interaction-catalog.md b/docs/contract-additions/sourceos-interaction-catalog.md index 0eae0ef..95ec6f1 100644 --- a/docs/contract-additions/sourceos-interaction-catalog.md +++ b/docs/contract-additions/sourceos-interaction-catalog.md @@ -24,10 +24,41 @@ The key architectural rule is that Noetica and AgentTerm are separate surfaces o | --- | --- | | `schemas/SourceOSInteractionEvent.json` | Machine-readable JSON Schema for the shared interaction envelope. | | `examples/sourceos-interaction-event.json` | Valid Noetica standalone completion example consumable by AgentTerm. | +| `generated/typescript/sourceos-interaction-event.ts` | Generated TypeScript interface/union definitions for downstream TypeScript consumers. | +| `generated/python/sourceos_interaction_event.py` | Generated Python `TypedDict` / `Literal` definitions for downstream Python consumers. | +| `tools/generate_sourceos_interaction_types.py` | Generator and stale-output checker for the generated artifacts. | | `tools/validate_sourceos_interaction_examples.py` | Dedicated validator for the schema/example pair. | -| `.github/workflows/sourceos-interaction-substrate.yml` | CI workflow for the interaction-substrate slice. | +| `.github/workflows/sourceos-interaction-substrate.yml` | CI workflow for the interaction-substrate schema/example slice. | +| `.github/workflows/sourceos-interaction-codegen.yml` | CI workflow that checks generated artifacts are current. | | `docs/contract-additions/sourceos-interaction-substrate.md` | Normative design and authority-boundary contract. | +## Generated type consumption + +The canonical generation command is: + +```bash +python tools/generate_sourceos_interaction_types.py +``` + +The canonical drift check is: + +```bash +python tools/generate_sourceos_interaction_types.py --check +``` + +Downstream repositories may consume the generated artifacts by vendoring from a pinned `sourceos-spec` commit, importing from a subtree/submodule, or running the generator during their own contract-sync process. + +Recommended downstream mapping: + +| Consumer | Generated artifact | +| --- | --- | +| `SocioProphet/Noetica` | `generated/typescript/sourceos-interaction-event.ts` | +| `SourceOS-Linux/agent-term` | `generated/python/sourceos_interaction_event.py` | +| `SocioProphet/superconscious` | Python or TypeScript artifact depending on implementation lane | +| `SocioProphet/agentplane` | Python or TypeScript artifact depending on implementation lane | + +Schema changes must update the generated artifacts in the same PR. CI should fail when the generated files are stale. + ## Required downstream bindings | Repository | Binding obligation | @@ -67,10 +98,12 @@ AgentTerm Matrix or terminal command ## Completion status -Initial implementation status at catalog creation: +Initial implementation status after codegen tranche: - SourceOS spec schema/example/validator/workflow: merged. - AgentTerm fixture ingest/render path: merged. - Noetica emitter path: merged. +- TypeScript and Python generated artifacts: present. +- Drift check workflow: present. -Future work should add generated types or schema-consumption automation when the downstream repositories are ready for a shared package or codegen path. +Future work should migrate Noetica and AgentTerm from local mirrors to the generated artifacts or a pinned contract-sync process.