From 418fbfb483002abc97a36ae0bd74941a2c54668a Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 11:14:37 -0400 Subject: [PATCH 1/9] Add sourceosctl reasoning command group --- sourceosctl/commands/reasoning.py | 181 ++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 sourceosctl/commands/reasoning.py diff --git a/sourceosctl/commands/reasoning.py b/sourceosctl/commands/reasoning.py new file mode 100644 index 0000000..b6cbb1d --- /dev/null +++ b/sourceosctl/commands/reasoning.py @@ -0,0 +1,181 @@ +"""Read-only Superconscious / SourceOS reasoning artifact helpers.""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path +from typing import Any, Dict, List + + +REQUIRED_CANONICAL = [ + "reasoning-events.sourceos.jsonl", + "reasoning-run.sourceos.json", + "reasoning-receipt.json", + "reasoning-replay-plan.json", + "reasoning-benchmark.json", +] +VALID_REPLAY_CLASSES = {"exact", "best-effort", "evidence-only", "non-replayable-side-effect"} + + +def _print_json(payload: Dict[str, Any]) -> int: + print(json.dumps(payload, indent=2, sort_keys=True)) + return 0 + + +def _load_json(path: Path) -> Dict[str, Any]: + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def _load_jsonl(path: Path) -> List[Dict[str, Any]]: + with path.open("r", encoding="utf-8") as handle: + return [json.loads(line) for line in handle if line.strip()] + + +def validate_run_dir(run_dir: Path) -> Dict[str, Any]: + run_dir = run_dir.resolve() + errors: List[str] = [] + + for artifact in REQUIRED_CANONICAL: + if not (run_dir / artifact).exists(): + errors.append(f"missing canonical artifact: {artifact}") + + if errors: + return {"type": "ReasoningValidation", "result": "fail", "runDir": str(run_dir), "errors": errors} + + events = _load_jsonl(run_dir / "reasoning-events.sourceos.jsonl") + reasoning_run = _load_json(run_dir / "reasoning-run.sourceos.json") + receipt = _load_json(run_dir / "reasoning-receipt.json") + replay = _load_json(run_dir / "reasoning-replay-plan.json") + benchmark = _load_json(run_dir / "reasoning-benchmark.json") + + run_id = reasoning_run.get("id") + if reasoning_run.get("type") != "ReasoningRun": + errors.append("reasoning-run.sourceos.json type must be ReasoningRun") + if reasoning_run.get("safeTrace", {}).get("mode") != "operational-trace-only": + errors.append("safe trace mode must be operational-trace-only") + if reasoning_run.get("safeTrace", {}).get("rawPrivateReasoning") != "not-collected": + errors.append("raw private reasoning must be not-collected") + + for index, event in enumerate(events, start=1): + if event.get("type") != "ReasoningEvent": + errors.append(f"event line {index} type must be ReasoningEvent") + if event.get("runRef") != run_id: + errors.append(f"event line {index} runRef mismatch") + if event.get("traceLevel") == "denied": + errors.append(f"event line {index} must not emit denied trace content") + + if receipt.get("type") != "ReasoningReceipt" or receipt.get("runRef") != run_id: + errors.append("reasoning receipt mismatch") + if replay.get("type") != "ReasoningReplayPlan" or replay.get("runRef") != run_id: + errors.append("reasoning replay plan mismatch") + if replay.get("replayClass") not in VALID_REPLAY_CLASSES: + errors.append("invalid replay class") + if benchmark.get("type") != "ReasoningBenchmark" or benchmark.get("runRef") != run_id: + errors.append("reasoning benchmark mismatch") + if benchmark.get("passed") is not True: + errors.append("reasoning benchmark must pass") + + return { + "type": "ReasoningValidation", + "result": "pass" if not errors else "fail", + "runDir": str(run_dir), + "runId": run_id, + "status": reasoning_run.get("status"), + "eventCount": len(events), + "replayClass": replay.get("replayClass"), + "benchmarkSuite": benchmark.get("suite"), + "benchmarkPassed": benchmark.get("passed"), + "safeTraceMode": reasoning_run.get("safeTrace", {}).get("mode"), + "rawPrivateReasoning": reasoning_run.get("safeTrace", {}).get("rawPrivateReasoning"), + "errors": errors, + } + + +def validate_cmd(args) -> int: + report = validate_run_dir(Path(args.run_dir)) + _print_json(report) + return 0 if report["result"] == "pass" else 1 + + +def inspect_cmd(args) -> int: + run_dir = Path(args.run_dir).resolve() + report = validate_run_dir(run_dir) + if report["result"] != "pass" and not args.allow_invalid: + _print_json(report) + return 1 + + reasoning_run = _load_json(run_dir / "reasoning-run.sourceos.json") + replay = _load_json(run_dir / "reasoning-replay-plan.json") + benchmark = _load_json(run_dir / "reasoning-benchmark.json") + events = _load_jsonl(run_dir / "reasoning-events.sourceos.jsonl") + + return _print_json( + { + "type": "ReasoningInspection", + "runId": reasoning_run.get("id"), + "status": reasoning_run.get("status"), + "task": reasoning_run.get("task"), + "agentRef": reasoning_run.get("agentRef"), + "workspaceRef": reasoning_run.get("workspaceRef"), + "safeTrace": reasoning_run.get("safeTrace"), + "replayClass": replay.get("replayClass"), + "benchmark": { + "suite": benchmark.get("suite"), + "passed": benchmark.get("passed"), + "assertions": benchmark.get("assertions", []), + }, + "eventTimeline": [ + { + "id": event.get("id"), + "eventType": event.get("eventType"), + "summary": event.get("summary"), + "traceLevel": event.get("traceLevel"), + "trustLevel": event.get("trustLevel"), + } + for event in events + ], + } + ) + + +def replay_plan_cmd(args) -> int: + run_dir = Path(args.run_dir).resolve() + return _print_json(_load_json(run_dir / "reasoning-replay-plan.json")) + + +def events_cmd(args) -> int: + run_dir = Path(args.run_dir).resolve() + events = _load_jsonl(run_dir / "reasoning-events.sourceos.jsonl") + return _print_json({"type": "ReasoningEvents", "runDir": str(run_dir), "events": events}) + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(prog="sourceosctl reasoning", description="Inspect and validate SourceOS reasoning artifacts") + sub = parser.add_subparsers(dest="reasoning_command", required=True) + + validate_p = sub.add_parser("validate", help="Validate a Superconscious/SourceOS reasoning run directory") + validate_p.add_argument("run_dir") + validate_p.set_defaults(func=validate_cmd) + + inspect_p = sub.add_parser("inspect", help="Inspect a reasoning run directory") + inspect_p.add_argument("run_dir") + inspect_p.add_argument("--allow-invalid", action="store_true", default=False) + inspect_p.set_defaults(func=inspect_cmd) + + replay_p = sub.add_parser("replay-plan", help="Print the reasoning replay plan") + replay_p.add_argument("run_dir") + replay_p.set_defaults(func=replay_plan_cmd) + + events_p = sub.add_parser("events", help="Print reasoning events") + events_p.add_argument("run_dir") + events_p.set_defaults(func=events_cmd) + return parser + + +def reasoning_main(argv: list[str] | None = None) -> int: + parser = build_parser() + args = parser.parse_args(argv) + return args.func(args) or 0 From 7087943e169d99e6801898400aec3da547127299 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 11:17:04 -0400 Subject: [PATCH 2/9] Route sourceosctl reasoning command group --- bin/sourceosctl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/sourceosctl b/bin/sourceosctl index db27135..02e8402 100755 --- a/bin/sourceosctl +++ b/bin/sourceosctl @@ -39,6 +39,11 @@ if len(sys.argv) > 1 and sys.argv[1] == "policy": sys.exit(policy_main(sys.argv[2:])) +if len(sys.argv) > 1 and sys.argv[1] == "reasoning": + from sourceosctl.commands.reasoning import reasoning_main + + sys.exit(reasoning_main(sys.argv[2:])) + if len(sys.argv) > 1 and sys.argv[1] == "network": from sourceosctl.commands.network import network_main From fc0479f47467eefda05c1dedf248bc0522401537 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 11:25:29 -0400 Subject: [PATCH 3/9] Add sourceosctl reasoning event fixture --- .../reasoning/deterministic/reasoning-events.sourceos.jsonl | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/fixtures/reasoning/deterministic/reasoning-events.sourceos.jsonl diff --git a/tests/fixtures/reasoning/deterministic/reasoning-events.sourceos.jsonl b/tests/fixtures/reasoning/deterministic/reasoning-events.sourceos.jsonl new file mode 100644 index 0000000..844bd07 --- /dev/null +++ b/tests/fixtures/reasoning/deterministic/reasoning-events.sourceos.jsonl @@ -0,0 +1,2 @@ +{"capturedAt":"2026-05-05T00:00:00Z","eventType":"reasoning.run.created","id":"urn:srcos:reasoning-event:sourceosctl-fixture-created","runRef":"urn:srcos:reasoning-run:sourceosctl-fixture","summary":"Created deterministic Superconscious reasoning run.","traceLevel":"public-safe","trustLevel":"trusted-control-input","type":"ReasoningEvent","specVersion":"2.0.0"} +{"capturedAt":"2026-05-05T00:00:01Z","eventType":"reasoning.run.completed","id":"urn:srcos:reasoning-event:sourceosctl-fixture-completed","runRef":"urn:srcos:reasoning-run:sourceosctl-fixture","summary":"Completed deterministic Superconscious reasoning run.","traceLevel":"public-safe","trustLevel":"trusted-control-input","type":"ReasoningEvent","specVersion":"2.0.0"} From f5f768942aa8e69f8de3a27b4735f89509bca538 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 11:32:33 -0400 Subject: [PATCH 4/9] Add sourceosctl reasoning run fixture --- .../deterministic/reasoning-run.sourceos.json | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/fixtures/reasoning/deterministic/reasoning-run.sourceos.json diff --git a/tests/fixtures/reasoning/deterministic/reasoning-run.sourceos.json b/tests/fixtures/reasoning/deterministic/reasoning-run.sourceos.json new file mode 100644 index 0000000..c7a3a9b --- /dev/null +++ b/tests/fixtures/reasoning/deterministic/reasoning-run.sourceos.json @@ -0,0 +1,32 @@ +{ + "id": "urn:srcos:reasoning-run:sourceosctl-fixture", + "type": "ReasoningRun", + "specVersion": "2.0.0", + "status": "completed", + "task": { + "id": "urn:srcos:reasoning-task:sourceosctl-fixture", + "title": "sourceosctl reasoning fixture", + "objectiveHash": "sha256:sourceosctl-fixture-objective" + }, + "agentRef": "urn:socioprophet:agent:superconscious-demo", + "workspaceRef": "urn:socioprophet:workspace:superconscious-m1", + "safeTrace": { + "mode": "operational-trace-only", + "rawPrivateReasoning": "not-collected", + "eventCount": 2 + }, + "eventRefs": [ + "urn:srcos:reasoning-event:sourceosctl-fixture-created", + "urn:srcos:reasoning-event:sourceosctl-fixture-completed" + ], + "artifactRefs": [ + "reasoning-events.sourceos.jsonl", + "reasoning-run.sourceos.json", + "reasoning-receipt.json", + "reasoning-replay-plan.json", + "reasoning-benchmark.json" + ], + "adapterRecords": [], + "startedAt": "2026-05-05T00:00:00Z", + "completedAt": "2026-05-05T00:00:01Z" +} From 65f6ced70c02bd851b24266bbae7a5f0038a1650 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 11:39:15 -0400 Subject: [PATCH 5/9] Add sourceosctl reasoning receipt fixture --- .../deterministic/reasoning-receipt.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/fixtures/reasoning/deterministic/reasoning-receipt.json diff --git a/tests/fixtures/reasoning/deterministic/reasoning-receipt.json b/tests/fixtures/reasoning/deterministic/reasoning-receipt.json new file mode 100644 index 0000000..db1fafd --- /dev/null +++ b/tests/fixtures/reasoning/deterministic/reasoning-receipt.json @@ -0,0 +1,17 @@ +{ + "id": "urn:srcos:receipt:reasoning:sourceosctl-fixture", + "type": "ReasoningReceipt", + "specVersion": "2.0.0", + "runRef": "urn:srcos:reasoning-run:sourceosctl-fixture", + "taskRef": "urn:srcos:reasoning-task:sourceosctl-fixture", + "status": "completed", + "traceHash": "sha256:sourceosctl-fixture-trace", + "coordination": { + "policy": "allowed-safe-deterministic-mode", + "modelRoute": "deterministic-stub-route", + "memory": "proposal-only", + "approval": "not-required" + }, + "replayClass": "exact", + "capturedAt": "2026-05-05T00:00:01Z" +} From 6baf3bdf09bf37bcbacfaa090990594e52015ec2 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 11:48:25 -0400 Subject: [PATCH 6/9] Add sourceosctl reasoning replay fixture --- .../deterministic/reasoning-replay-plan.json | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/fixtures/reasoning/deterministic/reasoning-replay-plan.json diff --git a/tests/fixtures/reasoning/deterministic/reasoning-replay-plan.json b/tests/fixtures/reasoning/deterministic/reasoning-replay-plan.json new file mode 100644 index 0000000..d4e7dd9 --- /dev/null +++ b/tests/fixtures/reasoning/deterministic/reasoning-replay-plan.json @@ -0,0 +1,22 @@ +{ + "id": "urn:srcos:reasoning-replay-plan:sourceosctl-fixture", + "type": "ReasoningReplayPlan", + "specVersion": "2.0.0", + "runRef": "urn:srcos:reasoning-run:sourceosctl-fixture", + "replayClass": "exact", + "inputs": { + "taskRef": "urn:srcos:reasoning-task:sourceosctl-fixture", + "taskHash": "sha256:sourceosctl-fixture-task", + "mode": "deterministic-local" + }, + "constraints": { + "network": "denied", + "modelCalls": "denied", + "hostState": "unchanged" + }, + "stepRefs": [ + "urn:srcos:reasoning-event:sourceosctl-fixture-created", + "urn:srcos:reasoning-event:sourceosctl-fixture-completed" + ], + "capturedAt": "2026-05-05T00:00:01Z" +} From 1b52e3b53ba04dfc1f76a7c60fc48631bdf6a45c Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 13:37:36 -0400 Subject: [PATCH 7/9] Add sourceosctl reasoning benchmark fixture --- .../deterministic/reasoning-benchmark.json | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/fixtures/reasoning/deterministic/reasoning-benchmark.json diff --git a/tests/fixtures/reasoning/deterministic/reasoning-benchmark.json b/tests/fixtures/reasoning/deterministic/reasoning-benchmark.json new file mode 100644 index 0000000..878026b --- /dev/null +++ b/tests/fixtures/reasoning/deterministic/reasoning-benchmark.json @@ -0,0 +1,21 @@ +{ + "id": "urn:srcos:reasoning-benchmark:sourceosctl-fixture", + "type": "ReasoningBenchmark", + "specVersion": "2.0.0", + "runRef": "urn:srcos:reasoning-run:sourceosctl-fixture", + "suite": "m1-deterministic-smoke", + "passed": true, + "assertions": [ + { + "name": "run-completed", + "passed": true, + "summary": "The reasoning run reached completed status." + }, + { + "name": "safe-trace-only", + "passed": true, + "summary": "The reasoning run emitted safe operational trace metadata only." + } + ], + "capturedAt": "2026-05-05T00:00:01Z" +} From 08113246de77965e3fb93473b1afe4fed969178e Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 13:48:48 -0400 Subject: [PATCH 8/9] Add tests for sourceosctl reasoning commands --- tests/test_reasoning_cli.py | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tests/test_reasoning_cli.py diff --git a/tests/test_reasoning_cli.py b/tests/test_reasoning_cli.py new file mode 100644 index 0000000..ac21949 --- /dev/null +++ b/tests/test_reasoning_cli.py @@ -0,0 +1,70 @@ +"""Unit tests for sourceosctl reasoning commands.""" + +import json +import os +import pathlib +import shutil +import sys +import tempfile +import unittest + +_REPO_ROOT = pathlib.Path(__file__).parent.parent +sys.path.insert(0, str(_REPO_ROOT)) + +from sourceosctl.commands import reasoning + + +FIXTURE = _REPO_ROOT / "tests" / "fixtures" / "reasoning" / "deterministic" + + +class TestReasoningCommands(unittest.TestCase): + def test_reasoning_validate_passes_for_fixture(self): + self.assertEqual(reasoning.reasoning_main(["validate", str(FIXTURE)]), 0) + + def test_reasoning_inspect_passes_for_fixture(self): + self.assertEqual(reasoning.reasoning_main(["inspect", str(FIXTURE)]), 0) + + def test_reasoning_replay_plan_passes_for_fixture(self): + self.assertEqual(reasoning.reasoning_main(["replay-plan", str(FIXTURE)]), 0) + + def test_reasoning_events_passes_for_fixture(self): + self.assertEqual(reasoning.reasoning_main(["events", str(FIXTURE)]), 0) + + def test_validate_run_dir_returns_structured_pass(self): + report = reasoning.validate_run_dir(FIXTURE) + self.assertEqual(report["result"], "pass") + self.assertEqual(report["runId"], "urn:srcos:reasoning-run:sourceosctl-fixture") + self.assertEqual(report["replayClass"], "exact") + self.assertTrue(report["benchmarkPassed"]) + self.assertEqual(report["rawPrivateReasoning"], "not-collected") + + def test_reasoning_validate_fails_closed_when_benchmark_missing(self): + with tempfile.TemporaryDirectory() as tmp: + tmp_path = pathlib.Path(tmp) + for source in FIXTURE.iterdir(): + shutil.copy(source, tmp_path / source.name) + os.unlink(tmp_path / "reasoning-benchmark.json") + + report = reasoning.validate_run_dir(tmp_path) + + self.assertEqual(report["result"], "fail") + self.assertIn("missing canonical artifact: reasoning-benchmark.json", report["errors"]) + + def test_reasoning_validate_fails_on_raw_private_reasoning(self): + with tempfile.TemporaryDirectory() as tmp: + tmp_path = pathlib.Path(tmp) + for source in FIXTURE.iterdir(): + shutil.copy(source, tmp_path / source.name) + run_path = tmp_path / "reasoning-run.sourceos.json" + payload = json.loads(run_path.read_text(encoding="utf-8")) + payload["safeTrace"]["rawPrivateReasoning"] = "present" + run_path.write_text(json.dumps(payload), encoding="utf-8") + + report = reasoning.validate_run_dir(tmp_path) + + self.assertEqual(report["result"], "fail") + self.assertIn("raw private reasoning must be not-collected", report["errors"]) + + +if __name__ == "__main__": + unittest.main() From 1b585312770208b6247c44b968ea57c54d07b122 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 14:00:36 -0400 Subject: [PATCH 9/9] Wire sourceosctl reasoning validation into Makefile --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 97d4161..e8b4f1d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test scan-local-persistence validate-local-agents validate-local-agent-templates +.PHONY: validate test scan-local-persistence validate-local-agents validate-local-agent-templates validate-reasoning-cli -validate: test scan-local-persistence validate-local-agents validate-local-agent-templates +validate: test scan-local-persistence validate-local-agents validate-local-agent-templates validate-reasoning-cli @test -f README.md @test -f AGENTS.md @test -f .github/copilot-instructions.md @@ -20,3 +20,9 @@ validate-local-agents: validate-local-agent-templates: @python3 scripts/validate_local_agent_templates.py . + +validate-reasoning-cli: + @python3 bin/sourceosctl reasoning validate tests/fixtures/reasoning/deterministic >/dev/null + @python3 bin/sourceosctl reasoning inspect tests/fixtures/reasoning/deterministic >/dev/null + @python3 bin/sourceosctl reasoning replay-plan tests/fixtures/reasoning/deterministic >/dev/null + @python3 bin/sourceosctl reasoning events tests/fixtures/reasoning/deterministic >/dev/null