From e8d8e74aabd63a03d92b0b9e31a05df78bbdb2d8 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 20:43:15 -0400 Subject: [PATCH 1/9] feat(civic-stack): emit OQL/OAC runtime evidence capsule for Seven-Model civic architecture (#154) - CivicStackRunCapsule schema: run_id, actor_ref, oql_plan_id, artifact_manifest_id, policy_decision_id, tool_grants, action_dispatch_records, oql_plan_acceptance, oac_compiler_invocation, subagent_delegations, attestation_events, rationalgrl_trace, hellgraph_evidence_refs, delivery_excellence_signal_ref, provenance_refs, timestamps - RationalGRL trace: goals_addressed (goal/softgoal), tasks_executed, dependencies_blocked with defeater_reason on blocked tasks and denied goals - OQL plan acceptance with OQL-to-agent-task mappings - OAC compiler invocation with artifact emission refs - Policy gates: deny outcome enforces empty tool_grants + all dispatches blocked; blocked dispatches require defeater_reason; oac failure forbids artifact_emission_refs - 2 valid fixtures (allow + deny/policy-blocked) + 3 reject fixtures - validate-civic-stack-runtime-evidence wired into Makefile aggregate validate target - Upstream anchors: ontogenesis#80, #81, policy-fabric#72, sociosphere#323, delivery-excellence#28 --- Makefile | 8 +- .../civic-stack-run-capsule.schema.v0.1.json | 270 ++++++++++++++++++ ...ck-run-capsule.missing-hellgraph-refs.json | 20 ++ ...k-run-capsule.missing-provenance-refs.json | 21 ++ ...ct.civic-stack-run-capsule.wrong-kind.json | 21 ++ .../valid.civic-stack-run-capsule.json | 160 +++++++++++ ...ivic-stack-run-capsule.policy-blocked.json | 69 +++++ .../validate_civic_stack_runtime_evidence.py | 123 ++++++++ 8 files changed, 690 insertions(+), 2 deletions(-) create mode 100644 schemas/civic-stack-run-capsule.schema.v0.1.json create mode 100644 tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-hellgraph-refs.json create mode 100644 tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-provenance-refs.json create mode 100644 tests/fixtures/civic-stack/reject.civic-stack-run-capsule.wrong-kind.json create mode 100644 tests/fixtures/civic-stack/valid.civic-stack-run-capsule.json create mode 100644 tests/fixtures/civic-stack/valid.civic-stack-run-capsule.policy-blocked.json create mode 100644 tools/validate_civic_stack_runtime_evidence.py diff --git a/Makefile b/Makefile index 8856a65..bcd6b2f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence python3 tools/validate_execution_timing.py validate-governance-context: @@ -248,6 +248,10 @@ validate-prophet-mesh-agentplane-adapter: python3 -m json.tool contracts/prophet-mesh/prophet-mesh-agentplane-adapter.v0.1.json >/dev/null python3 tools/validate_prophet_mesh_agentplane_adapter.py +validate-civic-stack-runtime-evidence: + python3 -m json.tool schemas/civic-stack-run-capsule.schema.v0.1.json >/dev/null + python3 tools/validate_civic_stack_runtime_evidence.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/civic-stack-run-capsule.schema.v0.1.json b/schemas/civic-stack-run-capsule.schema.v0.1.json new file mode 100644 index 0000000..00dffbc --- /dev/null +++ b/schemas/civic-stack-run-capsule.schema.v0.1.json @@ -0,0 +1,270 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/civic-stack-run-capsule/v0.1", + "title": "CivicStackRunCapsule", + "description": "AgentPlane runtime evidence capsule for Seven-Model Civic Operating Architecture execution. Emits OQL plan acceptance, OAC compiler invocation, tool grants, action dispatch, and RationalGRL trace links. AgentPlane emits governed runtime evidence; it does not own the ontology, policy evaluation, or Delivery Excellence scoring.", + "type": "object", + "required": [ + "kind", + "run_id", + "actor_ref", + "oql_plan_id", + "artifact_manifest_id", + "policy_decision_id", + "timestamps", + "provenance_refs", + "rationalgrl_trace", + "hellgraph_evidence_refs", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "CivicStackRunCapsule" }, + "run_id": { "type": "string", "minLength": 1 }, + "actor_ref": { "type": "string", "description": "Agent or human actor reference" }, + "post_authority_ref": { + "type": "string", + "description": "Post or authority binding reference, if applicable" + }, + "oql_plan_id": { "type": "string", "minLength": 1 }, + "artifact_manifest_id": { "type": "string", "minLength": 1 }, + "service_id": { "type": "string" }, + "policy_decision_id": { "type": "string", "minLength": 1 }, + "policy_decision_outcome": { + "type": "string", + "enum": ["allow", "allow_with_constraints", "deny", "escalate"] + }, + "dataset_ids": { + "type": "array", + "items": { "type": "string" } + }, + "resource_ids": { + "type": "array", + "items": { "type": "string" } + }, + "tool_grants": { + "type": "array", + "items": { "$ref": "#/$defs/ToolGrant" } + }, + "action_dispatch_records": { + "type": "array", + "items": { "$ref": "#/$defs/ActionDispatchRecord" } + }, + "oql_plan_acceptance": { "$ref": "#/$defs/OQLPlanAcceptance" }, + "oac_compiler_invocation": { "$ref": "#/$defs/OACCompilerInvocation" }, + "subagent_delegations": { + "type": "array", + "items": { "$ref": "#/$defs/SubagentDelegation" } + }, + "attestation_events": { + "type": "array", + "items": { "$ref": "#/$defs/AttestationEvent" } + }, + "timestamps": { + "type": "object", + "required": ["started_at", "completed_at"], + "additionalProperties": false, + "properties": { + "started_at": { "type": "string", "format": "date-time" }, + "completed_at": { "type": "string", "format": "date-time" } + } + }, + "provenance_refs": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "rationalgrl_trace": { "$ref": "#/$defs/RationalGRLTrace" }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "description": "Evidence refs emitted to HellGraph/Prophet Core" + }, + "delivery_excellence_signal_ref": { + "type": "string", + "description": "Score signal ref emitted to Delivery Excellence" + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "$defs": { + "ToolGrant": { + "type": "object", + "required": ["grant_id", "tool_id", "granted_to", "policy_decision_ref"], + "additionalProperties": false, + "properties": { + "grant_id": { "type": "string", "minLength": 1 }, + "tool_id": { "type": "string", "minLength": 1 }, + "granted_to": { "type": "string", "minLength": 1 }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "cgrm_decision_ref": { "type": "string" }, + "scope_constraints": { + "type": "array", + "items": { "type": "string" } + } + } + }, + "ActionDispatchRecord": { + "type": "object", + "required": ["dispatch_id", "action_type", "policy_decision_ref", "dispatch_status"], + "additionalProperties": false, + "properties": { + "dispatch_id": { "type": "string", "minLength": 1 }, + "action_type": { "type": "string", "minLength": 1 }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "dispatch_status": { + "type": "string", + "enum": ["dispatched", "blocked", "deferred", "completed"] + }, + "rationalgrl_task_ref": { "type": "string" }, + "defeater_reason": { + "type": "string", + "description": "RationalGRL defeater description when dispatch_status=blocked" + } + } + }, + "OQLPlanAcceptance": { + "type": "object", + "required": ["acceptance_id", "oql_plan_id", "acceptance_status"], + "additionalProperties": false, + "properties": { + "acceptance_id": { "type": "string", "minLength": 1 }, + "oql_plan_id": { "type": "string", "minLength": 1 }, + "acceptance_status": { + "type": "string", + "enum": ["accepted", "rejected", "partial", "pending_review"] + }, + "interpretation_ref": { "type": "string" }, + "oql_task_mappings": { + "type": "array", + "items": { "$ref": "#/$defs/OQLTaskMapping" } + } + } + }, + "OQLTaskMapping": { + "type": "object", + "required": ["task_id", "oql_task_ref", "agent_action_ref"], + "additionalProperties": false, + "properties": { + "task_id": { "type": "string" }, + "oql_task_ref": { "type": "string" }, + "agent_action_ref": { "type": "string" } + } + }, + "OACCompilerInvocation": { + "type": "object", + "required": ["invocation_id", "compiler_id", "artifact_manifest_id", "invocation_status"], + "additionalProperties": false, + "properties": { + "invocation_id": { "type": "string", "minLength": 1 }, + "compiler_id": { "type": "string", "minLength": 1 }, + "artifact_manifest_id": { "type": "string", "minLength": 1 }, + "invocation_status": { + "type": "string", + "enum": ["success", "failure", "partial"] + }, + "artifact_emission_refs": { + "type": "array", + "items": { "type": "string" } + } + } + }, + "SubagentDelegation": { + "type": "object", + "required": ["delegation_id", "delegated_to", "task_ref", "policy_decision_ref"], + "additionalProperties": false, + "properties": { + "delegation_id": { "type": "string", "minLength": 1 }, + "delegated_to": { "type": "string", "minLength": 1 }, + "task_ref": { "type": "string", "minLength": 1 }, + "policy_decision_ref": { "type": "string", "minLength": 1 } + } + }, + "AttestationEvent": { + "type": "object", + "required": ["attestation_id", "attestation_type", "attested_by"], + "additionalProperties": false, + "properties": { + "attestation_id": { "type": "string", "minLength": 1 }, + "attestation_type": { + "type": "string", + "enum": ["policy_compliance", "provenance_chain", "dataset_access", "tool_grant", "oql_plan_acceptance"] + }, + "attested_by": { "type": "string", "minLength": 1 }, + "ref": { "type": "string" } + } + }, + "RationalGRLTrace": { + "type": "object", + "required": ["trace_id", "goals_addressed", "tasks_executed"], + "additionalProperties": false, + "properties": { + "trace_id": { "type": "string", "minLength": 1 }, + "goals_addressed": { + "type": "array", + "items": { + "type": "object", + "required": ["goal_ref", "goal_type", "satisfaction_status"], + "additionalProperties": false, + "properties": { + "goal_ref": { "type": "string" }, + "goal_type": { + "type": "string", + "enum": ["goal", "softgoal"] + }, + "satisfaction_status": { + "type": "string", + "enum": ["satisfied", "partially_satisfied", "denied", "unknown"] + }, + "contribution_refs": { + "type": "array", + "items": { "type": "string" } + } + } + } + }, + "tasks_executed": { + "type": "array", + "items": { + "type": "object", + "required": ["task_ref", "execution_status"], + "additionalProperties": false, + "properties": { + "task_ref": { "type": "string" }, + "execution_status": { + "type": "string", + "enum": ["completed", "blocked", "delegated", "deferred"] + }, + "resource_used_refs": { + "type": "array", + "items": { "type": "string" } + }, + "dependency_satisfied_refs": { + "type": "array", + "items": { "type": "string" } + }, + "defeater_reason": { "type": "string" } + } + } + }, + "dependencies_blocked": { + "type": "array", + "items": { + "type": "object", + "required": ["dependency_ref", "blocking_policy_ref"], + "additionalProperties": false, + "properties": { + "dependency_ref": { "type": "string" }, + "blocking_policy_ref": { "type": "string" }, + "defeater_reason": { "type": "string" } + } + } + } + } + } + } +} diff --git a/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-hellgraph-refs.json b/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-hellgraph-refs.json new file mode 100644 index 0000000..ca7893c --- /dev/null +++ b/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-hellgraph-refs.json @@ -0,0 +1,20 @@ +{ + "_reject_reason": "hellgraph_evidence_refs is required but absent", + "kind": "CivicStackRunCapsule", + "run_id": "civic-stack-run:reject-no-hellgraph", + "actor_ref": "agent://agentplane/civic-stack-agent/v1", + "oql_plan_id": "oql://plan/service-delivery-v1/step-1", + "artifact_manifest_id": "manifest://civic-stack/artifacts/reject-no-hellgraph", + "policy_decision_id": "policy-fabric://decision/pd-reject-no-hellgraph", + "timestamps": { + "started_at": "2024-01-15T10:00:00Z", + "completed_at": "2024-01-15T10:01:00Z" + }, + "provenance_refs": ["provenance://sociosphere/civic-stack-run/reject-no-hellgraph"], + "rationalgrl_trace": { + "trace_id": "rationalgrl-trace:reject-no-hellgraph", + "goals_addressed": [], + "tasks_executed": [] + }, + "issued_at": "2024-01-15T10:01:01Z" +} diff --git a/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-provenance-refs.json b/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-provenance-refs.json new file mode 100644 index 0000000..3808fbb --- /dev/null +++ b/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.missing-provenance-refs.json @@ -0,0 +1,21 @@ +{ + "_reject_reason": "provenance_refs is required (minItems: 1) but empty", + "kind": "CivicStackRunCapsule", + "run_id": "civic-stack-run:reject-empty-provenance", + "actor_ref": "agent://agentplane/civic-stack-agent/v1", + "oql_plan_id": "oql://plan/service-delivery-v1/step-1", + "artifact_manifest_id": "manifest://civic-stack/artifacts/reject-empty-provenance", + "policy_decision_id": "policy-fabric://decision/pd-reject-empty-provenance", + "timestamps": { + "started_at": "2024-01-15T10:00:00Z", + "completed_at": "2024-01-15T10:01:00Z" + }, + "provenance_refs": [], + "rationalgrl_trace": { + "trace_id": "rationalgrl-trace:reject-empty-provenance", + "goals_addressed": [], + "tasks_executed": [] + }, + "hellgraph_evidence_refs": ["evidence://hellgraph/reject-empty-provenance/run-capsule"], + "issued_at": "2024-01-15T10:01:01Z" +} diff --git a/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.wrong-kind.json b/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.wrong-kind.json new file mode 100644 index 0000000..f4a267d --- /dev/null +++ b/tests/fixtures/civic-stack/reject.civic-stack-run-capsule.wrong-kind.json @@ -0,0 +1,21 @@ +{ + "_reject_reason": "kind must be CivicStackRunCapsule (const violation)", + "kind": "CivicStackRunCapsuleV2", + "run_id": "civic-stack-run:reject-wrong-kind", + "actor_ref": "agent://agentplane/civic-stack-agent/v1", + "oql_plan_id": "oql://plan/service-delivery-v1/step-1", + "artifact_manifest_id": "manifest://civic-stack/artifacts/reject-wrong-kind", + "policy_decision_id": "policy-fabric://decision/pd-reject-wrong-kind", + "timestamps": { + "started_at": "2024-01-15T10:00:00Z", + "completed_at": "2024-01-15T10:01:00Z" + }, + "provenance_refs": ["provenance://sociosphere/civic-stack-run/reject-wrong-kind"], + "rationalgrl_trace": { + "trace_id": "rationalgrl-trace:reject-wrong-kind", + "goals_addressed": [], + "tasks_executed": [] + }, + "hellgraph_evidence_refs": ["evidence://hellgraph/reject-wrong-kind/run-capsule"], + "issued_at": "2024-01-15T10:01:01Z" +} diff --git a/tests/fixtures/civic-stack/valid.civic-stack-run-capsule.json b/tests/fixtures/civic-stack/valid.civic-stack-run-capsule.json new file mode 100644 index 0000000..f87d52d --- /dev/null +++ b/tests/fixtures/civic-stack/valid.civic-stack-run-capsule.json @@ -0,0 +1,160 @@ +{ + "kind": "CivicStackRunCapsule", + "run_id": "civic-stack-run:a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "actor_ref": "agent://agentplane/civic-stack-agent/v1", + "post_authority_ref": "post://authority/civic-oversight-post/v1", + "oql_plan_id": "oql://plan/service-delivery-v1/step-3", + "artifact_manifest_id": "manifest://civic-stack/artifacts/2024-01-15-run-a1b2", + "service_id": "civic-service:social-case-management", + "policy_decision_id": "policy-fabric://decision/pd-civic-run-a1b2", + "policy_decision_outcome": "allow", + "dataset_ids": [ + "dataset://case-management/beneficiary-records/batch-001", + "dataset://case-management/service-catalog/v4" + ], + "resource_ids": [ + "resource://compute/civic-agent-executor/slot-7", + "resource://storage/case-output/run-a1b2" + ], + "tool_grants": [ + { + "grant_id": "grant:civic-run-a1b2-tool-1", + "tool_id": "tool://case-lookup/v2", + "granted_to": "agent://agentplane/civic-stack-agent/v1", + "policy_decision_ref": "policy-fabric://decision/pd-civic-run-a1b2", + "cgrm_decision_ref": "cgrm://decision/cgrm-civic-run-a1b2-read", + "scope_constraints": ["read_only", "beneficiary_scope_limited"] + }, + { + "grant_id": "grant:civic-run-a1b2-tool-2", + "tool_id": "tool://service-eligibility-check/v3", + "granted_to": "agent://agentplane/civic-stack-agent/v1", + "policy_decision_ref": "policy-fabric://decision/pd-civic-run-a1b2", + "cgrm_decision_ref": "cgrm://decision/cgrm-civic-run-a1b2-eligibility" + } + ], + "action_dispatch_records": [ + { + "dispatch_id": "dispatch:civic-run-a1b2-action-1", + "action_type": "case.lookup", + "policy_decision_ref": "policy-fabric://decision/pd-civic-run-a1b2", + "dispatch_status": "completed", + "rationalgrl_task_ref": "task://rationalgrl/case-lookup-task/v1" + }, + { + "dispatch_id": "dispatch:civic-run-a1b2-action-2", + "action_type": "eligibility.check", + "policy_decision_ref": "policy-fabric://decision/pd-civic-run-a1b2", + "dispatch_status": "completed", + "rationalgrl_task_ref": "task://rationalgrl/eligibility-check-task/v1" + } + ], + "oql_plan_acceptance": { + "acceptance_id": "oql-acceptance:civic-run-a1b2", + "oql_plan_id": "oql://plan/service-delivery-v1/step-3", + "acceptance_status": "accepted", + "interpretation_ref": "oql://interpretation/service-delivery-v1/step-3-interp", + "oql_task_mappings": [ + { + "task_id": "oql-task-map:1", + "oql_task_ref": "oql://task/case-lookup", + "agent_action_ref": "dispatch:civic-run-a1b2-action-1" + }, + { + "task_id": "oql-task-map:2", + "oql_task_ref": "oql://task/eligibility-check", + "agent_action_ref": "dispatch:civic-run-a1b2-action-2" + } + ] + }, + "oac_compiler_invocation": { + "invocation_id": "oac-invocation:civic-run-a1b2", + "compiler_id": "oac://compiler/civic-stack/v1", + "artifact_manifest_id": "manifest://civic-stack/artifacts/2024-01-15-run-a1b2", + "invocation_status": "success", + "artifact_emission_refs": [ + "artifact://case-eligibility-result/run-a1b2/output-001", + "artifact://service-delivery-report/run-a1b2/output-002" + ] + }, + "subagent_delegations": [ + { + "delegation_id": "delegation:civic-run-a1b2-sub-1", + "delegated_to": "agent://agentplane/case-lookup-subagent/v1", + "task_ref": "task://rationalgrl/case-lookup-task/v1", + "policy_decision_ref": "policy-fabric://decision/pd-civic-run-a1b2-sub" + } + ], + "attestation_events": [ + { + "attestation_id": "attestation:civic-run-a1b2-policy", + "attestation_type": "policy_compliance", + "attested_by": "agent://agentplane/civic-stack-agent/v1", + "ref": "policy-fabric://decision/pd-civic-run-a1b2" + }, + { + "attestation_id": "attestation:civic-run-a1b2-oql", + "attestation_type": "oql_plan_acceptance", + "attested_by": "agent://agentplane/civic-stack-agent/v1", + "ref": "oql-acceptance:civic-run-a1b2" + } + ], + "timestamps": { + "started_at": "2024-01-15T10:00:00Z", + "completed_at": "2024-01-15T10:04:33Z" + }, + "provenance_refs": [ + "provenance://sociosphere/civic-stack-run/a1b2c3d4", + "provenance://ontogenesis/civic-run-lineage/a1b2" + ], + "rationalgrl_trace": { + "trace_id": "rationalgrl-trace:civic-run-a1b2", + "goals_addressed": [ + { + "goal_ref": "goal://rationalgrl/civic-service-delivery/primary", + "goal_type": "goal", + "satisfaction_status": "satisfied", + "contribution_refs": [ + "dispatch:civic-run-a1b2-action-1", + "dispatch:civic-run-a1b2-action-2" + ] + }, + { + "goal_ref": "goal://rationalgrl/civic-service-delivery/quality", + "goal_type": "softgoal", + "satisfaction_status": "partially_satisfied", + "contribution_refs": [ + "dispatch:civic-run-a1b2-action-1" + ] + } + ], + "tasks_executed": [ + { + "task_ref": "task://rationalgrl/case-lookup-task/v1", + "execution_status": "completed", + "resource_used_refs": ["resource://compute/civic-agent-executor/slot-7"], + "dependency_satisfied_refs": [] + }, + { + "task_ref": "task://rationalgrl/eligibility-check-task/v1", + "execution_status": "completed", + "resource_used_refs": ["resource://compute/civic-agent-executor/slot-7"], + "dependency_satisfied_refs": ["task://rationalgrl/case-lookup-task/v1"] + } + ], + "dependencies_blocked": [] + }, + "hellgraph_evidence_refs": [ + "evidence://hellgraph/civic-stack-run-a1b2/run-capsule", + "evidence://prophet-core/civic-stack-run-a1b2/emission" + ], + "delivery_excellence_signal_ref": "de://signal/civic-stack-run-a1b2/score", + "upstream_anchors": [ + "ontogenesis#80", + "ontogenesis#81", + "policy-fabric#72", + "sociosphere#323", + "delivery-excellence#28" + ], + "issued_at": "2024-01-15T10:04:35Z" +} diff --git a/tests/fixtures/civic-stack/valid.civic-stack-run-capsule.policy-blocked.json b/tests/fixtures/civic-stack/valid.civic-stack-run-capsule.policy-blocked.json new file mode 100644 index 0000000..727ec9b --- /dev/null +++ b/tests/fixtures/civic-stack/valid.civic-stack-run-capsule.policy-blocked.json @@ -0,0 +1,69 @@ +{ + "kind": "CivicStackRunCapsule", + "run_id": "civic-stack-run:blocked-b2c3d4e5-f6a7-8901-bcde-f12345678901", + "actor_ref": "agent://agentplane/civic-stack-agent/v1", + "oql_plan_id": "oql://plan/restricted-data-access-v1/step-1", + "artifact_manifest_id": "manifest://civic-stack/artifacts/2024-01-15-run-b2c3-blocked", + "policy_decision_id": "policy-fabric://decision/pd-civic-run-b2c3-deny", + "policy_decision_outcome": "deny", + "dataset_ids": ["dataset://restricted/pii-records/batch-009"], + "resource_ids": [], + "tool_grants": [], + "action_dispatch_records": [ + { + "dispatch_id": "dispatch:civic-run-b2c3-blocked-action-1", + "action_type": "pii.access", + "policy_decision_ref": "policy-fabric://decision/pd-civic-run-b2c3-deny", + "dispatch_status": "blocked", + "rationalgrl_task_ref": "task://rationalgrl/pii-access-task/v1", + "defeater_reason": "PolicyFabric denied PII access: insufficient authorization scope for beneficiary PII" + } + ], + "oql_plan_acceptance": { + "acceptance_id": "oql-acceptance:civic-run-b2c3-blocked", + "oql_plan_id": "oql://plan/restricted-data-access-v1/step-1", + "acceptance_status": "rejected", + "interpretation_ref": "oql://interpretation/restricted-data-access-v1/step-1-interp" + }, + "timestamps": { + "started_at": "2024-01-15T11:00:00Z", + "completed_at": "2024-01-15T11:00:04Z" + }, + "provenance_refs": [ + "provenance://sociosphere/civic-stack-run/b2c3-blocked" + ], + "rationalgrl_trace": { + "trace_id": "rationalgrl-trace:civic-run-b2c3-blocked", + "goals_addressed": [ + { + "goal_ref": "goal://rationalgrl/restricted-data-access/primary", + "goal_type": "goal", + "satisfaction_status": "denied", + "contribution_refs": [] + } + ], + "tasks_executed": [ + { + "task_ref": "task://rationalgrl/pii-access-task/v1", + "execution_status": "blocked", + "defeater_reason": "RationalGRL defeater: PolicyFabric deny decision prevents task execution" + } + ], + "dependencies_blocked": [ + { + "dependency_ref": "task://rationalgrl/pii-access-task/v1", + "blocking_policy_ref": "policy-fabric://decision/pd-civic-run-b2c3-deny", + "defeater_reason": "PII access blocked: authorization scope insufficient" + } + ] + }, + "hellgraph_evidence_refs": [ + "evidence://hellgraph/civic-stack-run-b2c3/run-capsule-blocked", + "evidence://prophet-core/civic-stack-run-b2c3/policy-deny-evidence" + ], + "upstream_anchors": [ + "ontogenesis#80", + "policy-fabric#72" + ], + "issued_at": "2024-01-15T11:00:05Z" +} diff --git a/tools/validate_civic_stack_runtime_evidence.py b/tools/validate_civic_stack_runtime_evidence.py new file mode 100644 index 0000000..f4c4850 --- /dev/null +++ b/tools/validate_civic_stack_runtime_evidence.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +import sys +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "civic-stack-run-capsule.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "civic-stack" + +ALLOWED_POLICY_OUTCOMES = {"allow", "allow_with_constraints", "deny", "escalate"} +ALLOWED_DISPATCH_STATUSES = {"dispatched", "blocked", "deferred", "completed"} + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + outcome = data.get("policy_decision_outcome") + if outcome and outcome not in ALLOWED_POLICY_OUTCOMES: + problems.append(f"policy_decision_outcome invalid: {outcome}") + + # deny outcome: tool_grants must be empty and all dispatches must be blocked + if outcome == "deny": + grants = data.get("tool_grants", []) + if grants: + problems.append("deny policy_decision_outcome must have no tool_grants") + dispatches = data.get("action_dispatch_records", []) + non_blocked = [d for d in dispatches if d.get("dispatch_status") != "blocked"] + if non_blocked: + problems.append("deny policy_decision_outcome requires all dispatches blocked") + + # blocked dispatches must have defeater_reason + for dispatch in data.get("action_dispatch_records", []): + if dispatch.get("dispatch_status") == "blocked" and not dispatch.get("defeater_reason"): + problems.append(f"blocked dispatch {dispatch.get('dispatch_id')} requires defeater_reason") + + # rationalgrl_trace: blocked tasks must have defeater_reason + trace = data.get("rationalgrl_trace", {}) + for task in trace.get("tasks_executed", []): + if task.get("execution_status") == "blocked" and not task.get("defeater_reason"): + problems.append(f"blocked task {task.get('task_ref')} in rationalgrl_trace requires defeater_reason") + + # hellgraph_evidence_refs required and non-empty (belt-and-suspenders on schema minItems) + hg_refs = data.get("hellgraph_evidence_refs", []) + if not hg_refs: + problems.append("hellgraph_evidence_refs must not be empty") + + # provenance_refs required and non-empty + prov_refs = data.get("provenance_refs", []) + if not prov_refs: + problems.append("provenance_refs must not be empty") + + # oac_compiler_invocation: failure status should have no artifact_emission_refs + oac = data.get("oac_compiler_invocation") + if oac and oac.get("invocation_status") == "failure": + if oac.get("artifact_emission_refs"): + problems.append("oac_compiler_invocation failure must not have artifact_emission_refs") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid civic-stack fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject civic-stack fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": civic-stack runtime evidence — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From 5e0183cdf733a59915a29863f012abb877174776 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 20:46:43 -0400 Subject: [PATCH 2/9] feat(conversational): evidence and replay integration seam for conversational services (#149) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ConversationalActionEvidence schema: binds conversation session/turn to AgentPlane execution artifact — action_type (8-value enum), policy_decision_ref, execution_artifact_ref, replay_linkage (eligible/verified/divergence_detected/scope), hellgraph_evidence_refs - ConversationalReplayRecord schema: replay artifact for conversational triggers — status (completed/failed/diverged/pending), replay_scope (turn/session/execution_artifact), divergence_record (conditional required when status=diverged) with divergence_type and resolution_status enums, non_claims required - Policy gates: approval_denial forces deny/escalate outcome; replay_divergence_detected requires replay_divergence_ref; diverged status requires divergence_record - 4 valid fixtures (trigger-execution, approval-denial, replay-completed, replay-diverged) + 2 reject fixtures - validate-conversational-evidence wired into Makefile aggregate validate target --- Makefile | 9 +- ...rsational-action-evidence.schema.v0.1.json | 109 ++++++++++++++++ ...versational-replay-record.schema.v0.1.json | 79 ++++++++++++ ...ction-evidence.missing-hellgraph-refs.json | 16 +++ ...replay-record.diverged-without-record.json | 13 ++ ...ional-action-evidence.approval-denial.json | 27 ++++ ...nal-action-evidence.trigger-execution.json | 36 ++++++ ...onversational-replay-record.completed.json | 20 +++ ...conversational-replay-record.diverged.json | 23 ++++ tools/validate_conversational_evidence.py | 119 ++++++++++++++++++ 10 files changed, 449 insertions(+), 2 deletions(-) create mode 100644 schemas/conversational-action-evidence.schema.v0.1.json create mode 100644 schemas/conversational-replay-record.schema.v0.1.json create mode 100644 tests/fixtures/conversational-evidence/reject.conversational-action-evidence.missing-hellgraph-refs.json create mode 100644 tests/fixtures/conversational-evidence/reject.conversational-replay-record.diverged-without-record.json create mode 100644 tests/fixtures/conversational-evidence/valid.conversational-action-evidence.approval-denial.json create mode 100644 tests/fixtures/conversational-evidence/valid.conversational-action-evidence.trigger-execution.json create mode 100644 tests/fixtures/conversational-evidence/valid.conversational-replay-record.completed.json create mode 100644 tests/fixtures/conversational-evidence/valid.conversational-replay-record.diverged.json create mode 100644 tools/validate_conversational_evidence.py diff --git a/Makefile b/Makefile index bcd6b2f..0c43d98 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence python3 tools/validate_execution_timing.py validate-governance-context: @@ -252,6 +252,11 @@ validate-civic-stack-runtime-evidence: python3 -m json.tool schemas/civic-stack-run-capsule.schema.v0.1.json >/dev/null python3 tools/validate_civic_stack_runtime_evidence.py +validate-conversational-evidence: + python3 -m json.tool schemas/conversational-action-evidence.schema.v0.1.json >/dev/null + python3 -m json.tool schemas/conversational-replay-record.schema.v0.1.json >/dev/null + python3 tools/validate_conversational_evidence.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/conversational-action-evidence.schema.v0.1.json b/schemas/conversational-action-evidence.schema.v0.1.json new file mode 100644 index 0000000..94cce05 --- /dev/null +++ b/schemas/conversational-action-evidence.schema.v0.1.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/conversational-action-evidence/v0.1", + "title": "ConversationalActionEvidence", + "description": "Evidence artifact for a conversational action that enters the AgentPlane execution and evidence plane. Binds a conversational turn or multi-turn session to governed execution work — replay linkage, policy decision refs, and HellGraph evidence emission. AgentPlane owns the execution boundary; conversational services own the turn record; this artifact is the seam.", + "type": "object", + "required": [ + "kind", + "evidence_id", + "conversation_session_id", + "turn_id", + "action_type", + "actor_ref", + "policy_decision_ref", + "execution_artifact_ref", + "replay_linkage", + "hellgraph_evidence_refs", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "ConversationalActionEvidence" }, + "evidence_id": { "type": "string", "minLength": 1 }, + "conversation_session_id": { "type": "string", "minLength": 1 }, + "turn_id": { "type": "string", "minLength": 1 }, + "action_type": { + "type": "string", + "enum": [ + "trigger_execution", + "query", + "annotation", + "approval_grant", + "approval_denial", + "escalation", + "cancellation", + "replay_request" + ] + }, + "actor_ref": { "type": "string", "minLength": 1 }, + "service_ref": { "type": "string" }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "policy_outcome": { + "type": "string", + "enum": ["allow", "allow_with_constraints", "deny", "escalate"] + }, + "execution_artifact_ref": { + "type": "string", + "minLength": 1, + "description": "Ref to the AgentPlane execution artifact (run, admission, governed run, etc.) triggered or referenced by this conversational action" + }, + "execution_artifact_kind": { + "type": "string", + "description": "Kind discriminator of the bound execution artifact" + }, + "replay_linkage": { "$ref": "#/$defs/ReplayLinkage" }, + "annotation_refs": { + "type": "array", + "items": { "type": "string" }, + "description": "Optional annotation or comment refs that informed this action" + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "description": "Explicit non-claim declarations scoping this evidence artifact" + }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "$defs": { + "ReplayLinkage": { + "type": "object", + "required": ["replay_eligible", "replay_artifact_ref"], + "additionalProperties": false, + "properties": { + "replay_eligible": { "type": "boolean" }, + "replay_artifact_ref": { "type": "string", "minLength": 1 }, + "replay_verified": { "type": "boolean" }, + "replay_divergence_detected": { "type": "boolean" }, + "replay_divergence_ref": { + "type": "string", + "description": "Ref to divergence record when replay_divergence_detected is true" + }, + "replay_scope": { + "type": "string", + "enum": ["turn", "session", "execution_artifact"], + "description": "What scope the replay covers" + } + } + } + }, + "if": { + "properties": { "action_type": { "const": "approval_denial" } } + }, + "then": { + "properties": { + "policy_outcome": { + "enum": ["deny", "escalate"] + } + } + } +} diff --git a/schemas/conversational-replay-record.schema.v0.1.json b/schemas/conversational-replay-record.schema.v0.1.json new file mode 100644 index 0000000..4e7a40e --- /dev/null +++ b/schemas/conversational-replay-record.schema.v0.1.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/conversational-replay-record/v0.1", + "title": "ConversationalReplayRecord", + "description": "Replay record linking a conversational session or turn to an AgentPlane governed replay execution. Provides the replay artifact for ConversationalActionEvidence.replay_linkage. AgentPlane emits this on replay completion; the conversational service is the upstream consumer.", + "type": "object", + "required": [ + "kind", + "replay_record_id", + "conversation_session_id", + "replay_trigger_ref", + "replay_execution_ref", + "replay_status", + "replay_scope", + "policy_decision_ref", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "ConversationalReplayRecord" }, + "replay_record_id": { "type": "string", "minLength": 1 }, + "conversation_session_id": { "type": "string", "minLength": 1 }, + "turn_id": { "type": "string" }, + "replay_trigger_ref": { + "type": "string", + "minLength": 1, + "description": "Ref to the ConversationalActionEvidence that triggered this replay" + }, + "replay_execution_ref": { + "type": "string", + "minLength": 1, + "description": "Ref to the AgentPlane governed execution artifact for this replay" + }, + "replay_status": { + "type": "string", + "enum": ["completed", "failed", "diverged", "pending"] + }, + "replay_scope": { + "type": "string", + "enum": ["turn", "session", "execution_artifact"] + }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "divergence_record": { + "type": "object", + "required": ["detected_at", "divergence_type", "original_ref", "replay_ref"], + "additionalProperties": false, + "properties": { + "detected_at": { "type": "string", "format": "date-time" }, + "divergence_type": { + "type": "string", + "enum": ["output_mismatch", "policy_change", "data_drift", "actor_change", "tool_unavailable"] + }, + "original_ref": { "type": "string", "minLength": 1 }, + "replay_ref": { "type": "string", "minLength": 1 }, + "resolution_status": { + "type": "string", + "enum": ["unresolved", "accepted", "escalated", "invalidated"] + } + } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "if": { + "properties": { "replay_status": { "const": "diverged" } } + }, + "then": { + "required": ["divergence_record"] + } +} diff --git a/tests/fixtures/conversational-evidence/reject.conversational-action-evidence.missing-hellgraph-refs.json b/tests/fixtures/conversational-evidence/reject.conversational-action-evidence.missing-hellgraph-refs.json new file mode 100644 index 0000000..e91cbf2 --- /dev/null +++ b/tests/fixtures/conversational-evidence/reject.conversational-action-evidence.missing-hellgraph-refs.json @@ -0,0 +1,16 @@ +{ + "_reject_reason": "hellgraph_evidence_refs is required but absent", + "kind": "ConversationalActionEvidence", + "evidence_id": "conv-evidence:reject-no-hellgraph", + "conversation_session_id": "conv-session:reject-sess-001", + "turn_id": "conv-turn:reject-turn-01", + "action_type": "query", + "actor_ref": "agent://agentplane/conversational-gateway/v1", + "policy_decision_ref": "policy-fabric://decision/pd-reject-no-hellgraph", + "execution_artifact_ref": "governed-run://agentplane/runs/reject-no-hellgraph", + "replay_linkage": { + "replay_eligible": false, + "replay_artifact_ref": "replay://agentplane/conversational/replay-reject" + }, + "issued_at": "2024-01-15T14:00:00Z" +} diff --git a/tests/fixtures/conversational-evidence/reject.conversational-replay-record.diverged-without-record.json b/tests/fixtures/conversational-evidence/reject.conversational-replay-record.diverged-without-record.json new file mode 100644 index 0000000..7e69c8f --- /dev/null +++ b/tests/fixtures/conversational-evidence/reject.conversational-replay-record.diverged-without-record.json @@ -0,0 +1,13 @@ +{ + "_reject_reason": "replay_status=diverged requires divergence_record (conditional allOf)", + "kind": "ConversationalReplayRecord", + "replay_record_id": "conv-replay:reject-diverged-no-record", + "conversation_session_id": "conv-session:reject-sess-002", + "replay_trigger_ref": "conv-evidence:reject-trigger", + "replay_execution_ref": "governed-run://agentplane/runs/reject-diverged", + "replay_status": "diverged", + "replay_scope": "turn", + "policy_decision_ref": "policy-fabric://decision/pd-reject-diverged", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T16:00:00Z" +} diff --git a/tests/fixtures/conversational-evidence/valid.conversational-action-evidence.approval-denial.json b/tests/fixtures/conversational-evidence/valid.conversational-action-evidence.approval-denial.json new file mode 100644 index 0000000..219d379 --- /dev/null +++ b/tests/fixtures/conversational-evidence/valid.conversational-action-evidence.approval-denial.json @@ -0,0 +1,27 @@ +{ + "kind": "ConversationalActionEvidence", + "evidence_id": "conv-evidence:b2c3d4-approval-denial", + "conversation_session_id": "conv-session:escalation-review-2024-01-15-sess-002", + "turn_id": "conv-turn:sess-002-turn-03", + "action_type": "approval_denial", + "actor_ref": "user://operator/senior-analyst/badge-7841", + "service_ref": "service://conversational-mesh/escalation-review/v1", + "policy_decision_ref": "policy-fabric://decision/pd-conv-approval-denial-b2c3", + "policy_outcome": "deny", + "execution_artifact_ref": "governed-run://agentplane/runs/run-b2c3d4e5-denied", + "execution_artifact_kind": "GovernedRunContract", + "replay_linkage": { + "replay_eligible": true, + "replay_artifact_ref": "replay://agentplane/conversational/replay-b2c3d4", + "replay_verified": false, + "replay_scope": "turn" + }, + "non_claims": [ + "This artifact does not record the reason for denial beyond the policy decision ref.", + "This artifact does not represent the outcome of any subsequent appeal." + ], + "hellgraph_evidence_refs": [ + "evidence://hellgraph/conversational/conv-evidence-b2c3d4" + ], + "issued_at": "2024-01-15T14:12:10Z" +} diff --git a/tests/fixtures/conversational-evidence/valid.conversational-action-evidence.trigger-execution.json b/tests/fixtures/conversational-evidence/valid.conversational-action-evidence.trigger-execution.json new file mode 100644 index 0000000..6846d16 --- /dev/null +++ b/tests/fixtures/conversational-evidence/valid.conversational-action-evidence.trigger-execution.json @@ -0,0 +1,36 @@ +{ + "kind": "ConversationalActionEvidence", + "evidence_id": "conv-evidence:a1b2c3-trigger-exec", + "conversation_session_id": "conv-session:case-review-2024-01-15-sess-001", + "turn_id": "conv-turn:sess-001-turn-07", + "action_type": "trigger_execution", + "actor_ref": "agent://agentplane/conversational-gateway/v1", + "service_ref": "service://conversational-mesh/case-review-service/v2", + "policy_decision_ref": "policy-fabric://decision/pd-conv-trigger-exec-a1b2", + "policy_outcome": "allow", + "execution_artifact_ref": "governed-run://agentplane/runs/run-a1b2c3d4-case-analysis", + "execution_artifact_kind": "GovernedRunContract", + "replay_linkage": { + "replay_eligible": true, + "replay_artifact_ref": "replay://agentplane/conversational/replay-a1b2c3", + "replay_verified": true, + "replay_divergence_detected": false, + "replay_scope": "execution_artifact" + }, + "annotation_refs": [ + "annotation://case-review/turn-06-analyst-note" + ], + "non_claims": [ + "This artifact does not claim to represent the full conversation transcript.", + "This artifact does not certify outcome quality; it records the execution trigger only." + ], + "hellgraph_evidence_refs": [ + "evidence://hellgraph/conversational/conv-evidence-a1b2c3", + "evidence://prophet-core/conversational/turn-07-exec-trigger" + ], + "upstream_anchors": [ + "standards-storage#conversational-standards", + "agentplane#149" + ], + "issued_at": "2024-01-15T14:07:55Z" +} diff --git a/tests/fixtures/conversational-evidence/valid.conversational-replay-record.completed.json b/tests/fixtures/conversational-evidence/valid.conversational-replay-record.completed.json new file mode 100644 index 0000000..dec6310 --- /dev/null +++ b/tests/fixtures/conversational-evidence/valid.conversational-replay-record.completed.json @@ -0,0 +1,20 @@ +{ + "kind": "ConversationalReplayRecord", + "replay_record_id": "conv-replay:a1b2c3-completed", + "conversation_session_id": "conv-session:case-review-2024-01-15-sess-001", + "turn_id": "conv-turn:sess-001-turn-07", + "replay_trigger_ref": "conv-evidence:a1b2c3-trigger-exec", + "replay_execution_ref": "governed-run://agentplane/runs/replay-run-a1b2c3d4", + "replay_status": "completed", + "replay_scope": "execution_artifact", + "policy_decision_ref": "policy-fabric://decision/pd-conv-replay-a1b2c3", + "non_claims": [ + "This replay record does not certify semantic equivalence of replay output to original.", + "This record does not represent live execution state." + ], + "upstream_anchors": [ + "standards-storage#conversational-standards", + "agentplane#149" + ], + "issued_at": "2024-01-15T15:30:00Z" +} diff --git a/tests/fixtures/conversational-evidence/valid.conversational-replay-record.diverged.json b/tests/fixtures/conversational-evidence/valid.conversational-replay-record.diverged.json new file mode 100644 index 0000000..f7cf9fd --- /dev/null +++ b/tests/fixtures/conversational-evidence/valid.conversational-replay-record.diverged.json @@ -0,0 +1,23 @@ +{ + "kind": "ConversationalReplayRecord", + "replay_record_id": "conv-replay:c3d4e5-diverged", + "conversation_session_id": "conv-session:policy-migration-sess-003", + "turn_id": "conv-turn:sess-003-turn-02", + "replay_trigger_ref": "conv-evidence:c3d4e5-replay-request", + "replay_execution_ref": "governed-run://agentplane/runs/replay-run-c3d4e5", + "replay_status": "diverged", + "replay_scope": "execution_artifact", + "policy_decision_ref": "policy-fabric://decision/pd-conv-replay-c3d4e5", + "divergence_record": { + "detected_at": "2024-01-15T16:05:22Z", + "divergence_type": "policy_change", + "original_ref": "governed-run://agentplane/runs/run-c3d4e5-original", + "replay_ref": "governed-run://agentplane/runs/replay-run-c3d4e5", + "resolution_status": "escalated" + }, + "non_claims": [ + "This record does not prescribe a resolution path for the detected divergence.", + "Divergence escalation outcome is tracked separately by the policy fabric." + ], + "issued_at": "2024-01-15T16:05:25Z" +} diff --git a/tools/validate_conversational_evidence.py b/tools/validate_conversational_evidence.py new file mode 100644 index 0000000..a99aef7 --- /dev/null +++ b/tools/validate_conversational_evidence.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA_CAE = ROOT / "schemas" / "conversational-action-evidence.schema.v0.1.json" +SCHEMA_CRR = ROOT / "schemas" / "conversational-replay-record.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "conversational-evidence" + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def schema_for(data: dict[str, Any], schemas: dict[str, Any]) -> dict[str, Any]: + kind = data.get("kind", "") + if kind == "ConversationalActionEvidence": + return schemas["cae"] + if kind == "ConversationalReplayRecord": + return schemas["crr"] + raise ValueError(f"unknown kind: {kind}") + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + kind = data.get("kind") + + if kind == "ConversationalActionEvidence": + hg_refs = data.get("hellgraph_evidence_refs", []) + if not hg_refs: + problems.append("hellgraph_evidence_refs must not be empty") + + replay = data.get("replay_linkage", {}) + if replay.get("replay_divergence_detected") and not replay.get("replay_divergence_ref"): + problems.append("replay_divergence_detected=true requires replay_divergence_ref") + + action_type = data.get("action_type") + policy_outcome = data.get("policy_outcome") + if action_type == "approval_denial" and policy_outcome not in ("deny", "escalate"): + problems.append("approval_denial action_type requires deny or escalate policy_outcome") + + if kind == "ConversationalReplayRecord": + non_claims = data.get("non_claims", []) + if not non_claims: + problems.append("non_claims must not be empty") + + if data.get("replay_status") == "diverged" and not data.get("divergence_record"): + problems.append("replay_status=diverged requires divergence_record") + + div_rec = data.get("divergence_record") + if div_rec and data.get("replay_status") != "diverged": + problems.append("divergence_record present but replay_status is not diverged") + + return problems + + +def validate_file(path: Path, schemas: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + schema = schema_for(data, schemas) + jsonschema.validate(data, schema) + except (jsonschema.ValidationError, ValueError) as exc: + return [f"schema: {exc}"] + return check_policy_gates(data) + + +def main() -> int: + schemas = { + "cae": load_json(SCHEMA_CAE), + "crr": load_json(SCHEMA_CRR), + } + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid conversational-evidence fixtures") + + for path in valids: + problems = validate_file(path, schemas) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject conversational-evidence fixtures") + + for path in rejects: + problems = validate_file(path, schemas) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": conversational evidence — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From 796013f690dddef3bba2875e932da24d6885406d Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 20:49:38 -0400 Subject: [PATCH 3/9] feat(systema): tensegrity runtime contract, capability radius R0-R5, cybernetic oversteer controls (#136) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/doctrine/tensegrity-runtime-contract.md: compression members (agent/tool/service/model/repo/host) vs tension members (policy/identity/provenance/tests/signatures/audits/ledgers/capability_grants/replay/revocation) and five tensegrity invariants: policy always required, closed chain, revocation dissolves immediately, replay seals the loop, oversteer is a governance obligation - docs/specs/agent-action-tension-members-v0.md: tension member obligations matrix by action type; structural rules (policy always required, replay for mutation actions, audit for blocked/intervention, revocation path at R2+, provenance must include upstream anchor) - docs/specs/capability-radius-v0.md: R0 observe-local through R5 deployment-host-mutation; radius/tool-grant contract; rapid_radius_escalation oversteer indicator - docs/specs/cybernetic-oversteer-v0.md: 10 oversteer indicators with tension member under strain mapping; detection contract (HellGraph emission, delivery_excellence degraded, escalate elevation, RationalGRL softgoal); oversteer vs. error distinction - examples/tensegrity/agent-action-tension-members.example.json: full tension member declaration for R3 write - examples/reachability/agent-capability-radius.example.json: R3 actor profile with conditional R4 gate - examples/governance/oversteer-indicators.example.json: policy_flip_flops + repeated_failed_validations simultaneous firing → escalate elevation + delivery excellence degraded signal --- docs/doctrine/tensegrity-runtime-contract.md | 55 +++++++++++++++++++ docs/specs/agent-action-tension-members-v0.md | 47 ++++++++++++++++ docs/specs/capability-radius-v0.md | 28 ++++++++++ docs/specs/cybernetic-oversteer-v0.md | 40 ++++++++++++++ .../oversteer-indicators.example.json | 42 ++++++++++++++ .../agent-capability-radius.example.json | 45 +++++++++++++++ .../agent-action-tension-members.example.json | 33 +++++++++++ 7 files changed, 290 insertions(+) create mode 100644 docs/doctrine/tensegrity-runtime-contract.md create mode 100644 docs/specs/agent-action-tension-members-v0.md create mode 100644 docs/specs/capability-radius-v0.md create mode 100644 docs/specs/cybernetic-oversteer-v0.md create mode 100644 examples/governance/oversteer-indicators.example.json create mode 100644 examples/reachability/agent-capability-radius.example.json create mode 100644 examples/tensegrity/agent-action-tension-members.example.json diff --git a/docs/doctrine/tensegrity-runtime-contract.md b/docs/doctrine/tensegrity-runtime-contract.md new file mode 100644 index 0000000..4c89fa5 --- /dev/null +++ b/docs/doctrine/tensegrity-runtime-contract.md @@ -0,0 +1,55 @@ +# Tensegrity Runtime Contract + +## Purpose + +AgentPlane's execution model is a **tensegrity structure**: agents, tools, services, models, repos, and hosts are **compression members** — structural elements that do work. They are stabilized by continuous **tension members**: policy, identity, provenance, tests, signatures, audits, ledgers, capability grants, replay, and revocation. + +Neither class functions alone. A compression member without tension yields ungoverned execution. A tension member without a compression member yields policy theater with no work done. + +This contract defines how AgentPlane enforces tensegrity at runtime. + +## Compression Members + +| Compression Member | Description | +|--------------------|-------------| +| Agent | Execution actor with bounded capability radius | +| Tool | Callable surface scoped by tool grant and CGRM decision | +| Service | External or internal service endpoint with policy gate | +| Model | Inference engine with model-routing lane decision | +| Repo | Source repository with branch and GitOps audit chain | +| Host | Execution environment with resource scope and capability radius R5 guard | + +## Tension Members + +| Tension Member | Description | +|----------------|-------------| +| Policy | Policy decision ref from PolicyFabric; required on every execution artifact | +| Identity | Actor ref and post/authority binding; required for all dispatches | +| Provenance | Hash-chain of inputs, prior artifacts, and upstream anchors | +| Tests | Validation receipts and verification execution receipts | +| Signatures | Attestation events and cryptographic seals on receipts | +| Audits | Audit trail refs on intervention outcomes and blocked dispatches | +| Ledgers | Evidence ledger refs and budget settlement receipts | +| Capability Grants | Tool grants scoped by CGRM and capability radius level | +| Replay | Replay artifact ref required on all governed runs | +| Revocation | Revocation path declared at compression member registration | + +## Tensegrity Invariants + +1. **No compression member executes without a policy tension member.** Every agent action, tool invocation, service call, and model routing decision must carry a `policy_decision_ref`. + +2. **Tension members must form a closed chain.** Policy → Identity → Provenance → Evidence → Replay → Revocation must each reference the same run or be transitively linkable through `upstream_anchors`. + +3. **Revocation dissolves a tension member's grip immediately.** A revoked capability grant, expired policy decision, or invalidated identity ref causes the dependent compression member to transition to `blocked` or `deferred` — not to `completed`. + +4. **Replay seals the tensegrity loop.** A governed run without a `replay_artifact_ref` is structurally incomplete. Replay verifies that the compression-plus-tension envelope produces the same result under rerun, or surfaces a `divergence_record` for escalation. + +5. **Oversteer detection is a governance obligation, not an optimization.** See `cybernetic-oversteer-v0.md`. + +## Integration Points + +- `ConversationalActionEvidence` — tension: policy, identity, replay_linkage +- `CivicStackRunCapsule` — tension: policy, provenance_refs, rationalgrl_trace, hellgraph_evidence_refs +- `BoundaryCalculusEvidenceEnvelope` — tension: promotion_gate, policy_result, attribution_discriminating_evidence_refs +- `GovernedRunContract` — tension: policy, budget, verifier chain, replay_artifact_ref +- `CapabilityRadiusProfile` — defines tension member scope per compression member level (R0–R5) diff --git a/docs/specs/agent-action-tension-members-v0.md b/docs/specs/agent-action-tension-members-v0.md new file mode 100644 index 0000000..9f965c2 --- /dev/null +++ b/docs/specs/agent-action-tension-members-v0.md @@ -0,0 +1,47 @@ +# Agent Action Tension Members v0 + +## Purpose + +Defines how a single agent action declares its compression role and the tension members that stabilize it. + +## Structure + +Every agent action artifact in AgentPlane should carry the following tension member declarations: + +``` +action_id — unique identifier for this action +compression_member — agent | tool | service | model | repo | host +policy_ref — policy decision ref (PolicyFabric) +identity_ref — actor or post/authority ref +provenance_refs — hash chain: prior action, run capsule, upstream anchors +evidence_refs — evidence artifacts emitted by or consumed for this action +replay_ref — replay artifact ref (required for governed runs) +revocation_path — revocation URI; if revoked, action transitions to blocked +audit_ref — audit trail ref (required on interventions and blocked outcomes) +``` + +## Tension Member Obligations by Action Type + +| Action Type | Policy | Identity | Provenance | Evidence | Replay | Revocation | Audit | +|----------------------|--------|----------|------------|----------|--------|------------|-------| +| observe | ✓ | ✓ | ✓ | ✓ | — | optional | — | +| query | ✓ | ✓ | ✓ | ✓ | — | optional | — | +| transform | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | +| write | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | +| deploy | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| revoke | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| escalate | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| trigger_execution | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | +| approval_denial | ✓ | ✓ | ✓ | ✓ | ✓ | optional | ✓ | + +## Structural Rules + +1. **`policy_ref` is always required.** No action without a PolicyFabric decision ref is structurally valid. +2. **`replay_ref` is required for actions that mutate state.** transform, write, deploy, revoke, escalate, trigger_execution, approval_denial. +3. **`audit_ref` is required for denied or blocked outcomes** and for any intervention (modified, blocked, escalated) per the bounded-action-loop contract. +4. **`revocation_path` is required for actions at R2 or above** (capability radius). See `capability-radius-v0.md`. +5. **`provenance_refs` must include at least one upstream anchor** linking this action to a run capsule, governed run, or admission artifact. + +## Example + +See `examples/tensegrity/agent-action-tension-members.example.json`. diff --git a/docs/specs/capability-radius-v0.md b/docs/specs/capability-radius-v0.md new file mode 100644 index 0000000..153fa8c --- /dev/null +++ b/docs/specs/capability-radius-v0.md @@ -0,0 +1,28 @@ +# Capability Radius v0 + +## Purpose + +Defines the six capability radius levels (R0–R5) that bound what an agent, tool, or service can do within the tensegrity runtime. Radius is a tension member: it scopes tool grants, CGRM decisions, and revocation paths. + +## Radius Levels + +| Level | Name | Scope | Tension Members Required | +|-------|------------------------|-----------------------------------------------------------------------------------------|---------------------------------------------| +| R0 | observe-local | Read from in-process or local context; no side effects outside the execution envelope | policy, identity | +| R1 | query-bounded | Query services or data stores with read-only scope; results stay in-process | policy, identity, provenance | +| R2 | transform-scoped | Produce or modify artifacts within a governed workspace; no direct writes to shared state | policy, identity, provenance, evidence, replay | +| R3 | write-governed | Write to governed repositories, ledgers, or evidence stores; requires signed receipt | policy, identity, provenance, evidence, replay, revocation | +| R4 | deploy-staged | Deploy to staged or sandboxed environments; Signadot or equivalent runtime gate required | policy, identity, provenance, evidence, replay, revocation, audit | +| R5 | deployment-host-mutation | Mutate production hosts, release branches, or live infrastructure; requires explicit admission gate and senior authority ref | policy, identity, provenance, evidence, replay, revocation, audit, post_authority_ref | + +## Radius and Tool Grants + +A tool grant may not exceed the actor's declared capability radius. Attempting to invoke a tool with a radius higher than the actor's current grant level causes the dispatch to transition to `blocked` with a RationalGRL defeater. + +## Radius and Oversteer + +Rapid radius escalation (R0 → R3 in a single session without intermediate evidence) is an oversteer indicator. See `cybernetic-oversteer-v0.md`. + +## Radius Profile + +The live capability radius profile for an actor or service is declared in `examples/reachability/agent-capability-radius.example.json`. diff --git a/docs/specs/cybernetic-oversteer-v0.md b/docs/specs/cybernetic-oversteer-v0.md new file mode 100644 index 0000000..b791bf8 --- /dev/null +++ b/docs/specs/cybernetic-oversteer-v0.md @@ -0,0 +1,40 @@ +# Cybernetic Oversteer v0 + +## Purpose + +Defines oversteer as a first-class governance condition in the tensegrity runtime. Oversteer occurs when the execution system is self-correcting faster than evidence-gathering can validate. It signals that tension members are under strain: policy is reversing, evidence is not accumulating, or the actor is outrunning its capability radius. + +## Oversteer Indicators + +Each indicator maps to a pattern in the execution record or governance signal stream. + +| Indicator | Description | Tension Member Under Strain | +|-------------------------------|--------------------------------------------------------------------------------------------------|-------------------------------| +| repeated_reversals | The same decision (approve/deny, dispatch/block) is reversed three or more times in a session | Policy | +| patch_churn | More than N patches to the same artifact within a bounded time window without advancing the evidence chain | Provenance, Evidence | +| issue_churn | Issues are opened and closed on the same scope without resolution propagating to execution artifacts | Evidence, Audit | +| branch_churn | More than N branch create/delete cycles on the same base without a merged artifact | Repo, Provenance | +| oscillating_decisions | Policy decisions flip between allow and deny on the same request profile without new evidence | Policy | +| policy_flip_flops | A policy decision is overridden, reinstated, and overridden again within one run capsule | Policy | +| repeated_failed_validations | The same validation check fails three or more consecutive times without a new evidence artifact | Tests, Evidence | +| excessive_retry_no_evidence | Retries exceed threshold with no new evidence_refs added to the run capsule | Evidence, Replay | +| rapid_radius_escalation | Actor capability radius jumps two or more levels without intermediate evidence and policy gates | Capability Grants | +| tension_member_gap | A required tension member (e.g., replay_ref) is absent from a mutation-class action | Varies | + +## Detection Contract + +Oversteer indicators are emitted as `OvensteerIndicator` fields in the `OversteerGovernanceSignal` artifact (see `examples/governance/oversteer-indicators.example.json`). They do not block execution directly but: + +1. Are emitted to HellGraph/Prophet Core as evidence. +2. Trigger a `delivery_excellence_signal_ref` with a degraded score. +3. Elevate the next policy decision request to `escalate` if two or more indicators fire simultaneously. +4. Are included in the RationalGRL trace as softgoal degradation events. + +## Oversteer vs. Error + +An error is a single-point failure with a clear revocation path. Oversteer is a systemic pattern. Errors resolve through repair and evidence. Oversteer resolves through tension member reinforcement: adding evidence, slowing radius expansion, or requiring human authority at R4/R5. + +## Non-Claims + +- This spec does not define the thresholds N for churn indicators; those are set by PolicyFabric configuration per org and repo. +- This spec does not prescribe automatic execution halt; that is a policy gate decision. diff --git a/examples/governance/oversteer-indicators.example.json b/examples/governance/oversteer-indicators.example.json new file mode 100644 index 0000000..566e8e7 --- /dev/null +++ b/examples/governance/oversteer-indicators.example.json @@ -0,0 +1,42 @@ +{ + "kind": "OversteerGovernanceSignalExample", + "description": "Example of an oversteer governance signal fired during a run that exhibited policy flip-flops and repeated failed validations.", + "signal_id": "oversteer-signal:example-run-policy-flipflop-001", + "run_capsule_ref": "civic-stack-run:oversteer-example-001", + "actor_ref": "agent://agentplane/civic-stack-agent/v1", + "session_window": { + "started_at": "2024-01-15T10:00:00Z", + "ended_at": "2024-01-15T10:45:00Z" + }, + "indicators_fired": [ + { + "indicator": "policy_flip_flops", + "count": 3, + "evidence": "Policy decision pd-civic-run-001 was overridden to deny, reinstated to allow, overridden to deny again within the same run capsule.", + "tension_member_under_strain": "policy", + "first_detected_at": "2024-01-15T10:12:00Z" + }, + { + "indicator": "repeated_failed_validations", + "count": 4, + "evidence": "validate-civic-stack-runtime-evidence failed 4 consecutive times on the same input without new evidence_refs added.", + "tension_member_under_strain": "evidence", + "first_detected_at": "2024-01-15T10:22:00Z" + } + ], + "simultaneous_indicators": 2, + "policy_escalation_triggered": true, + "next_policy_decision_elevated_to": "escalate", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/oversteer/signal-example-run-policy-flipflop-001" + ], + "delivery_excellence_signal_ref": "de://signal/oversteer/example-run-policy-flipflop-001/degraded", + "rationalgrl_softgoal_degradation_refs": [ + "goal://rationalgrl/civic-service-delivery/quality" + ], + "non_claims": [ + "This signal does not halt execution; it elevates the next policy decision to escalate.", + "Threshold values for indicator counts are set by PolicyFabric configuration, not this signal." + ], + "issued_at": "2024-01-15T10:45:05Z" +} diff --git a/examples/reachability/agent-capability-radius.example.json b/examples/reachability/agent-capability-radius.example.json new file mode 100644 index 0000000..91e60a1 --- /dev/null +++ b/examples/reachability/agent-capability-radius.example.json @@ -0,0 +1,45 @@ +{ + "kind": "AgentCapabilityRadiusExample", + "description": "Capability radius profile for a governed evidence-writing agent in AgentPlane. Current level R3 with conditional R4 gate.", + "actor_ref": "agent://agentplane/evidence-writer/v2", + "capability_radius": { + "current_level": "R3", + "allowed_levels": ["R0", "R1", "R2", "R3"], + "conditional_levels": [ + { + "level": "R4", + "condition": "Explicit post_authority_ref from senior analyst and signed PolicyFabric R4 grant", + "gate": "policy-fabric://gate/R4-deploy-staged" + } + ], + "denied_levels": ["R5"] + }, + "tool_grants_in_scope": [ + { + "tool_id": "tool://evidence-store/write/v2", + "radius_required": "R3", + "policy_decision_ref": "policy-fabric://decision/pd-tool-grant-evidence-write-v2", + "cgrm_decision_ref": "cgrm://decision/cgrm-evidence-write-v2" + }, + { + "tool_id": "tool://hellgraph/emit/v1", + "radius_required": "R3", + "policy_decision_ref": "policy-fabric://decision/pd-tool-grant-hellgraph-emit-v1", + "cgrm_decision_ref": "cgrm://decision/cgrm-hellgraph-emit-v1" + } + ], + "tension_members_at_current_radius": { + "policy": "required", + "identity": "required", + "provenance": "required", + "evidence": "required", + "replay": "required", + "revocation": "required", + "audit": "required_on_intervention" + }, + "oversteer_guards": { + "max_radius_jump_per_session": 1, + "require_intermediate_evidence_between_jumps": true, + "rapid_radius_escalation_indicator": "rapid_radius_escalation" + } +} diff --git a/examples/tensegrity/agent-action-tension-members.example.json b/examples/tensegrity/agent-action-tension-members.example.json new file mode 100644 index 0000000..6c7aa21 --- /dev/null +++ b/examples/tensegrity/agent-action-tension-members.example.json @@ -0,0 +1,33 @@ +{ + "kind": "AgentActionTensionMembersExample", + "description": "Example demonstrating full tension member declaration for a write-governed action at R3 capability radius.", + "action_id": "action:tensegrity-example-write-governed-001", + "compression_member": "agent", + "action_type": "write", + "capability_radius": "R3", + "policy_ref": "policy-fabric://decision/pd-write-governed-example-001", + "identity_ref": "agent://agentplane/evidence-writer/v2", + "provenance_refs": [ + "provenance://run-capsule/run-tensegrity-example-001", + "provenance://governed-run/governed-run-tensegrity-example-001", + "upstream:agentplane#136" + ], + "evidence_refs": [ + "evidence://hellgraph/tensegrity-example-write/evidence-001", + "evidence://prophet-core/tensegrity-example-write/emission-001" + ], + "replay_ref": "replay://agentplane/tensegrity-example-write/replay-001", + "revocation_path": "revocation://agentplane/capability-grants/evidence-writer-v2/revoke", + "audit_ref": null, + "tension_member_status": { + "policy": "satisfied", + "identity": "satisfied", + "provenance": "satisfied", + "evidence": "satisfied", + "replay": "satisfied", + "revocation": "satisfied", + "audit": "not_required" + }, + "tensegrity_valid": true, + "notes": "All required tension members for R3 write action are present. audit_ref not required because outcome is not denied or blocked." +} From ef1eda083493ccfadf74b437ebab8ae149b31417 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 20:53:34 -0400 Subject: [PATCH 4/9] feat(concept-lineage): Phase 4 concept-to-artifact evidence receipts with replay semantics (#134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ConceptToArtifactLineageReceipt schema: concept_kind (10-value enum: term/definition/geometry_relation/ projection_relation/scenario/prototype/artifact/commons_impact_claim/dymaxion_metric_claim/cross_reference), source_anchor (type/confidence/assumptions), geometry_projection with mandatory distortion_assumptions, artifact_linkage with lineage_chain_refs, commons_impact with evidence_basis enum, dymaxion_metric with required assumptions - extraction_mode 4-value enum: deterministic_extraction → exact replay; model_assisted → near_equivalent; human_review → indicative_only; non_replayable_interpretive_judgment → not_replayable - Policy gates: non_replayable mode forces is_replayable=false + non_replayable_reason required; distortion_assumptions and dymaxion_metric.assumptions must be non-empty; asserted_without_evidence commons claims cannot be peer_reviewed; non_claims required on all receipts - 3 valid fixtures: Dymaxion artifact lineage (model_assisted), geodesic projection claim (human_review), interpretive judgment (non_replayable) + 2 reject fixtures - validate-concept-to-artifact-lineage wired into Makefile aggregate validate target - Integration targets: ontogenesis#61, gaia-world-model#21, sherlock-search#42, sociosphere#291 --- Makefile | 8 +- ...-artifact-lineage-receipt.schema.v0.1.json | 229 ++++++++++++++++++ .../reject.missing-non-claims.json | 20 ++ .../concept-lineage/reject.wrong-kind.json | 21 ++ .../valid.dymaxion-artifact-lineage.json | 60 +++++ .../valid.geodesic-projection-claim.json | 54 +++++ ....interpretive-judgment-non-replayable.json | 45 ++++ tools/validate_concept_to_artifact_lineage.py | 117 +++++++++ 8 files changed, 552 insertions(+), 2 deletions(-) create mode 100644 schemas/concept-to-artifact-lineage-receipt.schema.v0.1.json create mode 100644 tests/fixtures/concept-lineage/reject.missing-non-claims.json create mode 100644 tests/fixtures/concept-lineage/reject.wrong-kind.json create mode 100644 tests/fixtures/concept-lineage/valid.dymaxion-artifact-lineage.json create mode 100644 tests/fixtures/concept-lineage/valid.geodesic-projection-claim.json create mode 100644 tests/fixtures/concept-lineage/valid.interpretive-judgment-non-replayable.json create mode 100644 tools/validate_concept_to_artifact_lineage.py diff --git a/Makefile b/Makefile index 0c43d98..0c81b53 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage python3 tools/validate_execution_timing.py validate-governance-context: @@ -257,6 +257,10 @@ validate-conversational-evidence: python3 -m json.tool schemas/conversational-replay-record.schema.v0.1.json >/dev/null python3 tools/validate_conversational_evidence.py +validate-concept-to-artifact-lineage: + python3 -m json.tool schemas/concept-to-artifact-lineage-receipt.schema.v0.1.json >/dev/null + python3 tools/validate_concept_to_artifact_lineage.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/concept-to-artifact-lineage-receipt.schema.v0.1.json b/schemas/concept-to-artifact-lineage-receipt.schema.v0.1.json new file mode 100644 index 0000000..a4c0fbb --- /dev/null +++ b/schemas/concept-to-artifact-lineage-receipt.schema.v0.1.json @@ -0,0 +1,229 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/concept-to-artifact-lineage-receipt/v0.1", + "title": "ConceptToArtifactLineageReceipt", + "description": "AgentPlane evidence receipt for Phase 4 Fuller/Synergetics concept-to-artifact lineage work. Records concept extraction, source anchors, definition families, cross-references, geometry/projection relations, artifact linkage, commons impact claims, and promotion/rejection state. AgentPlane owns the receipt and replay semantics; Ontogenesis owns the concept ontology.", + "type": "object", + "required": [ + "kind", + "receipt_id", + "concept_id", + "concept_kind", + "source_anchor", + "extraction_mode", + "validation_state", + "replay_semantics", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "ConceptToArtifactLineageReceipt" }, + "receipt_id": { "type": "string", "minLength": 1 }, + "concept_id": { + "type": "string", + "minLength": 1, + "description": "Ref to ConceptEntry in Ontogenesis" + }, + "concept_kind": { + "type": "string", + "enum": [ + "term", + "definition", + "geometry_relation", + "projection_relation", + "scenario", + "prototype", + "artifact", + "commons_impact_claim", + "dymaxion_metric_claim", + "cross_reference" + ] + }, + "source_anchor": { "$ref": "#/$defs/SourceAnchor" }, + "definition_family_refs": { + "type": "array", + "items": { "type": "string" }, + "description": "Refs to related definition-family entries in the concept ontology" + }, + "cross_reference_refs": { + "type": "array", + "items": { "type": "string" } + }, + "geometry_projection": { "$ref": "#/$defs/GeometryProjection" }, + "artifact_linkage": { "$ref": "#/$defs/ArtifactLinkage" }, + "commons_impact": { "$ref": "#/$defs/CommonsImpact" }, + "dymaxion_metric": { "$ref": "#/$defs/DymaxionMetric" }, + "extraction_mode": { + "type": "string", + "enum": [ + "deterministic_extraction", + "model_assisted_extraction", + "human_review", + "non_replayable_interpretive_judgment" + ], + "description": "Distinguishes replay fidelity class: deterministic_extraction and model_assisted_extraction are replayable; human_review and non_replayable_interpretive_judgment are not" + }, + "validation_state": { + "type": "string", + "enum": ["proposed", "validated", "rejected", "under_review", "promoted"] + }, + "promotion_gate_ref": { + "type": "string", + "description": "Ref to the policy/review gate that must pass before promotion" + }, + "replay_semantics": { "$ref": "#/$defs/ReplaySemantics" }, + "policy_decision_ref": { "type": "string" }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" } + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "$defs": { + "SourceAnchor": { + "type": "object", + "required": ["source_ref", "anchor_type", "extraction_confidence"], + "additionalProperties": false, + "properties": { + "source_ref": { "type": "string", "minLength": 1 }, + "anchor_type": { + "type": "string", + "enum": ["text_passage", "figure", "table", "mathematical_expression", "oral_record", "derived"] + }, + "page_or_section": { "type": "string" }, + "extraction_confidence": { + "type": "string", + "enum": ["high", "medium", "low", "unverifiable"] + }, + "assumptions": { + "type": "array", + "items": { "type": "string" }, + "description": "Explicit assumptions made during extraction" + } + } + }, + "GeometryProjection": { + "type": "object", + "required": ["geometry_type", "projection_type", "distortion_assumptions"], + "additionalProperties": false, + "properties": { + "geometry_type": { + "type": "string", + "enum": ["geodesic", "polyhedral", "great_circle", "vector_equilibrium", "fluid_geography", "other"] + }, + "projection_type": { + "type": "string", + "enum": ["dymaxion", "gnomonic", "azimuthal", "cylindrical", "other"] + }, + "distortion_assumptions": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "description": "Explicit assumptions about projection distortions — required because all projections distort; these must not be suppressed" + }, + "relation_refs": { + "type": "array", + "items": { "type": "string" } + } + } + }, + "ArtifactLinkage": { + "type": "object", + "required": ["artifact_ref", "linkage_type"], + "additionalProperties": false, + "properties": { + "artifact_ref": { "type": "string", "minLength": 1 }, + "linkage_type": { + "type": "string", + "enum": ["prototype", "realized_artifact", "referenced_artifact", "computational_model", "commons_output"] + }, + "lineage_chain_refs": { + "type": "array", + "items": { "type": "string" }, + "description": "Ordered chain: term → definition → geometry → scenario → prototype → artifact" + } + } + }, + "CommonsImpact": { + "type": "object", + "required": ["impact_claim", "evidence_basis", "validation_state"], + "additionalProperties": false, + "properties": { + "impact_claim": { "type": "string", "minLength": 1 }, + "evidence_basis": { + "type": "string", + "enum": ["empirical", "modeled", "theoretical", "asserted_without_evidence"] + }, + "validation_state": { + "type": "string", + "enum": ["unvalidated", "peer_reviewed", "rejected", "disputed"] + }, + "evidence_refs": { + "type": "array", + "items": { "type": "string" } + } + } + }, + "DymaxionMetric": { + "type": "object", + "required": ["metric_name", "metric_value", "unit", "source_anchor_ref", "assumptions"], + "additionalProperties": false, + "properties": { + "metric_name": { "type": "string", "minLength": 1 }, + "metric_value": {}, + "unit": { "type": "string", "minLength": 1 }, + "source_anchor_ref": { "type": "string", "minLength": 1 }, + "assumptions": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "validation_state": { + "type": "string", + "enum": ["proposed", "validated", "disputed", "rejected"] + } + } + }, + "ReplaySemantics": { + "type": "object", + "required": ["is_replayable", "replay_fidelity"], + "additionalProperties": false, + "properties": { + "is_replayable": { "type": "boolean" }, + "replay_fidelity": { + "type": "string", + "enum": ["exact", "near_equivalent", "indicative_only", "not_replayable"], + "description": "deterministic_extraction → exact; model_assisted → near_equivalent; human_review → indicative_only; interpretive → not_replayable" + }, + "replay_artifact_ref": { "type": "string" }, + "non_replayable_reason": { + "type": "string", + "description": "Required when is_replayable=false; must explain why rather than suppress" + } + } + } + }, + "if": { + "properties": { "extraction_mode": { "const": "non_replayable_interpretive_judgment" } } + }, + "then": { + "properties": { + "replay_semantics": { + "properties": { + "is_replayable": { "const": false } + } + } + }, + "required": ["non_claims"] + } +} diff --git a/tests/fixtures/concept-lineage/reject.missing-non-claims.json b/tests/fixtures/concept-lineage/reject.missing-non-claims.json new file mode 100644 index 0000000..7ec8c04 --- /dev/null +++ b/tests/fixtures/concept-lineage/reject.missing-non-claims.json @@ -0,0 +1,20 @@ +{ + "_reject_reason": "non_claims is required (minItems: 1) but absent", + "kind": "ConceptToArtifactLineageReceipt", + "receipt_id": "c2a-receipt:reject-missing-non-claims", + "concept_id": "ontogenesis://concept/reject-test/entry", + "concept_kind": "term", + "source_anchor": { + "source_ref": "ontogenesis://source/reject-test/chapter-1", + "anchor_type": "text_passage", + "extraction_confidence": "high", + "assumptions": [] + }, + "extraction_mode": "deterministic_extraction", + "validation_state": "proposed", + "replay_semantics": { + "is_replayable": true, + "replay_fidelity": "exact" + }, + "issued_at": "2024-01-15T13:00:00Z" +} diff --git a/tests/fixtures/concept-lineage/reject.wrong-kind.json b/tests/fixtures/concept-lineage/reject.wrong-kind.json new file mode 100644 index 0000000..c11aefd --- /dev/null +++ b/tests/fixtures/concept-lineage/reject.wrong-kind.json @@ -0,0 +1,21 @@ +{ + "_reject_reason": "kind must be ConceptToArtifactLineageReceipt (const violation)", + "kind": "ConceptLineageReceiptV2", + "receipt_id": "c2a-receipt:reject-wrong-kind", + "concept_id": "ontogenesis://concept/reject-test/entry", + "concept_kind": "term", + "source_anchor": { + "source_ref": "ontogenesis://source/reject-test/chapter-1", + "anchor_type": "text_passage", + "extraction_confidence": "high", + "assumptions": [] + }, + "extraction_mode": "deterministic_extraction", + "validation_state": "proposed", + "replay_semantics": { + "is_replayable": true, + "replay_fidelity": "exact" + }, + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T13:00:00Z" +} diff --git a/tests/fixtures/concept-lineage/valid.dymaxion-artifact-lineage.json b/tests/fixtures/concept-lineage/valid.dymaxion-artifact-lineage.json new file mode 100644 index 0000000..5f14884 --- /dev/null +++ b/tests/fixtures/concept-lineage/valid.dymaxion-artifact-lineage.json @@ -0,0 +1,60 @@ +{ + "kind": "ConceptToArtifactLineageReceipt", + "receipt_id": "c2a-receipt:dymaxion-artifact-lineage-001", + "concept_id": "ontogenesis://concept/dymaxion-map/entry-001", + "concept_kind": "artifact", + "source_anchor": { + "source_ref": "ontogenesis://source/fuller-synergetics-1975/chapter-986", + "anchor_type": "text_passage", + "page_or_section": "986.010–986.085", + "extraction_confidence": "high", + "assumptions": [ + "The 1975 edition text is the canonical reference for this passage.", + "Passage boundary is determined by Fuller's own sectioning, not editorial judgment." + ] + }, + "definition_family_refs": [ + "ontogenesis://concept/world-game/definition-family", + "ontogenesis://concept/geodesic-dome/definition-family" + ], + "cross_reference_refs": [ + "ontogenesis://concept/vector-equilibrium/entry-001", + "ontogenesis://concept/omni-triangulation/entry-001" + ], + "artifact_linkage": { + "artifact_ref": "artifact://dymaxion-map/1943-edition/prototype", + "linkage_type": "prototype", + "lineage_chain_refs": [ + "ontogenesis://concept/closest-packing-spheres/term", + "ontogenesis://concept/icosahedron-projection/definition", + "ontogenesis://concept/dymaxion-projection/geometry_relation", + "ontogenesis://concept/world-game-scenario/scenario", + "artifact://dymaxion-map/1943-edition/prototype" + ] + }, + "extraction_mode": "model_assisted_extraction", + "validation_state": "under_review", + "promotion_gate_ref": "guardrail-fabric://gate/fuller-synergetics-phase4-review", + "replay_semantics": { + "is_replayable": true, + "replay_fidelity": "near_equivalent", + "replay_artifact_ref": "replay://agentplane/concept-lineage/dymaxion-artifact-lineage-001" + }, + "policy_decision_ref": "policy-fabric://decision/pd-concept-lineage-dymaxion-001", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/concept-lineage/dymaxion-artifact-lineage-001" + ], + "upstream_anchors": [ + "ontogenesis#61", + "gaia-world-model#21", + "sherlock-search#42", + "sociosphere#291", + "agentplane#134" + ], + "non_claims": [ + "This receipt does not claim to represent Fuller's intent beyond the referenced text passage.", + "Model-assisted extraction is near-equivalent on replay, not exact; human review is required before promotion.", + "This receipt does not assert historical accuracy of Dymaxion map provenance beyond the source anchor." + ], + "issued_at": "2024-01-15T12:00:00Z" +} diff --git a/tests/fixtures/concept-lineage/valid.geodesic-projection-claim.json b/tests/fixtures/concept-lineage/valid.geodesic-projection-claim.json new file mode 100644 index 0000000..19e813f --- /dev/null +++ b/tests/fixtures/concept-lineage/valid.geodesic-projection-claim.json @@ -0,0 +1,54 @@ +{ + "kind": "ConceptToArtifactLineageReceipt", + "receipt_id": "c2a-receipt:geodesic-projection-claim-001", + "concept_id": "ontogenesis://concept/fluid-geography-projection/entry-002", + "concept_kind": "projection_relation", + "source_anchor": { + "source_ref": "ontogenesis://source/fuller-synergetics-1979/chapter-1009", + "anchor_type": "figure", + "page_or_section": "Fig. 1009.10", + "extraction_confidence": "medium", + "assumptions": [ + "Figure caption is taken as authoritative for the projection type label.", + "Scale bar on the figure is assumed to be accurate to the published edition." + ] + }, + "geometry_projection": { + "geometry_type": "fluid_geography", + "projection_type": "dymaxion", + "distortion_assumptions": [ + "Edge distortion at icosahedron seams is not represented in the flat map.", + "Area preservation is approximate; this projection prioritizes shape over area.", + "Continental coastline accuracy varies by edition and has not been independently verified." + ], + "relation_refs": [ + "ontogenesis://concept/icosahedron-unfolding/geometry_relation", + "ontogenesis://concept/geodesic-great-circle/geometry_relation" + ] + }, + "cross_reference_refs": [ + "ontogenesis://concept/azimuthal-projection/cross_reference" + ], + "extraction_mode": "human_review", + "validation_state": "validated", + "replay_semantics": { + "is_replayable": true, + "replay_fidelity": "indicative_only", + "replay_artifact_ref": "replay://agentplane/concept-lineage/geodesic-projection-claim-001" + }, + "policy_decision_ref": "policy-fabric://decision/pd-concept-lineage-geodesic-001", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/concept-lineage/geodesic-projection-claim-001" + ], + "upstream_anchors": [ + "ontogenesis#61", + "gaia-world-model#21", + "agentplane#134" + ], + "non_claims": [ + "This receipt does not claim the Dymaxion projection is superior to other projections.", + "Human review provides indicative replay only; exact re-extraction is not possible from a figure.", + "This receipt does not claim geographic accuracy of the underlying source figure." + ], + "issued_at": "2024-01-15T12:30:00Z" +} diff --git a/tests/fixtures/concept-lineage/valid.interpretive-judgment-non-replayable.json b/tests/fixtures/concept-lineage/valid.interpretive-judgment-non-replayable.json new file mode 100644 index 0000000..be61738 --- /dev/null +++ b/tests/fixtures/concept-lineage/valid.interpretive-judgment-non-replayable.json @@ -0,0 +1,45 @@ +{ + "kind": "ConceptToArtifactLineageReceipt", + "receipt_id": "c2a-receipt:interpretive-commons-claim-001", + "concept_id": "ontogenesis://concept/world-game-commons-impact/entry-003", + "concept_kind": "commons_impact_claim", + "source_anchor": { + "source_ref": "ontogenesis://source/fuller-operating-manual-1969/chapter-4", + "anchor_type": "oral_record", + "page_or_section": "World Game Workshop transcript, 1969", + "extraction_confidence": "low", + "assumptions": [ + "Transcript accuracy depends on the fidelity of the 1969 recording and transcription.", + "Speaker intent is interpreted, not recoverable from transcript alone." + ] + }, + "commons_impact": { + "impact_claim": "World Game resource distribution model could reduce global resource scarcity if deployed at planetary scale.", + "evidence_basis": "theoretical", + "validation_state": "disputed", + "evidence_refs": [ + "ontogenesis://source/world-game-institute/archive-001" + ] + }, + "extraction_mode": "non_replayable_interpretive_judgment", + "validation_state": "proposed", + "replay_semantics": { + "is_replayable": false, + "replay_fidelity": "not_replayable", + "non_replayable_reason": "This claim is an interpretive judgment about historical intent from an oral record. Re-extraction by any agent would produce a different interpretation; no deterministic or model-consistent replay is possible." + }, + "policy_decision_ref": "policy-fabric://decision/pd-concept-lineage-interpretive-001", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/concept-lineage/interpretive-commons-claim-001" + ], + "upstream_anchors": [ + "ontogenesis#61", + "agentplane#134" + ], + "non_claims": [ + "This receipt does not assert the commons impact claim is correct or validated.", + "Non-replayable interpretive judgment is explicitly marked; it must not be used as proof.", + "This receipt does not store the model rationale chain that produced the interpretation." + ], + "issued_at": "2024-01-15T13:00:00Z" +} diff --git a/tools/validate_concept_to_artifact_lineage.py b/tools/validate_concept_to_artifact_lineage.py new file mode 100644 index 0000000..fdf0d31 --- /dev/null +++ b/tools/validate_concept_to_artifact_lineage.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "concept-to-artifact-lineage-receipt.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "concept-lineage" + +NON_REPLAYABLE_MODES = {"non_replayable_interpretive_judgment"} +REPLAYABLE_MODES = {"deterministic_extraction", "model_assisted_extraction", "human_review"} + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + non_claims = data.get("non_claims", []) + if not non_claims: + problems.append("non_claims must not be empty") + + extraction_mode = data.get("extraction_mode") + replay = data.get("replay_semantics", {}) + + if extraction_mode in NON_REPLAYABLE_MODES: + if replay.get("is_replayable") is not False: + problems.append("non_replayable_interpretive_judgment must have is_replayable=false") + if not replay.get("non_replayable_reason"): + problems.append("non_replayable_interpretive_judgment requires non_replayable_reason") + + if extraction_mode in REPLAYABLE_MODES: + if replay.get("is_replayable") is False and not replay.get("non_replayable_reason"): + problems.append("non-replayable receipt with replayable extraction_mode requires non_replayable_reason") + + # geometry_projection.distortion_assumptions must be non-empty when present + geo = data.get("geometry_projection") + if geo: + if not geo.get("distortion_assumptions"): + problems.append("geometry_projection.distortion_assumptions must not be empty") + + # dymaxion_metric.assumptions must be non-empty when present + metric = data.get("dymaxion_metric") + if metric: + if not metric.get("assumptions"): + problems.append("dymaxion_metric.assumptions must not be empty") + + # No unreviewed model rationale stored as proof: + # commons_impact with evidence_basis=asserted_without_evidence must not be validated + commons = data.get("commons_impact") + if commons: + if commons.get("evidence_basis") == "asserted_without_evidence" and commons.get("validation_state") in ("peer_reviewed",): + problems.append("commons_impact with asserted_without_evidence basis cannot be peer_reviewed") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid concept-lineage fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject concept-lineage fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": concept-to-artifact lineage — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From 02094f4a9fe8788f3d08198b8eb7b4d3e3102d9c Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 20:56:58 -0400 Subject: [PATCH 5/9] feat(model-routing): enforce model-routing lane decisions in agent execution artifacts (#119) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ModelRoutingLaneDecisionReceipt schema: run_ref, chain_stage (planning/execution/verification/ reflection/synthesis), task_class (8 values), requested_lane, selected_lane (5 lanes: no_model through pro), lane_decision_outcome (lane_selected/downgraded/escalated/denied/deferred), cost_class, prompt_evidence_policy (hash_only default — raw prompts never stored), context_tool_posture, verification_mode - High-end/pro conditional: selected_lane=high_end or pro requires escalation_receipt_ref + de_escalation_required_after_stage (schema conditional allOf) - Policy gates: denied outcome must de-escalate to no_model; verification stage must not use model_primary; high-end without escalation_receipt → denied; no raw prompts enforced - 4 valid fixtures: standard lane_selected, escalated high_end with receipt+de-escalation, verification no_model mechanical_tools_only, denied high_end without escalation de-escalated to no_model - 2 reject fixtures - validate-model-routing-lane-receipts wired into Makefile aggregate validate target - Consumers: model-router (AgentExecutionModelRoutingPolicy), guardrail-fabric integration --- Makefile | 8 +- ...ing-lane-decision-receipt.schema.v0.1.json | 124 ++++++++++++++++++ ...t.high-end-missing-escalation-receipt.json | 19 +++ .../model-routing/reject.wrong-kind.json | 18 +++ .../valid.denied-high-end-no-escalation.json | 21 +++ .../valid.escalated-high-end-planning.json | 32 +++++ .../valid.lane-selected-standard.json | 29 ++++ .../valid.verification-no-model.json | 21 +++ tools/validate_model_routing_lane_receipts.py | 113 ++++++++++++++++ 9 files changed, 383 insertions(+), 2 deletions(-) create mode 100644 schemas/model-routing-lane-decision-receipt.schema.v0.1.json create mode 100644 tests/fixtures/model-routing/reject.high-end-missing-escalation-receipt.json create mode 100644 tests/fixtures/model-routing/reject.wrong-kind.json create mode 100644 tests/fixtures/model-routing/valid.denied-high-end-no-escalation.json create mode 100644 tests/fixtures/model-routing/valid.escalated-high-end-planning.json create mode 100644 tests/fixtures/model-routing/valid.lane-selected-standard.json create mode 100644 tests/fixtures/model-routing/valid.verification-no-model.json create mode 100644 tools/validate_model_routing_lane_receipts.py diff --git a/Makefile b/Makefile index 0c81b53..ac0ffb2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts python3 tools/validate_execution_timing.py validate-governance-context: @@ -261,6 +261,10 @@ validate-concept-to-artifact-lineage: python3 -m json.tool schemas/concept-to-artifact-lineage-receipt.schema.v0.1.json >/dev/null python3 tools/validate_concept_to_artifact_lineage.py +validate-model-routing-lane-receipts: + python3 -m json.tool schemas/model-routing-lane-decision-receipt.schema.v0.1.json >/dev/null + python3 tools/validate_model_routing_lane_receipts.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/model-routing-lane-decision-receipt.schema.v0.1.json b/schemas/model-routing-lane-decision-receipt.schema.v0.1.json new file mode 100644 index 0000000..4c04ebd --- /dev/null +++ b/schemas/model-routing-lane-decision-receipt.schema.v0.1.json @@ -0,0 +1,124 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/model-routing-lane-decision-receipt/v0.1", + "title": "ModelRoutingLaneDecisionReceipt", + "description": "AgentPlane evidence receipt for a model-routing lane decision. Consumed from model-router AgentExecutionModelRoutingPolicy and recorded as first-class execution evidence. Required before any model-backed execution stage. AgentPlane enforces the contract; model-router owns policy semantics.", + "type": "object", + "required": [ + "kind", + "receipt_id", + "run_ref", + "chain_stage", + "task_class", + "requested_lane", + "selected_lane", + "lane_decision_outcome", + "cost_class", + "prompt_evidence_policy", + "context_tool_posture", + "policy_decision_ref", + "model_router_policy_ref", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "ModelRoutingLaneDecisionReceipt" }, + "receipt_id": { "type": "string", "minLength": 1 }, + "run_ref": { "type": "string", "minLength": 1 }, + "chain_stage": { + "type": "string", + "enum": ["planning", "execution", "verification", "reflection", "synthesis"], + "description": "Stage in the agent execution chain. verification defaults to no-model (mechanical tools)." + }, + "task_class": { + "type": "string", + "enum": [ + "reasoning", + "code_generation", + "code_review", + "data_extraction", + "summarization", + "verification", + "classification", + "retrieval_augmented" + ] + }, + "requested_lane": { "$ref": "#/$defs/RoutingLane" }, + "selected_lane": { "$ref": "#/$defs/RoutingLane" }, + "lane_decision_outcome": { + "type": "string", + "enum": ["lane_selected", "downgraded", "escalated", "denied", "deferred"], + "description": "denied: high-end/pro requested without escalation receipt; deferred: pending approval" + }, + "downgrade_reason": { "type": "string" }, + "escalation_reason": { "type": "string" }, + "escalation_receipt_ref": { + "type": "string", + "description": "Required when selected_lane=high_end or pro and lane_decision_outcome=escalated" + }, + "de_escalation_required_after_stage": { + "type": "boolean", + "description": "True when the current high-end/pro selection must de-escalate in subsequent stages unless independently re-qualified" + }, + "cost_class": { + "type": "string", + "enum": ["minimal", "standard", "elevated", "high", "pro"] + }, + "prompt_evidence_policy": { + "type": "string", + "enum": ["hash_only", "hash_and_schema", "redacted_summary"], + "description": "hash_only is the default. Raw prompts are never stored." + }, + "prompt_hash_ref": { + "type": "string", + "description": "Hash ref to prompt, per prompt_evidence_policy. Never raw text." + }, + "context_tool_posture": { + "type": "string", + "enum": ["tools_disabled", "tools_read_only", "tools_governed", "tools_full"], + "description": "Governs tool access during this model-backed stage" + }, + "verification_mode": { + "type": "string", + "enum": ["mechanical_tools_only", "model_assisted", "model_primary"], + "description": "Verification stage should be mechanical_tools_only by default" + }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "model_router_policy_ref": { + "type": "string", + "minLength": 1, + "description": "Ref to the AgentExecutionModelRoutingPolicy in model-router" + }, + "guardrail_fabric_ref": { "type": "string" }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" } + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "$defs": { + "RoutingLane": { + "type": "string", + "enum": ["no_model", "lightweight", "standard", "high_end", "pro"], + "description": "no_model: mechanical tools only; lightweight: fast/cheap; standard: balanced; high_end: frontier reasoning; pro: maximum capability" + } + }, + "if": { + "properties": { + "selected_lane": { "enum": ["high_end", "pro"] } + } + }, + "then": { + "required": ["escalation_receipt_ref", "de_escalation_required_after_stage"] + } +} diff --git a/tests/fixtures/model-routing/reject.high-end-missing-escalation-receipt.json b/tests/fixtures/model-routing/reject.high-end-missing-escalation-receipt.json new file mode 100644 index 0000000..839ed6e --- /dev/null +++ b/tests/fixtures/model-routing/reject.high-end-missing-escalation-receipt.json @@ -0,0 +1,19 @@ +{ + "_reject_reason": "selected_lane=high_end requires escalation_receipt_ref and de_escalation_required_after_stage (conditional allOf)", + "kind": "ModelRoutingLaneDecisionReceipt", + "receipt_id": "route-receipt:reject-highend-no-escalation", + "run_ref": "governed-run://agentplane/runs/reject-highend", + "chain_stage": "planning", + "task_class": "reasoning", + "requested_lane": "high_end", + "selected_lane": "high_end", + "lane_decision_outcome": "escalated", + "escalation_reason": "some reason", + "cost_class": "high", + "prompt_evidence_policy": "hash_only", + "context_tool_posture": "tools_governed", + "policy_decision_ref": "policy-fabric://decision/pd-reject-highend", + "model_router_policy_ref": "model-router://policy/default", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T10:00:00Z" +} diff --git a/tests/fixtures/model-routing/reject.wrong-kind.json b/tests/fixtures/model-routing/reject.wrong-kind.json new file mode 100644 index 0000000..ac0064a --- /dev/null +++ b/tests/fixtures/model-routing/reject.wrong-kind.json @@ -0,0 +1,18 @@ +{ + "_reject_reason": "kind must be ModelRoutingLaneDecisionReceipt (const violation)", + "kind": "ModelRoutingReceipt", + "receipt_id": "route-receipt:reject-wrong-kind", + "run_ref": "governed-run://agentplane/runs/reject-wrong-kind", + "chain_stage": "planning", + "task_class": "reasoning", + "requested_lane": "standard", + "selected_lane": "standard", + "lane_decision_outcome": "lane_selected", + "cost_class": "standard", + "prompt_evidence_policy": "hash_only", + "context_tool_posture": "tools_governed", + "policy_decision_ref": "policy-fabric://decision/pd-reject-wrong-kind", + "model_router_policy_ref": "model-router://policy/default", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T10:00:00Z" +} diff --git a/tests/fixtures/model-routing/valid.denied-high-end-no-escalation.json b/tests/fixtures/model-routing/valid.denied-high-end-no-escalation.json new file mode 100644 index 0000000..38cb6e7 --- /dev/null +++ b/tests/fixtures/model-routing/valid.denied-high-end-no-escalation.json @@ -0,0 +1,21 @@ +{ + "kind": "ModelRoutingLaneDecisionReceipt", + "receipt_id": "route-receipt:denied-high-end-no-escalation-run-c3d4", + "run_ref": "governed-run://agentplane/runs/run-c3d4e5-denied", + "chain_stage": "execution", + "task_class": "code_generation", + "requested_lane": "high_end", + "selected_lane": "no_model", + "lane_decision_outcome": "denied", + "downgrade_reason": "high_end lane requested without a valid escalation receipt; execution stage denied, de-escalated to no_model pending escalation approval.", + "cost_class": "minimal", + "prompt_evidence_policy": "hash_only", + "context_tool_posture": "tools_disabled", + "policy_decision_ref": "policy-fabric://decision/pd-model-routing-denied-c3d4", + "model_router_policy_ref": "model-router://policy/agent-execution-model-routing/default.v1", + "non_claims": [ + "Denial does not imply the task class is invalid, only that escalation authorization was not present.", + "This receipt does not store the contents of the denied request." + ], + "issued_at": "2024-01-15T10:00:04Z" +} diff --git a/tests/fixtures/model-routing/valid.escalated-high-end-planning.json b/tests/fixtures/model-routing/valid.escalated-high-end-planning.json new file mode 100644 index 0000000..c4dfa53 --- /dev/null +++ b/tests/fixtures/model-routing/valid.escalated-high-end-planning.json @@ -0,0 +1,32 @@ +{ + "kind": "ModelRoutingLaneDecisionReceipt", + "receipt_id": "route-receipt:high-end-planning-run-b2c3", + "run_ref": "governed-run://agentplane/runs/run-b2c3d4-complex-reasoning", + "chain_stage": "planning", + "task_class": "reasoning", + "requested_lane": "high_end", + "selected_lane": "high_end", + "lane_decision_outcome": "escalated", + "escalation_reason": "Task requires multi-step causal reasoning across 6+ dependent services; standard lane scored insufficient confidence on prior similar tasks.", + "escalation_receipt_ref": "escalation://model-router/receipts/escalation-b2c3d4-planning", + "de_escalation_required_after_stage": true, + "cost_class": "high", + "prompt_evidence_policy": "hash_only", + "prompt_hash_ref": "sha256:b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5", + "context_tool_posture": "tools_governed", + "policy_decision_ref": "policy-fabric://decision/pd-model-routing-highend-b2c3", + "model_router_policy_ref": "model-router://policy/agent-execution-model-routing/default.v1", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/model-routing/route-receipt-highend-b2c3" + ], + "upstream_anchors": [ + "model-router://schemas/agent-execution-model-routing-policy", + "agentplane#119" + ], + "non_claims": [ + "This receipt does not store raw prompts.", + "high_end lane selection must de-escalate in subsequent chain stages unless independently re-qualified.", + "This receipt does not claim the escalation reason is the only valid justification for high_end selection." + ], + "issued_at": "2024-01-15T10:00:02Z" +} diff --git a/tests/fixtures/model-routing/valid.lane-selected-standard.json b/tests/fixtures/model-routing/valid.lane-selected-standard.json new file mode 100644 index 0000000..8dc0405 --- /dev/null +++ b/tests/fixtures/model-routing/valid.lane-selected-standard.json @@ -0,0 +1,29 @@ +{ + "kind": "ModelRoutingLaneDecisionReceipt", + "receipt_id": "route-receipt:standard-planning-run-a1b2", + "run_ref": "governed-run://agentplane/runs/run-a1b2c3-code-review", + "chain_stage": "planning", + "task_class": "reasoning", + "requested_lane": "standard", + "selected_lane": "standard", + "lane_decision_outcome": "lane_selected", + "cost_class": "standard", + "prompt_evidence_policy": "hash_only", + "prompt_hash_ref": "sha256:a3b1c2d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2", + "context_tool_posture": "tools_governed", + "policy_decision_ref": "policy-fabric://decision/pd-model-routing-standard-a1b2", + "model_router_policy_ref": "model-router://policy/agent-execution-model-routing/default.v1", + "guardrail_fabric_ref": "guardrail-fabric://gate/model-routing-lane-a1b2", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/model-routing/route-receipt-standard-a1b2" + ], + "upstream_anchors": [ + "model-router://schemas/agent-execution-model-routing-policy", + "agentplane#119" + ], + "non_claims": [ + "This receipt does not store raw prompts; only hash_only evidence is retained.", + "This receipt does not claim to represent model provider selection; lane selection is abstracted from providers." + ], + "issued_at": "2024-01-15T10:00:01Z" +} diff --git a/tests/fixtures/model-routing/valid.verification-no-model.json b/tests/fixtures/model-routing/valid.verification-no-model.json new file mode 100644 index 0000000..55c9bec --- /dev/null +++ b/tests/fixtures/model-routing/valid.verification-no-model.json @@ -0,0 +1,21 @@ +{ + "kind": "ModelRoutingLaneDecisionReceipt", + "receipt_id": "route-receipt:verification-no-model-run-a1b2", + "run_ref": "governed-run://agentplane/runs/run-a1b2c3-code-review", + "chain_stage": "verification", + "task_class": "verification", + "requested_lane": "no_model", + "selected_lane": "no_model", + "lane_decision_outcome": "lane_selected", + "cost_class": "minimal", + "prompt_evidence_policy": "hash_only", + "context_tool_posture": "tools_read_only", + "verification_mode": "mechanical_tools_only", + "policy_decision_ref": "policy-fabric://decision/pd-model-routing-verification-a1b2", + "model_router_policy_ref": "model-router://policy/agent-execution-model-routing/default.v1", + "non_claims": [ + "Verification stage uses mechanical tools only (tests, linters, schema validation, diffs, build output).", + "This receipt does not claim the verification output is model-interpreted." + ], + "issued_at": "2024-01-15T10:00:03Z" +} diff --git a/tools/validate_model_routing_lane_receipts.py b/tools/validate_model_routing_lane_receipts.py new file mode 100644 index 0000000..29337dd --- /dev/null +++ b/tools/validate_model_routing_lane_receipts.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "model-routing-lane-decision-receipt.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "model-routing" + +HIGH_LANES = {"high_end", "pro"} + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + selected = data.get("selected_lane") + outcome = data.get("lane_decision_outcome") + stage = data.get("chain_stage") + + # high-end/pro without escalation receipt is denied + if selected in HIGH_LANES and outcome not in ("denied", "deferred"): + if not data.get("escalation_receipt_ref"): + problems.append(f"selected_lane={selected} requires escalation_receipt_ref unless denied/deferred") + if data.get("de_escalation_required_after_stage") is None: + problems.append(f"selected_lane={selected} requires de_escalation_required_after_stage") + + # denied outcome: selected_lane should not be high-end (de-escalate to no_model) + if outcome == "denied" and selected in HIGH_LANES: + problems.append("denied outcome should de-escalate selected_lane to no_model or lightweight") + + # verification stage must default to no_model; model_primary not allowed + if stage == "verification": + vm = data.get("verification_mode") + if vm == "model_primary": + problems.append("verification stage must not use model_primary") + if selected not in ("no_model", "lightweight"): + # warn only if verification_mode is explicitly model_primary or not mechanical + if vm and vm != "mechanical_tools_only": + problems.append("verification stage should use mechanical_tools_only or no_model lane") + + # no raw prompts: prompt_evidence_policy must never be absent + if not data.get("prompt_evidence_policy"): + problems.append("prompt_evidence_policy is required") + + # non_claims required + if not data.get("non_claims"): + problems.append("non_claims must not be empty") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid model-routing fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject model-routing fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": model-routing lane receipts — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From f126074048b69a2699c1c27d4e677260e2f5d2fc Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:00:57 -0400 Subject: [PATCH 6/9] feat(shir): governed SHIR chain as AgentPlane job v0.1 (#112) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SHIRGovernedChainJob schema: job_type const (shir.governed_chain.v0.1), 4 required inputs (input_ref, schema_ref, ontology_profile_ref, out_ref), policy_mode (advisory/fail_closed/review_required), relation_strategy (default relation_node), all 4 stages (rdf_to_shir/shir_to_pyg/semantic_leakage/chain_receipt), full artifact manifest (11 artifact refs), 8 failure modes - job_status conditional: requires_review/failed_closed require failure_mode + policy_outcome - Policy gates: fail_closed + semantic_leakage_blocking → failed_closed; completed requires chain_receipt completed; shir_to_pyg completed requires projection_loss_report_ref - 2 valid fixtures: clean TopoLVM run (allowed) + leakage review_required (semantic_leakage_blocking) - 2 reject fixtures: wrong job_type const, requires_review without failure_mode - validate-shir-governed-chain-job wired into Makefile aggregate validate target - Non-goals enforced: no tensor materialization, no GNN training, no ontology promotion, no PyTorch/PyG/DGL - Upstream: mlops-ts-suite#36-39, #45, #46 --- Makefile | 8 +- .../shir-governed-chain-job.schema.v0.1.json | 161 ++++++++++++++++++ ....requires-review-missing-failure-mode.json | 23 +++ .../shir-chain/reject.wrong-job-type.json | 23 +++ .../valid.shir-chain-completed-toplvm.json | 86 ++++++++++ ...id.shir-chain-requires-review-leakage.json | 64 +++++++ tools/validate_shir_governed_chain_job.py | 118 +++++++++++++ 7 files changed, 481 insertions(+), 2 deletions(-) create mode 100644 schemas/shir-governed-chain-job.schema.v0.1.json create mode 100644 tests/fixtures/shir-chain/reject.requires-review-missing-failure-mode.json create mode 100644 tests/fixtures/shir-chain/reject.wrong-job-type.json create mode 100644 tests/fixtures/shir-chain/valid.shir-chain-completed-toplvm.json create mode 100644 tests/fixtures/shir-chain/valid.shir-chain-requires-review-leakage.json create mode 100644 tools/validate_shir_governed_chain_job.py diff --git a/Makefile b/Makefile index ac0ffb2..b9df980 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job python3 tools/validate_execution_timing.py validate-governance-context: @@ -265,6 +265,10 @@ validate-model-routing-lane-receipts: python3 -m json.tool schemas/model-routing-lane-decision-receipt.schema.v0.1.json >/dev/null python3 tools/validate_model_routing_lane_receipts.py +validate-shir-governed-chain-job: + python3 -m json.tool schemas/shir-governed-chain-job.schema.v0.1.json >/dev/null + python3 tools/validate_shir_governed_chain_job.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/shir-governed-chain-job.schema.v0.1.json b/schemas/shir-governed-chain-job.schema.v0.1.json new file mode 100644 index 0000000..a4dff0c --- /dev/null +++ b/schemas/shir-governed-chain-job.schema.v0.1.json @@ -0,0 +1,161 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/shir-governed-chain-job/v0.1", + "title": "SHIRGovernedChainJob", + "description": "AgentPlane job contract for the governed SHIR chain (rdf-to-shir → shir-to-pyg → semantic-leakage → chain receipt). job_type: shir.governed_chain.v0.1. No PyTorch/PyG/DGL runtime required in v0.1. AgentPlane orchestrates stages, retains artifacts, and emits the chain run receipt.", + "type": "object", + "required": [ + "kind", + "job_id", + "job_type", + "input_ref", + "schema_ref", + "ontology_profile_ref", + "out_ref", + "policy_mode", + "relation_strategy", + "stages", + "artifacts", + "job_status", + "policy_decision_ref", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "SHIRGovernedChainJob" }, + "job_id": { "type": "string", "minLength": 1 }, + "job_type": { "type": "string", "const": "shir.governed_chain.v0.1" }, + "input_ref": { + "type": "string", + "minLength": 1, + "description": "RDF/Turtle/JSON-LD/TriG artifact reference; v0.1 defaults to Turtle" + }, + "input_format": { + "type": "string", + "enum": ["turtle", "json-ld", "trig", "n-quads"], + "default": "turtle" + }, + "schema_ref": { "type": "string", "minLength": 1 }, + "ontology_profile_ref": { "type": "string", "minLength": 1 }, + "out_ref": { + "type": "string", + "minLength": 1, + "description": "Artifact-retention location (stable run directory or object prefix)" + }, + "prediction_cutoff": { + "type": "string", + "format": "date-time", + "description": "Optional timestamp for semantic leakage checks" + }, + "policy_mode": { + "type": "string", + "enum": ["advisory", "fail_closed", "review_required"] + }, + "relation_strategy": { + "type": "string", + "enum": ["relation_node", "edge_only", "hybrid"], + "description": "v0.1 default: relation_node" + }, + "stages": { "$ref": "#/$defs/SHIRChainStages" }, + "artifacts": { "$ref": "#/$defs/SHIRArtifacts" }, + "failure_mode": { + "type": "string", + "enum": [ + "none", + "syntax_parse_failure", + "schema_validation_failure", + "projection_loss_blocking", + "semantic_leakage_blocking", + "policy_denied", + "artifact_retention_failure", + "downstream_publication_failure", + "replay_mismatch" + ] + }, + "failure_artifact_ref": { + "type": "string", + "description": "Structured error artifact ref when failure_mode is set" + }, + "job_status": { + "type": "string", + "enum": ["running", "completed", "requires_review", "failed_closed", "failed", "denied"] + }, + "policy_outcome": { + "type": "string", + "enum": ["allowed", "requires_review", "denied", "failed_closed"] + }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "replay_artifact_ref": { "type": "string" }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" } + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "$defs": { + "SHIRChainStages": { + "type": "object", + "required": ["rdf_to_shir", "shir_to_pyg", "semantic_leakage", "chain_receipt"], + "additionalProperties": false, + "properties": { + "rdf_to_shir": { "$ref": "#/$defs/StageRecord" }, + "shir_to_pyg": { "$ref": "#/$defs/StageRecord" }, + "semantic_leakage": { "$ref": "#/$defs/StageRecord" }, + "chain_receipt": { "$ref": "#/$defs/StageRecord" } + } + }, + "StageRecord": { + "type": "object", + "required": ["stage_id", "stage_status"], + "additionalProperties": false, + "properties": { + "stage_id": { "type": "string", "minLength": 1 }, + "stage_status": { + "type": "string", + "enum": ["pending", "running", "completed", "failed", "skipped", "blocked"] + }, + "stage_receipt_ref": { "type": "string" }, + "failure_reason": { "type": "string" }, + "artifact_refs": { + "type": "array", + "items": { "type": "string" } + } + } + }, + "SHIRArtifacts": { + "type": "object", + "additionalProperties": false, + "properties": { + "shir_candidate_assertion_ref": { "type": "string" }, + "shir_assertion_ref": { "type": "string" }, + "rdf_to_shir_receipt_ref": { "type": "string" }, + "pyg_manifest_ref": { "type": "string" }, + "projection_manifest_ref": { "type": "string" }, + "projection_loss_report_ref": { "type": "string" }, + "shir_to_pyg_receipt_ref": { "type": "string" }, + "semantic_leakage_report_ref": { "type": "string" }, + "semantic_leakage_projection_loss_report_ref": { "type": "string" }, + "semantic_leakage_receipt_ref": { "type": "string" }, + "chain_run_receipt_ref": { "type": "string" } + } + } + }, + "if": { + "properties": { + "job_status": { "enum": ["requires_review", "failed_closed"] } + } + }, + "then": { + "required": ["failure_mode", "policy_outcome"] + } +} diff --git a/tests/fixtures/shir-chain/reject.requires-review-missing-failure-mode.json b/tests/fixtures/shir-chain/reject.requires-review-missing-failure-mode.json new file mode 100644 index 0000000..4b0bb48 --- /dev/null +++ b/tests/fixtures/shir-chain/reject.requires-review-missing-failure-mode.json @@ -0,0 +1,23 @@ +{ + "_reject_reason": "job_status=requires_review requires failure_mode and policy_outcome (conditional allOf)", + "kind": "SHIRGovernedChainJob", + "job_id": "shir-job:reject-review-missing-failure", + "job_type": "shir.governed_chain.v0.1", + "input_ref": "artifact://fabric-mlops-ts-suite/rdf/test.ttl", + "schema_ref": "semantic-serdes://schema/shir-v1/test", + "ontology_profile_ref": "ontogenesis://profile/shir/test", + "out_ref": "artifact://agentplane/shir-jobs/reject-review-missing-failure/output", + "policy_mode": "review_required", + "relation_strategy": "relation_node", + "stages": { + "rdf_to_shir": { "stage_id": "s1", "stage_status": "completed" }, + "shir_to_pyg": { "stage_id": "s2", "stage_status": "completed" }, + "semantic_leakage": { "stage_id": "s3", "stage_status": "blocked" }, + "chain_receipt": { "stage_id": "s4", "stage_status": "completed" } + }, + "artifacts": {}, + "job_status": "requires_review", + "policy_decision_ref": "policy-fabric://decision/pd-reject-review-missing-failure", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T16:00:00Z" +} diff --git a/tests/fixtures/shir-chain/reject.wrong-job-type.json b/tests/fixtures/shir-chain/reject.wrong-job-type.json new file mode 100644 index 0000000..d6072b1 --- /dev/null +++ b/tests/fixtures/shir-chain/reject.wrong-job-type.json @@ -0,0 +1,23 @@ +{ + "_reject_reason": "job_type must be shir.governed_chain.v0.1 (const violation)", + "kind": "SHIRGovernedChainJob", + "job_id": "shir-job:reject-wrong-type", + "job_type": "shir.governed_chain.v0.2", + "input_ref": "artifact://fabric-mlops-ts-suite/rdf/test.ttl", + "schema_ref": "semantic-serdes://schema/shir-v1/test", + "ontology_profile_ref": "ontogenesis://profile/shir/test", + "out_ref": "artifact://agentplane/shir-jobs/reject-wrong-type/output", + "policy_mode": "advisory", + "relation_strategy": "relation_node", + "stages": { + "rdf_to_shir": { "stage_id": "s1", "stage_status": "pending" }, + "shir_to_pyg": { "stage_id": "s2", "stage_status": "pending" }, + "semantic_leakage": { "stage_id": "s3", "stage_status": "pending" }, + "chain_receipt": { "stage_id": "s4", "stage_status": "pending" } + }, + "artifacts": {}, + "job_status": "running", + "policy_decision_ref": "policy-fabric://decision/pd-reject-wrong-type", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T16:00:00Z" +} diff --git a/tests/fixtures/shir-chain/valid.shir-chain-completed-toplvm.json b/tests/fixtures/shir-chain/valid.shir-chain-completed-toplvm.json new file mode 100644 index 0000000..f2ac2fc --- /dev/null +++ b/tests/fixtures/shir-chain/valid.shir-chain-completed-toplvm.json @@ -0,0 +1,86 @@ +{ + "kind": "SHIRGovernedChainJob", + "job_id": "shir-job:toplvm-clean-run-001", + "job_type": "shir.governed_chain.v0.1", + "input_ref": "artifact://fabric-mlops-ts-suite/rdf/toplvm-ontology.v1.ttl", + "input_format": "turtle", + "schema_ref": "semantic-serdes://schema/shir-v1/checkout-2024-01-15", + "ontology_profile_ref": "ontogenesis://profile/shir/toplvm-v1", + "out_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output", + "policy_mode": "advisory", + "relation_strategy": "relation_node", + "stages": { + "rdf_to_shir": { + "stage_id": "shir-job:toplvm-clean-run-001:rdf-to-shir", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/toplvm-clean-run-001/rdf-to-shir", + "artifact_refs": [ + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/shir-candidate.json", + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/shir-assertion.json" + ] + }, + "shir_to_pyg": { + "stage_id": "shir-job:toplvm-clean-run-001:shir-to-pyg", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/toplvm-clean-run-001/shir-to-pyg", + "artifact_refs": [ + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/pyg-manifest.json", + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/projection-manifest.json", + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/projection-loss-report.json" + ] + }, + "semantic_leakage": { + "stage_id": "shir-job:toplvm-clean-run-001:semantic-leakage", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/toplvm-clean-run-001/semantic-leakage", + "artifact_refs": [ + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/semantic-leakage-report.json", + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/semantic-leakage-projection-loss-report.json" + ] + }, + "chain_receipt": { + "stage_id": "shir-job:toplvm-clean-run-001:chain-receipt", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/toplvm-clean-run-001/chain", + "artifact_refs": [ + "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/chain-run-receipt.json" + ] + } + }, + "artifacts": { + "shir_candidate_assertion_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/shir-candidate.json", + "shir_assertion_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/shir-assertion.json", + "rdf_to_shir_receipt_ref": "receipt://shir/toplvm-clean-run-001/rdf-to-shir", + "pyg_manifest_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/pyg-manifest.json", + "projection_manifest_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/projection-manifest.json", + "projection_loss_report_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/projection-loss-report.json", + "shir_to_pyg_receipt_ref": "receipt://shir/toplvm-clean-run-001/shir-to-pyg", + "semantic_leakage_report_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/semantic-leakage-report.json", + "semantic_leakage_projection_loss_report_ref": "artifact://agentplane/shir-jobs/toplvm-clean-run-001/output/semantic-leakage-projection-loss-report.json", + "semantic_leakage_receipt_ref": "receipt://shir/toplvm-clean-run-001/semantic-leakage", + "chain_run_receipt_ref": "receipt://shir/toplvm-clean-run-001/chain" + }, + "failure_mode": "none", + "job_status": "completed", + "policy_outcome": "allowed", + "policy_decision_ref": "policy-fabric://decision/pd-shir-toplvm-clean-run-001", + "replay_artifact_ref": "replay://agentplane/shir-jobs/toplvm-clean-run-001", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/shir-chain/toplvm-clean-run-001" + ], + "upstream_anchors": [ + "prophet-platform-fabric-mlops-ts-suite#36", + "prophet-platform-fabric-mlops-ts-suite#37", + "prophet-platform-fabric-mlops-ts-suite#38", + "prophet-platform-fabric-mlops-ts-suite#39", + "prophet-platform-fabric-mlops-ts-suite#45", + "prophet-platform-fabric-mlops-ts-suite#46", + "agentplane#112" + ], + "non_claims": [ + "This job contract does not materialize tensors or run GNN training.", + "No ontology promotion occurs in v0.1.", + "PyTorch/PyG/DGL runtime is not required for this orchestration contract." + ], + "issued_at": "2024-01-15T16:00:00Z" +} diff --git a/tests/fixtures/shir-chain/valid.shir-chain-requires-review-leakage.json b/tests/fixtures/shir-chain/valid.shir-chain-requires-review-leakage.json new file mode 100644 index 0000000..c35b18f --- /dev/null +++ b/tests/fixtures/shir-chain/valid.shir-chain-requires-review-leakage.json @@ -0,0 +1,64 @@ +{ + "kind": "SHIRGovernedChainJob", + "job_id": "shir-job:leakage-review-002", + "job_type": "shir.governed_chain.v0.1", + "input_ref": "artifact://fabric-mlops-ts-suite/rdf/leaky-ontology.v1.ttl", + "input_format": "turtle", + "schema_ref": "semantic-serdes://schema/shir-v1/checkout-2024-01-15", + "ontology_profile_ref": "ontogenesis://profile/shir/leaky-v1", + "out_ref": "artifact://agentplane/shir-jobs/leakage-review-002/output", + "policy_mode": "review_required", + "relation_strategy": "relation_node", + "stages": { + "rdf_to_shir": { + "stage_id": "shir-job:leakage-review-002:rdf-to-shir", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/leakage-review-002/rdf-to-shir" + }, + "shir_to_pyg": { + "stage_id": "shir-job:leakage-review-002:shir-to-pyg", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/leakage-review-002/shir-to-pyg", + "artifact_refs": [ + "artifact://agentplane/shir-jobs/leakage-review-002/output/projection-loss-report.json" + ] + }, + "semantic_leakage": { + "stage_id": "shir-job:leakage-review-002:semantic-leakage", + "stage_status": "blocked", + "stage_receipt_ref": "receipt://shir/leakage-review-002/semantic-leakage", + "failure_reason": "Semantic leakage exceeds advisory threshold; review_required policy mode triggered.", + "artifact_refs": [ + "artifact://agentplane/shir-jobs/leakage-review-002/output/semantic-leakage-report.json" + ] + }, + "chain_receipt": { + "stage_id": "shir-job:leakage-review-002:chain-receipt", + "stage_status": "completed", + "stage_receipt_ref": "receipt://shir/leakage-review-002/chain" + } + }, + "artifacts": { + "rdf_to_shir_receipt_ref": "receipt://shir/leakage-review-002/rdf-to-shir", + "projection_loss_report_ref": "artifact://agentplane/shir-jobs/leakage-review-002/output/projection-loss-report.json", + "shir_to_pyg_receipt_ref": "receipt://shir/leakage-review-002/shir-to-pyg", + "semantic_leakage_report_ref": "artifact://agentplane/shir-jobs/leakage-review-002/output/semantic-leakage-report.json", + "semantic_leakage_receipt_ref": "receipt://shir/leakage-review-002/semantic-leakage", + "chain_run_receipt_ref": "receipt://shir/leakage-review-002/chain" + }, + "failure_mode": "semantic_leakage_blocking", + "failure_artifact_ref": "artifact://agentplane/shir-jobs/leakage-review-002/output/semantic-leakage-report.json", + "job_status": "requires_review", + "policy_outcome": "requires_review", + "policy_decision_ref": "policy-fabric://decision/pd-shir-leakage-review-002", + "upstream_anchors": [ + "prophet-platform-fabric-mlops-ts-suite#38", + "prophet-platform-fabric-mlops-ts-suite#45", + "agentplane#112" + ], + "non_claims": [ + "requires_review does not halt artifact retention; partial artifacts are preserved.", + "This job does not prescribe the review outcome." + ], + "issued_at": "2024-01-15T16:30:00Z" +} diff --git a/tools/validate_shir_governed_chain_job.py b/tools/validate_shir_governed_chain_job.py new file mode 100644 index 0000000..09947df --- /dev/null +++ b/tools/validate_shir_governed_chain_job.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "shir-governed-chain-job.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "shir-chain" + +REVIEW_STATUSES = {"requires_review", "failed_closed"} + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + status = data.get("job_status") + failure_mode = data.get("failure_mode") + policy_outcome = data.get("policy_outcome") + + # requires_review and failed_closed must declare failure_mode and policy_outcome + if status in REVIEW_STATUSES: + if not failure_mode: + problems.append(f"job_status={status} requires failure_mode") + if not policy_outcome: + problems.append(f"job_status={status} requires policy_outcome") + + # fail_closed policy_mode + semantic_leakage_blocking → failed_closed status + policy_mode = data.get("policy_mode") + if policy_mode == "fail_closed" and failure_mode == "semantic_leakage_blocking": + if status != "failed_closed": + problems.append("fail_closed policy_mode + semantic_leakage_blocking must set job_status=failed_closed") + + # completed job: chain_receipt stage must be completed + if status == "completed": + chain = data.get("stages", {}).get("chain_receipt", {}) + if chain.get("stage_status") != "completed": + problems.append("completed job requires chain_receipt stage_status=completed") + + # shir-to-pyg must emit projection_loss_report + artifacts = data.get("artifacts", {}) + stages = data.get("stages", {}) + shir_to_pyg = stages.get("shir_to_pyg", {}) + if shir_to_pyg.get("stage_status") == "completed": + if not artifacts.get("projection_loss_report_ref"): + # also check stage artifact_refs + stage_refs = shir_to_pyg.get("artifact_refs", []) + if not any("projection-loss" in r for r in stage_refs): + problems.append("shir_to_pyg completed stage requires projection_loss_report_ref in artifacts or stage artifact_refs") + + # non_claims required + if not data.get("non_claims"): + problems.append("non_claims must not be empty") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid shir-chain fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject shir-chain fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": SHIR governed chain job — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From d776cbf0000ec12ee8eb386dced5a8ae24096c35 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:04:34 -0400 Subject: [PATCH 7/9] feat(device-actuation): capability-scoped agent actuation boundary for device orchestration (#111) - DeviceActuationBoundaryReceipt schema: 14 action_class values (phone/home/browser/shell/device_generic + 8 high-risk: lock/alarm/camera/vehicle/payment/identity_token/health_relevant/os_mutation/irreversible_deletion), capability_class (low_risk/medium_risk/high_risk), 6 proposal_status values (proposed/denied/approved/executed/rolled_back/failed) - Conditional: high_risk + approved/executed requires approval_ref + approval_authority_ref - Policy gates: high-risk action_class forces capability_class=high_risk; denied requires denial_reason; rolled_back requires rollback_artifact_ref; high_risk proposed must not have policy_outcome=allow (no bypass from proposal to approval without explicit approval step) - 3 valid fixtures: low-risk browser (executed/allow), high-risk payment (denied), high-risk lock (approved+executed with approval refs) - 2 reject fixtures - validate-device-actuation-boundary wired into Makefile - Non-goals enforced: no direct ecosystem integration, no NL-to-actuation bypass path --- Makefile | 8 +- ...ctuation-boundary-receipt.schema.v0.1.json | 122 ++++++++++++++++++ ...gh-risk-approved-missing-approval-ref.json | 16 +++ .../device-actuation/reject.wrong-kind.json | 13 ++ .../valid.high-risk-lock-approved.json | 32 +++++ .../valid.high-risk-payment-denied.json | 31 +++++ ...valid.low-risk-browser-action-allowed.json | 30 +++++ tools/validate_device_actuation_boundary.py | 114 ++++++++++++++++ 8 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 schemas/device-actuation-boundary-receipt.schema.v0.1.json create mode 100644 tests/fixtures/device-actuation/reject.high-risk-approved-missing-approval-ref.json create mode 100644 tests/fixtures/device-actuation/reject.wrong-kind.json create mode 100644 tests/fixtures/device-actuation/valid.high-risk-lock-approved.json create mode 100644 tests/fixtures/device-actuation/valid.high-risk-payment-denied.json create mode 100644 tests/fixtures/device-actuation/valid.low-risk-browser-action-allowed.json create mode 100644 tools/validate_device_actuation_boundary.py diff --git a/Makefile b/Makefile index b9df980..ef147bf 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary python3 tools/validate_execution_timing.py validate-governance-context: @@ -269,6 +269,10 @@ validate-shir-governed-chain-job: python3 -m json.tool schemas/shir-governed-chain-job.schema.v0.1.json >/dev/null python3 tools/validate_shir_governed_chain_job.py +validate-device-actuation-boundary: + python3 -m json.tool schemas/device-actuation-boundary-receipt.schema.v0.1.json >/dev/null + python3 tools/validate_device_actuation_boundary.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/device-actuation-boundary-receipt.schema.v0.1.json b/schemas/device-actuation-boundary-receipt.schema.v0.1.json new file mode 100644 index 0000000..055359d --- /dev/null +++ b/schemas/device-actuation-boundary-receipt.schema.v0.1.json @@ -0,0 +1,122 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/device-actuation-boundary-receipt/v0.1", + "title": "DeviceActuationBoundaryReceipt", + "description": "AgentPlane evidence receipt enforcing the hard boundary between agent proposal and physical/digital device actuation. Agents propose; actuation requires capability class, policy decision, and explicit approval for high-risk actions. No bypass path from natural language to actuation.", + "type": "object", + "required": [ + "kind", + "receipt_id", + "action_proposal_id", + "action_class", + "capability_class", + "actuation_target", + "proposal_status", + "policy_decision_ref", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "DeviceActuationBoundaryReceipt" }, + "receipt_id": { "type": "string", "minLength": 1 }, + "action_proposal_id": { "type": "string", "minLength": 1 }, + "action_class": { + "type": "string", + "enum": [ + "phone", + "home", + "browser", + "shell", + "device_generic", + "lock", + "alarm", + "camera", + "vehicle", + "payment", + "identity_token", + "health_relevant", + "os_mutation", + "irreversible_deletion" + ] + }, + "capability_class": { + "type": "string", + "enum": ["low_risk", "medium_risk", "high_risk"], + "description": "low_risk: read/observe, no side effects; medium_risk: reversible write; high_risk: irreversible, safety-relevant, or authorization-escalating" + }, + "actuation_target": { + "type": "object", + "required": ["target_id", "target_type"], + "additionalProperties": false, + "properties": { + "target_id": { "type": "string", "minLength": 1 }, + "target_type": { "type": "string", "minLength": 1 }, + "target_description": { "type": "string" } + } + }, + "proposal_status": { + "type": "string", + "enum": ["proposed", "denied", "approved", "executed", "rolled_back", "failed"], + "description": "proposed: agent recommendation only; denied: policy or approval gate refused; approved: explicit approval received; executed: action completed; rolled_back: execution reversed; failed: execution attempted but failed" + }, + "approval_ref": { + "type": "string", + "description": "Required for high_risk actions when proposal_status=approved or executed" + }, + "approval_authority_ref": { + "type": "string", + "description": "Post or authority ref of the approver for high_risk actions" + }, + "delegated_authority_ref": { + "type": "string", + "description": "Narrow delegated authority ref, if applicable" + }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "policy_outcome": { + "type": "string", + "enum": ["allow", "allow_with_constraints", "deny", "escalate"] + }, + "denial_reason": { "type": "string" }, + "rollback_artifact_ref": { + "type": "string", + "description": "Required when proposal_status=rolled_back" + }, + "failure_artifact_ref": { + "type": "string", + "description": "Structured failure artifact when proposal_status=failed" + }, + "evidence_refs": { + "type": "array", + "items": { "type": "string" } + }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" } + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "if": { + "properties": { "capability_class": { "const": "high_risk" } }, + "required": ["capability_class"] + }, + "then": { + "if": { + "properties": { + "proposal_status": { "enum": ["approved", "executed"] } + } + }, + "then": { + "required": ["approval_ref", "approval_authority_ref"] + } + } +} diff --git a/tests/fixtures/device-actuation/reject.high-risk-approved-missing-approval-ref.json b/tests/fixtures/device-actuation/reject.high-risk-approved-missing-approval-ref.json new file mode 100644 index 0000000..3477bb3 --- /dev/null +++ b/tests/fixtures/device-actuation/reject.high-risk-approved-missing-approval-ref.json @@ -0,0 +1,16 @@ +{ + "_reject_reason": "high_risk + proposal_status=approved requires approval_ref + approval_authority_ref (conditional)", + "kind": "DeviceActuationBoundaryReceipt", + "receipt_id": "actuation-receipt:reject-high-risk-no-approval", + "action_proposal_id": "proposal:reject-high-risk-no-approval", + "action_class": "payment", + "capability_class": "high_risk", + "actuation_target": { + "target_id": "payment://account/savings/transfer", + "target_type": "payment_transfer" + }, + "proposal_status": "approved", + "policy_decision_ref": "policy-fabric://decision/pd-reject-high-risk-no-approval", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T14:00:00Z" +} diff --git a/tests/fixtures/device-actuation/reject.wrong-kind.json b/tests/fixtures/device-actuation/reject.wrong-kind.json new file mode 100644 index 0000000..6a5cc63 --- /dev/null +++ b/tests/fixtures/device-actuation/reject.wrong-kind.json @@ -0,0 +1,13 @@ +{ + "_reject_reason": "kind must be DeviceActuationBoundaryReceipt (const violation)", + "kind": "DeviceActuationReceipt", + "receipt_id": "actuation-receipt:reject-wrong-kind", + "action_proposal_id": "proposal:reject-wrong-kind", + "action_class": "browser", + "capability_class": "low_risk", + "actuation_target": { "target_id": "browser://tab", "target_type": "browser_tab" }, + "proposal_status": "proposed", + "policy_decision_ref": "policy-fabric://decision/pd-reject-wrong-kind", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T14:00:00Z" +} diff --git a/tests/fixtures/device-actuation/valid.high-risk-lock-approved.json b/tests/fixtures/device-actuation/valid.high-risk-lock-approved.json new file mode 100644 index 0000000..6b43a14 --- /dev/null +++ b/tests/fixtures/device-actuation/valid.high-risk-lock-approved.json @@ -0,0 +1,32 @@ +{ + "kind": "DeviceActuationBoundaryReceipt", + "receipt_id": "actuation-receipt:high-risk-lock-approved-003", + "action_proposal_id": "proposal:lock-front-door", + "action_class": "lock", + "capability_class": "high_risk", + "actuation_target": { + "target_id": "device://smart-lock/front-door/lock-001", + "target_type": "smart_lock", + "target_description": "Lock front door smart lock" + }, + "proposal_status": "executed", + "approval_ref": "approval://user/explicit-approval/lock-front-door-2024-01-15", + "approval_authority_ref": "user://owner/residence/primary", + "policy_decision_ref": "policy-fabric://decision/pd-lock-high-risk-approved-003", + "policy_outcome": "allow", + "evidence_refs": [ + "evidence://agentplane/device-actuation/high-risk-lock-approved-003" + ], + "hellgraph_evidence_refs": [ + "evidence://hellgraph/device-actuation/high-risk-lock-approved-003" + ], + "upstream_anchors": [ + "prophet-platform://strategy/sovereign-device-orchestration", + "agentplane#111" + ], + "non_claims": [ + "This receipt does not certify physical lock state; it records the actuation boundary decision only.", + "Approval is from the authorized residence owner; no delegation to subagent is implied." + ], + "issued_at": "2024-01-15T14:10:00Z" +} diff --git a/tests/fixtures/device-actuation/valid.high-risk-payment-denied.json b/tests/fixtures/device-actuation/valid.high-risk-payment-denied.json new file mode 100644 index 0000000..dee34ef --- /dev/null +++ b/tests/fixtures/device-actuation/valid.high-risk-payment-denied.json @@ -0,0 +1,31 @@ +{ + "kind": "DeviceActuationBoundaryReceipt", + "receipt_id": "actuation-receipt:high-risk-payment-denied-002", + "action_proposal_id": "proposal:payment-initiate-transfer", + "action_class": "payment", + "capability_class": "high_risk", + "actuation_target": { + "target_id": "payment://account/checking/transfer", + "target_type": "payment_transfer", + "target_description": "Initiate transfer from checking account" + }, + "proposal_status": "denied", + "policy_decision_ref": "policy-fabric://decision/pd-payment-high-risk-denied-002", + "policy_outcome": "deny", + "denial_reason": "High-risk payment action requires explicit human approval and narrow delegated authority. No approval_ref or approval_authority_ref present in this execution context.", + "evidence_refs": [ + "evidence://agentplane/device-actuation/high-risk-payment-denied-002" + ], + "hellgraph_evidence_refs": [ + "evidence://hellgraph/device-actuation/high-risk-payment-denied-002" + ], + "upstream_anchors": [ + "prophet-platform://strategy/sovereign-device-orchestration", + "agentplane#111" + ], + "non_claims": [ + "No payment was initiated. This receipt records a denied proposal only.", + "This receipt does not store account numbers, amounts, or payment credentials." + ], + "issued_at": "2024-01-15T14:05:00Z" +} diff --git a/tests/fixtures/device-actuation/valid.low-risk-browser-action-allowed.json b/tests/fixtures/device-actuation/valid.low-risk-browser-action-allowed.json new file mode 100644 index 0000000..8df693b --- /dev/null +++ b/tests/fixtures/device-actuation/valid.low-risk-browser-action-allowed.json @@ -0,0 +1,30 @@ +{ + "kind": "DeviceActuationBoundaryReceipt", + "receipt_id": "actuation-receipt:low-risk-browser-nav-001", + "action_proposal_id": "proposal:browser-navigate-search-results", + "action_class": "browser", + "capability_class": "low_risk", + "actuation_target": { + "target_id": "browser://tab/active", + "target_type": "browser_tab", + "target_description": "Navigate active tab to search results page" + }, + "proposal_status": "executed", + "policy_decision_ref": "policy-fabric://decision/pd-browser-nav-low-risk-001", + "policy_outcome": "allow", + "evidence_refs": [ + "evidence://agentplane/device-actuation/low-risk-browser-nav-001" + ], + "hellgraph_evidence_refs": [ + "evidence://hellgraph/device-actuation/low-risk-browser-nav-001" + ], + "upstream_anchors": [ + "prophet-platform://strategy/sovereign-device-orchestration", + "agentplane#111" + ], + "non_claims": [ + "This receipt does not represent direct browser DOM access or script injection.", + "Low-risk browser actions are bounded to read/navigate operations; no credential access." + ], + "issued_at": "2024-01-15T14:00:00Z" +} diff --git a/tools/validate_device_actuation_boundary.py b/tools/validate_device_actuation_boundary.py new file mode 100644 index 0000000..eca80b2 --- /dev/null +++ b/tools/validate_device_actuation_boundary.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "device-actuation-boundary-receipt.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "device-actuation" + +HIGH_RISK_CLASSES = { + "lock", "alarm", "camera", "vehicle", "payment", + "identity_token", "health_relevant", "os_mutation", "irreversible_deletion" +} + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + cap_class = data.get("capability_class") + action_class = data.get("action_class") + status = data.get("proposal_status") + + # high_risk action_class must always be capability_class=high_risk + if action_class in HIGH_RISK_CLASSES and cap_class != "high_risk": + problems.append(f"action_class={action_class} requires capability_class=high_risk") + + # high_risk + approved/executed requires approval_ref + approval_authority_ref + if cap_class == "high_risk" and status in ("approved", "executed"): + if not data.get("approval_ref"): + problems.append("high_risk approved/executed requires approval_ref") + if not data.get("approval_authority_ref"): + problems.append("high_risk approved/executed requires approval_authority_ref") + + # denied must have denial_reason + if status == "denied" and not data.get("denial_reason"): + problems.append("denied proposal_status requires denial_reason") + + # rolled_back requires rollback_artifact_ref + if status == "rolled_back" and not data.get("rollback_artifact_ref"): + problems.append("rolled_back requires rollback_artifact_ref") + + # no bypass: proposed status must not have policy_outcome=allow on high_risk + if status == "proposed" and cap_class == "high_risk" and data.get("policy_outcome") == "allow": + problems.append("high_risk proposed action must not have policy_outcome=allow; approval required first") + + # non_claims required + if not data.get("non_claims"): + problems.append("non_claims must not be empty") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid device-actuation fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject device-actuation fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": device actuation boundary — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From 9faa03c97843c612b9f495c00e799ee73b53e7c5 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:10:21 -0400 Subject: [PATCH 8/9] feat(reasoning): integrate SourceOS ReasoningRun contracts into AgentPlane evidence and replay (#109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ReasoningRunEvidenceReceipt schema: seals SourceOS ReasoningReceipt/ReplayPlan import into AgentPlane evidence lifecycle — run_id, sourceos_receipt_ref, replay_class (4 values: exact/ best-effort/evidence-only/non-replayable-side-effect preserved from ReasoningReplayPlan), safe_trace_posture (mode const=operational-trace-only, raw_private_reasoning const=not-collected), benchmark_passed (required for promotion), hellgraph_evidence_refs - Invariants enforced: raw_private_reasoning=not-collected (const); operational-trace-only mode; benchmark_passed=false blocks reasoning_status=completed - Authority boundaries preserved: cognition loop in Superconscious, schemas in sourceos-spec, evidence sealing and replay here in AgentPlane - 2 valid fixtures: deterministic M1 receipt (exact replay, m1-smoke), best-effort replay - 2 reject fixtures: raw_private_reasoning=collected (const violation), wrong kind - validate-reasoning-run-evidence wired into Makefile - Existing validate-superconscious-reasoning-import (import_superconscious_reasoning.py) unaffected --- Makefile | 8 +- ...ning-run-evidence-receipt.schema.v0.1.json | 95 ++++++++++++++++ ...eject.raw-private-reasoning-collected.json | 17 +++ .../reasoning-run/reject.wrong-kind.json | 17 +++ .../valid.best-effort-replay.json | 29 +++++ .../valid.deterministic-m1-receipt.json | 36 ++++++ tools/validate_reasoning_run_evidence.py | 106 ++++++++++++++++++ 7 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 schemas/reasoning-run-evidence-receipt.schema.v0.1.json create mode 100644 tests/fixtures/reasoning-run/reject.raw-private-reasoning-collected.json create mode 100644 tests/fixtures/reasoning-run/reject.wrong-kind.json create mode 100644 tests/fixtures/reasoning-run/valid.best-effort-replay.json create mode 100644 tests/fixtures/reasoning-run/valid.deterministic-m1-receipt.json create mode 100644 tools/validate_reasoning_run_evidence.py diff --git a/Makefile b/Makefile index ef147bf..1b03c67 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary validate-reasoning-run-evidence -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary validate-reasoning-run-evidence python3 tools/validate_execution_timing.py validate-governance-context: @@ -273,6 +273,10 @@ validate-device-actuation-boundary: python3 -m json.tool schemas/device-actuation-boundary-receipt.schema.v0.1.json >/dev/null python3 tools/validate_device_actuation_boundary.py +validate-reasoning-run-evidence: + python3 -m json.tool schemas/reasoning-run-evidence-receipt.schema.v0.1.json >/dev/null + python3 tools/validate_reasoning_run_evidence.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/reasoning-run-evidence-receipt.schema.v0.1.json b/schemas/reasoning-run-evidence-receipt.schema.v0.1.json new file mode 100644 index 0000000..3aef1e7 --- /dev/null +++ b/schemas/reasoning-run-evidence-receipt.schema.v0.1.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/reasoning-run-evidence-receipt/v0.1", + "title": "ReasoningRunEvidenceReceipt", + "description": "AgentPlane evidence receipt sealing a SourceOS ReasoningRun import. Translates ReasoningReceipt and ReasoningReplayPlan from sourceos-spec into AgentPlane evidence and replay lifecycle. AgentPlane owns evidence sealing and replay authority; cognition loop remains in Superconscious; schemas remain in sourceos-spec.", + "type": "object", + "required": [ + "kind", + "receipt_id", + "run_id", + "sourceos_receipt_ref", + "replay_class", + "safe_trace_posture", + "benchmark_passed", + "policy_decision_ref", + "hellgraph_evidence_refs", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "ReasoningRunEvidenceReceipt" }, + "receipt_id": { "type": "string", "minLength": 1 }, + "run_id": { + "type": "string", + "minLength": 1, + "description": "SourceOS ReasoningRun.id — must match sourceos_receipt_ref.runRef" + }, + "sourceos_receipt_ref": { "type": "string", "minLength": 1 }, + "sourceos_replay_plan_ref": { "type": "string" }, + "sourceos_benchmark_ref": { "type": "string" }, + "replay_class": { + "type": "string", + "enum": ["exact", "best-effort", "evidence-only", "non-replayable-side-effect"], + "description": "Preserved from ReasoningReplayPlan.replayClass. Governs AgentPlane replay semantics." + }, + "replay_artifact_ref": { + "type": "string", + "description": "AgentPlane replay artifact ref derived from ReasoningReplayPlan" + }, + "safe_trace_posture": { + "type": "object", + "required": ["mode", "raw_private_reasoning"], + "additionalProperties": false, + "properties": { + "mode": { + "type": "string", + "const": "operational-trace-only", + "description": "Must be operational-trace-only; raw private reasoning is never ingested" + }, + "raw_private_reasoning": { + "type": "string", + "const": "not-collected" + } + } + }, + "benchmark_passed": { + "type": "boolean", + "description": "Must be true for promotion. From ReasoningBenchmark.passed." + }, + "benchmark_suite": { "type": "string" }, + "event_count": { + "type": "integer", + "minimum": 0 + }, + "reasoning_status": { + "type": "string", + "enum": ["completed", "failed", "interrupted", "pending"] + }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "if": { + "properties": { "benchmark_passed": { "const": false } } + }, + "then": { + "properties": { + "reasoning_status": { "not": { "const": "completed" } } + } + } +} diff --git a/tests/fixtures/reasoning-run/reject.raw-private-reasoning-collected.json b/tests/fixtures/reasoning-run/reject.raw-private-reasoning-collected.json new file mode 100644 index 0000000..7290a98 --- /dev/null +++ b/tests/fixtures/reasoning-run/reject.raw-private-reasoning-collected.json @@ -0,0 +1,17 @@ +{ + "_reject_reason": "safe_trace_posture.raw_private_reasoning must be not-collected (const violation)", + "kind": "ReasoningRunEvidenceReceipt", + "receipt_id": "reasoning-evidence:reject-raw-reasoning", + "run_id": "urn:srcos:reasoning-run:reject", + "sourceos_receipt_ref": "urn:srcos:receipt:reasoning:reject", + "replay_class": "exact", + "safe_trace_posture": { + "mode": "operational-trace-only", + "raw_private_reasoning": "collected" + }, + "benchmark_passed": true, + "policy_decision_ref": "policy-fabric://decision/pd-reject-raw", + "hellgraph_evidence_refs": ["evidence://hellgraph/reject"], + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T17:00:00Z" +} diff --git a/tests/fixtures/reasoning-run/reject.wrong-kind.json b/tests/fixtures/reasoning-run/reject.wrong-kind.json new file mode 100644 index 0000000..2a1e9c6 --- /dev/null +++ b/tests/fixtures/reasoning-run/reject.wrong-kind.json @@ -0,0 +1,17 @@ +{ + "_reject_reason": "kind must be ReasoningRunEvidenceReceipt (const violation)", + "kind": "ReasoningEvidenceReceipt", + "receipt_id": "reasoning-evidence:reject-wrong-kind", + "run_id": "urn:srcos:reasoning-run:reject", + "sourceos_receipt_ref": "urn:srcos:receipt:reasoning:reject", + "replay_class": "exact", + "safe_trace_posture": { + "mode": "operational-trace-only", + "raw_private_reasoning": "not-collected" + }, + "benchmark_passed": true, + "policy_decision_ref": "policy-fabric://decision/pd-reject-wrong-kind", + "hellgraph_evidence_refs": ["evidence://hellgraph/reject"], + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T17:00:00Z" +} diff --git a/tests/fixtures/reasoning-run/valid.best-effort-replay.json b/tests/fixtures/reasoning-run/valid.best-effort-replay.json new file mode 100644 index 0000000..157d2bf --- /dev/null +++ b/tests/fixtures/reasoning-run/valid.best-effort-replay.json @@ -0,0 +1,29 @@ +{ + "kind": "ReasoningRunEvidenceReceipt", + "receipt_id": "reasoning-evidence:agentplane-best-effort-002", + "run_id": "urn:srcos:reasoning-run:agentplane-best-effort-fixture", + "sourceos_receipt_ref": "urn:srcos:receipt:reasoning:agentplane-best-effort-fixture", + "sourceos_replay_plan_ref": "urn:srcos:reasoning-replay-plan:agentplane-best-effort-fixture", + "replay_class": "best-effort", + "safe_trace_posture": { + "mode": "operational-trace-only", + "raw_private_reasoning": "not-collected" + }, + "benchmark_passed": true, + "benchmark_suite": "m1-best-effort-smoke", + "event_count": 5, + "reasoning_status": "completed", + "policy_decision_ref": "policy-fabric://decision/pd-reasoning-run-best-effort-002", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/reasoning-run/agentplane-best-effort-002" + ], + "upstream_anchors": [ + "sourceos-spec://contracts/ReasoningReplayPlan", + "agentplane#109" + ], + "non_claims": [ + "best-effort replay class means replay may not produce identical output; near-equivalent fidelity only.", + "This receipt does not certify replay parity; it records the replay class declared by sourceos-spec." + ], + "issued_at": "2024-01-15T17:10:00Z" +} diff --git a/tests/fixtures/reasoning-run/valid.deterministic-m1-receipt.json b/tests/fixtures/reasoning-run/valid.deterministic-m1-receipt.json new file mode 100644 index 0000000..b933161 --- /dev/null +++ b/tests/fixtures/reasoning-run/valid.deterministic-m1-receipt.json @@ -0,0 +1,36 @@ +{ + "kind": "ReasoningRunEvidenceReceipt", + "receipt_id": "reasoning-evidence:agentplane-m1-deterministic-001", + "run_id": "urn:srcos:reasoning-run:agentplane-fixture", + "sourceos_receipt_ref": "urn:srcos:receipt:reasoning:agentplane-fixture", + "sourceos_replay_plan_ref": "urn:srcos:reasoning-replay-plan:agentplane-fixture", + "sourceos_benchmark_ref": "urn:srcos:reasoning-benchmark:agentplane-fixture", + "replay_class": "exact", + "replay_artifact_ref": "replay://agentplane/reasoning-run/agentplane-m1-deterministic-001", + "safe_trace_posture": { + "mode": "operational-trace-only", + "raw_private_reasoning": "not-collected" + }, + "benchmark_passed": true, + "benchmark_suite": "m1-deterministic-smoke", + "event_count": 2, + "reasoning_status": "completed", + "policy_decision_ref": "policy-fabric://decision/pd-reasoning-run-m1-deterministic-001", + "hellgraph_evidence_refs": [ + "evidence://hellgraph/reasoning-run/agentplane-m1-deterministic-001", + "evidence://prophet-core/reasoning-run/agentplane-m1-deterministic-001" + ], + "upstream_anchors": [ + "superconscious://run/agentplane-fixture", + "sourceos-spec://contracts/ReasoningRun", + "sourceos-spec://contracts/ReasoningReceipt", + "sourceos-spec://contracts/ReasoningReplayPlan", + "agentplane#109" + ], + "non_claims": [ + "This receipt does not store raw private reasoning content; safe_trace_posture.raw_private_reasoning=not-collected.", + "AgentPlane does not own the cognition loop; this receipt seals the evidence handoff only.", + "AgentPlane does not own SourceOS canonical schemas; sourceos-spec remains the authority." + ], + "issued_at": "2024-01-15T17:00:00Z" +} diff --git a/tools/validate_reasoning_run_evidence.py b/tools/validate_reasoning_run_evidence.py new file mode 100644 index 0000000..96bb890 --- /dev/null +++ b/tools/validate_reasoning_run_evidence.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "reasoning-run-evidence-receipt.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "reasoning-run" + +VALID_REPLAY_CLASSES = {"exact", "best-effort", "evidence-only", "non-replayable-side-effect"} + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + posture = data.get("safe_trace_posture", {}) + if posture.get("raw_private_reasoning") != "not-collected": + problems.append("safe_trace_posture.raw_private_reasoning must be not-collected") + if posture.get("mode") != "operational-trace-only": + problems.append("safe_trace_posture.mode must be operational-trace-only") + + replay_class = data.get("replay_class") + if replay_class not in VALID_REPLAY_CLASSES: + problems.append(f"replay_class invalid: {replay_class}") + + # benchmark_passed=false must not have reasoning_status=completed + if data.get("benchmark_passed") is False and data.get("reasoning_status") == "completed": + problems.append("benchmark_passed=false must not have reasoning_status=completed") + + # hellgraph_evidence_refs required non-empty + if not data.get("hellgraph_evidence_refs"): + problems.append("hellgraph_evidence_refs must not be empty") + + # non_claims required + if not data.get("non_claims"): + problems.append("non_claims must not be empty") + + # run_id must be present + if not data.get("run_id"): + problems.append("run_id is required") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid reasoning-run fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject reasoning-run fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": reasoning run evidence — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From 21fee33153f56f4c2fc1d6ded626dcf3b29c0c4b Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Thu, 11 Jun 2026 21:13:30 -0400 Subject: [PATCH 9/9] feat(graph-dispatch): graph-aware dispatch and PR impact work orders (#106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GraphAwareWorkOrder schema: work_order_type (code_fix/documentation_update/policy_review/ pr_impact_review), RepoGraphContext (repo, commit_ref, changed_paths, affected_node_ids, affected_edge_ids, source_anchor_refs, required_tests/docs/policies, provenance_receipt_refs, policy_status, prophet_understand_artifact_ref, graph_artifact_staleness) - scope_warnings: missing_graph_artifact/stale_graph_artifact/unknown_affected_nodes/edges — stale or missing graph requires explicit warning rather than silent failure - CitationRequirements: must_cite_affected_nodes/edges/source_anchors, architectural_impact_claim_requires_graph_evidence (when true, output must cite graph evidence) - Policy gates: stale/missing staleness requires scope_warning; architectural impact claim with missing/unknown graph requires scope_warnings - 2 valid fixtures: code_fix with full graph context, pr_impact_review with stale graph + warnings - 1 reject fixture - validate-graph-aware-work-orders wired into Makefile - Non-goals enforced: AgentPlane does not own graph generation; graph facts ≠ mutation authority --- Makefile | 8 +- .../graph-aware-work-order.schema.v0.1.json | 132 ++++++++++++++++++ .../graph-aware/reject.wrong-kind.json | 13 ++ .../valid.code-fix-work-order.json | 62 ++++++++ .../valid.pr-impact-review-missing-graph.json | 37 +++++ tools/validate_graph_aware_work_orders.py | 98 +++++++++++++ 6 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 schemas/graph-aware-work-order.schema.v0.1.json create mode 100644 tests/fixtures/graph-aware/reject.wrong-kind.json create mode 100644 tests/fixtures/graph-aware/valid.code-fix-work-order.json create mode 100644 tests/fixtures/graph-aware/valid.pr-impact-review-missing-graph.json create mode 100644 tools/validate_graph_aware_work_orders.py diff --git a/Makefile b/Makefile index 1b03c67..729ea56 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary validate-reasoning-run-evidence +.PHONY: validate test validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary validate-reasoning-run-evidence validate-graph-aware-work-orders -validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary validate-reasoning-run-evidence +validate: validate-agent-cycle-health validate-authority-dependency-evidence validate-prometheus-sr validate-reasoning-failure-traces validate-governance-context validate-lattice-data-governai-execution-refs validate-lattice-runtime-profile-refs validate-network-native-assistant-evidence validate-guardrail-evidence-artifacts validate-stop-gate-evaluator validate-guarded-workcell-artifact validate-guarded-workcell-executor validate-guarded-invocation-artifact validate-guarded-invocation validate-agentic-pr-work-order validate-semantic-enterprise-agent-boundary validate-ops-history-contracts validate-action-contracts validate-agent-operation-contract validate-superconscious-reasoning-import validate-agent-harness-runtime-contracts validate-bounded-action-loop agentplane-evidence-receipt-composition-tier2-binding-ci lawful-learning-phase9-contract-ci validate-evidence-receipt-binding validate-semantic-activation-receipt validate-governed-run-contract validate-preflight-receipt validate-attempt-admission-receipt validate-verification-execution-receipt validate-synthetic-verification-receipt validate-governed-runner-v0-2-contract-chain validate-budget-settlement-receipt validate-rollback-receipts validate-run-dossier validate-governed-runner-readonly validate-workroom-context-evidence validate-wallguard-collaboration-admission validate-prophet-mesh-agentplane-adapter validate-civic-stack-runtime-evidence validate-conversational-evidence validate-concept-to-artifact-lineage validate-model-routing-lane-receipts validate-shir-governed-chain-job validate-device-actuation-boundary validate-reasoning-run-evidence validate-graph-aware-work-orders python3 tools/validate_execution_timing.py validate-governance-context: @@ -277,6 +277,10 @@ validate-reasoning-run-evidence: python3 -m json.tool schemas/reasoning-run-evidence-receipt.schema.v0.1.json >/dev/null python3 tools/validate_reasoning_run_evidence.py +validate-graph-aware-work-orders: + python3 -m json.tool schemas/graph-aware-work-order.schema.v0.1.json >/dev/null + python3 tools/validate_graph_aware_work_orders.py + validate-agent-cycle-health: python3 tools/validate_agent_cycle_health.py diff --git a/schemas/graph-aware-work-order.schema.v0.1.json b/schemas/graph-aware-work-order.schema.v0.1.json new file mode 100644 index 0000000..6edf951 --- /dev/null +++ b/schemas/graph-aware-work-order.schema.v0.1.json @@ -0,0 +1,132 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://socioprophet.io/schemas/agentplane/graph-aware-work-order/v0.1", + "title": "GraphAwareWorkOrder", + "description": "AgentPlane work order informed by Prophet Understand repo graph artifacts. Repo graph context informs scope; it does not grant mutation authority. PolicyFabric governs execution boundaries. Agent output must cite affected node/edge IDs and source anchors when available.", + "type": "object", + "required": [ + "kind", + "work_order_id", + "work_order_type", + "repo_graph_context", + "policy_decision_ref", + "non_claims", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "kind": { "type": "string", "const": "GraphAwareWorkOrder" }, + "work_order_id": { "type": "string", "minLength": 1 }, + "work_order_type": { + "type": "string", + "enum": ["code_fix", "documentation_update", "policy_review", "pr_impact_review"] + }, + "repo_graph_context": { "$ref": "#/$defs/RepoGraphContext" }, + "scope_warnings": { + "type": "array", + "items": { + "type": "object", + "required": ["warning_type", "message"], + "additionalProperties": false, + "properties": { + "warning_type": { + "type": "string", + "enum": ["missing_graph_artifact", "stale_graph_artifact", "unknown_affected_nodes", "unknown_affected_edges"] + }, + "message": { "type": "string", "minLength": 1 }, + "artifact_ref": { "type": "string" } + } + }, + "description": "Missing or stale graph artifacts are explicit warnings, not silent failures" + }, + "output_citation_requirements": { "$ref": "#/$defs/CitationRequirements" }, + "policy_decision_ref": { "type": "string", "minLength": 1 }, + "evidence_required_before_handoff": { + "type": "array", + "items": { "type": "string" }, + "description": "Evidence artifact kinds required before PR or execution handoff" + }, + "hellgraph_evidence_refs": { + "type": "array", + "items": { "type": "string" } + }, + "upstream_anchors": { + "type": "array", + "items": { "type": "string" } + }, + "non_claims": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "issued_at": { "type": "string", "format": "date-time" } + }, + "$defs": { + "RepoGraphContext": { + "type": "object", + "required": ["repo", "commit_ref"], + "additionalProperties": false, + "properties": { + "repo": { "type": "string", "minLength": 1 }, + "commit_ref": { "type": "string", "minLength": 1 }, + "changed_paths": { + "type": "array", + "items": { "type": "string" } + }, + "affected_node_ids": { + "type": "array", + "items": { "type": "string" } + }, + "affected_edge_ids": { + "type": "array", + "items": { "type": "string" } + }, + "source_anchor_refs": { + "type": "array", + "items": { "type": "string" } + }, + "required_tests": { + "type": "array", + "items": { "type": "string" } + }, + "required_docs": { + "type": "array", + "items": { "type": "string" } + }, + "required_policies": { + "type": "array", + "items": { "type": "string" } + }, + "provenance_receipt_refs": { + "type": "array", + "items": { "type": "string" } + }, + "policy_status": { + "type": "string", + "enum": ["compliant", "review_required", "blocked", "unknown"] + }, + "prophet_understand_artifact_ref": { + "type": "string", + "description": "Ref to the Prophet Understand repo intelligence artifact" + }, + "graph_artifact_staleness": { + "type": "string", + "enum": ["current", "stale", "missing", "unknown"] + } + } + }, + "CitationRequirements": { + "type": "object", + "additionalProperties": false, + "properties": { + "must_cite_affected_nodes": { "type": "boolean" }, + "must_cite_affected_edges": { "type": "boolean" }, + "must_cite_source_anchors": { "type": "boolean" }, + "architectural_impact_claim_requires_graph_evidence": { + "type": "boolean", + "description": "When true, any claim of architectural impact in agent output requires graph evidence" + } + } + } + } +} diff --git a/tests/fixtures/graph-aware/reject.wrong-kind.json b/tests/fixtures/graph-aware/reject.wrong-kind.json new file mode 100644 index 0000000..9c2eb39 --- /dev/null +++ b/tests/fixtures/graph-aware/reject.wrong-kind.json @@ -0,0 +1,13 @@ +{ + "_reject_reason": "kind must be GraphAwareWorkOrder (const violation)", + "kind": "GraphWorkOrder", + "work_order_id": "work-order:reject-wrong-kind", + "work_order_type": "code_fix", + "repo_graph_context": { + "repo": "SocioProphet/agentplane", + "commit_ref": "sha:a1b2c3d4" + }, + "policy_decision_ref": "policy-fabric://decision/pd-reject", + "non_claims": ["placeholder"], + "issued_at": "2024-01-15T09:00:00Z" +} diff --git a/tests/fixtures/graph-aware/valid.code-fix-work-order.json b/tests/fixtures/graph-aware/valid.code-fix-work-order.json new file mode 100644 index 0000000..34d607c --- /dev/null +++ b/tests/fixtures/graph-aware/valid.code-fix-work-order.json @@ -0,0 +1,62 @@ +{ + "kind": "GraphAwareWorkOrder", + "work_order_id": "work-order:code-fix-auth-middleware-001", + "work_order_type": "code_fix", + "repo_graph_context": { + "repo": "SocioProphet/prophet-platform", + "commit_ref": "sha:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0", + "changed_paths": [ + "src/auth/middleware.ts", + "tests/auth/middleware.test.ts" + ], + "affected_node_ids": [ + "node://prophet-platform/auth/AuthMiddleware", + "node://prophet-platform/auth/SessionHandler" + ], + "affected_edge_ids": [ + "edge://prophet-platform/auth/AuthMiddleware->SessionHandler/depends" + ], + "source_anchor_refs": [ + "source://prophet-platform/src/auth/middleware.ts#L42-L78" + ], + "required_tests": [ + "tests/auth/middleware.test.ts" + ], + "required_docs": [ + "docs/auth/session-token-storage.md" + ], + "required_policies": [ + "policy-fabric://policy/session-token-compliance" + ], + "provenance_receipt_refs": [ + "provenance://agentplane/code-fix/auth-middleware-001" + ], + "policy_status": "review_required", + "prophet_understand_artifact_ref": "prophet-understand://artifact/prophet-platform/auth/impact-a1b2", + "graph_artifact_staleness": "current" + }, + "output_citation_requirements": { + "must_cite_affected_nodes": true, + "must_cite_affected_edges": true, + "must_cite_source_anchors": true, + "architectural_impact_claim_requires_graph_evidence": true + }, + "policy_decision_ref": "policy-fabric://decision/pd-graph-work-order-code-fix-001", + "evidence_required_before_handoff": [ + "GovernedRunContract", + "ModelRoutingLaneDecisionReceipt" + ], + "hellgraph_evidence_refs": [ + "evidence://hellgraph/graph-aware/code-fix-auth-middleware-001" + ], + "upstream_anchors": [ + "prophet-platform#407", + "agentplane#106" + ], + "non_claims": [ + "Graph context informs scope; it does not grant mutation authority.", + "Inferred graph facts are not mutation authority; PolicyFabric governs execution.", + "This work order does not claim to represent the full repo dependency graph." + ], + "issued_at": "2024-01-15T09:00:00Z" +} diff --git a/tests/fixtures/graph-aware/valid.pr-impact-review-missing-graph.json b/tests/fixtures/graph-aware/valid.pr-impact-review-missing-graph.json new file mode 100644 index 0000000..ad92c5b --- /dev/null +++ b/tests/fixtures/graph-aware/valid.pr-impact-review-missing-graph.json @@ -0,0 +1,37 @@ +{ + "kind": "GraphAwareWorkOrder", + "work_order_id": "work-order:pr-impact-review-stale-graph-002", + "work_order_type": "pr_impact_review", + "repo_graph_context": { + "repo": "SocioProphet/agentplane", + "commit_ref": "sha:b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1", + "changed_paths": ["schemas/bounded-action-loop.v0.schema.json"], + "affected_node_ids": [], + "affected_edge_ids": [], + "policy_status": "unknown", + "graph_artifact_staleness": "stale" + }, + "scope_warnings": [ + { + "warning_type": "stale_graph_artifact", + "message": "Prophet Understand graph artifact is stale; affected node/edge IDs may be incomplete.", + "artifact_ref": "prophet-understand://artifact/agentplane/schemas/stale-impact-b2c3" + }, + { + "warning_type": "unknown_affected_nodes", + "message": "Affected nodes could not be resolved from stale graph; citation requirements relaxed but must be noted in output." + } + ], + "output_citation_requirements": { + "must_cite_affected_nodes": false, + "must_cite_affected_edges": false, + "must_cite_source_anchors": true, + "architectural_impact_claim_requires_graph_evidence": true + }, + "policy_decision_ref": "policy-fabric://decision/pd-graph-work-order-pr-impact-002", + "non_claims": [ + "Stale graph artifact means affected node/edge coverage is incomplete; output must not claim full architectural coverage.", + "Unknown policy_status means this work order cannot claim compliance; human review required." + ], + "issued_at": "2024-01-15T09:15:00Z" +} diff --git a/tools/validate_graph_aware_work_orders.py b/tools/validate_graph_aware_work_orders.py new file mode 100644 index 0000000..21562fd --- /dev/null +++ b/tools/validate_graph_aware_work_orders.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import jsonschema +except ImportError as exc: + raise SystemExit("jsonschema is required: python3 -m pip install jsonschema") from exc + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "graph-aware-work-order.schema.v0.1.json" +FIXTURES = ROOT / "tests" / "fixtures" / "graph-aware" + + +def load_json(path: Path) -> dict[str, Any]: + data = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError("root must be object") + return data + + +def check_policy_gates(data: dict[str, Any]) -> list[str]: + problems: list[str] = [] + + ctx = data.get("repo_graph_context", {}) + staleness = ctx.get("graph_artifact_staleness") + scope_warnings = data.get("scope_warnings", []) + + # stale or missing graph artifact must have a scope_warning + if staleness in ("stale", "missing"): + warning_types = {w.get("warning_type") for w in scope_warnings} + if not (warning_types & {"stale_graph_artifact", "missing_graph_artifact"}): + problems.append(f"graph_artifact_staleness={staleness} requires a corresponding scope_warning") + + # architectural_impact_claim_requires_graph_evidence=true but graph is missing/stale → must have warning + cite = data.get("output_citation_requirements", {}) + if cite.get("architectural_impact_claim_requires_graph_evidence") and staleness in ("missing", "unknown"): + if not scope_warnings: + problems.append("architectural_impact_claim_requires_graph_evidence=true with missing/unknown graph requires scope_warnings") + + # non_claims required + if not data.get("non_claims"): + problems.append("non_claims must not be empty") + + return problems + + +def validate_file(path: Path, schema: dict[str, Any]) -> list[str]: + try: + data = load_json(path) + except Exception as exc: + return [f"parse error: {exc}"] + try: + jsonschema.validate(data, schema) + except jsonschema.ValidationError as exc: + return [f"schema: {exc.message}"] + return check_policy_gates(data) + + +def main() -> int: + schema = load_json(SCHEMA) + failed = False + + valids = sorted(FIXTURES.glob("valid.*.json")) + if not valids: + raise SystemExit("missing valid graph-aware fixtures") + + for path in valids: + problems = validate_file(path, schema) + if problems: + print(f"FAIL (valid): {path.name}") + for p in problems: + print(f" - {p}") + failed = True + else: + print(f"ok: {path.name}") + + rejects = sorted(FIXTURES.glob("reject.*.json")) + if not rejects: + raise SystemExit("missing reject graph-aware fixtures") + + for path in rejects: + problems = validate_file(path, schema) + if not problems: + print(f"FAIL (reject should have failed): {path.name}") + failed = True + else: + print(f"ok (rejected as expected): {path.name}") + + print(("PASS" if not failed else "FAIL") + f": graph-aware work orders — {len(valids)} valid, {len(rejects)} reject") + return 0 if not failed else 1 + + +if __name__ == "__main__": + raise SystemExit(main())