Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .github/workflows/run-replay-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ on:
- "docs/sociosphere-bridge.md"
- "schemas/run-artifact.schema.v0.1.json"
- "schemas/replay-artifact.schema.v0.1.json"
- "schemas/bundle.schema.v0.1.json"
- "scripts/emit_run_artifact.py"
- "scripts/emit_replay_artifact.py"
- "scripts/validate_bundle.py"
- "tests/test_sourceos_binding_projection.py"
- "tests/test_chronos_carrier_bridge.py"
- "examples/run-replay/**"
- ".github/workflows/run-replay-artifacts.yml"
push:
Expand All @@ -17,8 +21,12 @@ on:
- "docs/sociosphere-bridge.md"
- "schemas/run-artifact.schema.v0.1.json"
- "schemas/replay-artifact.schema.v0.1.json"
- "schemas/bundle.schema.v0.1.json"
- "scripts/emit_run_artifact.py"
- "scripts/emit_replay_artifact.py"
- "scripts/validate_bundle.py"
- "tests/test_sourceos_binding_projection.py"
- "tests/test_chronos_carrier_bridge.py"
- "examples/run-replay/**"
- ".github/workflows/run-replay-artifacts.yml"
workflow_dispatch:
Expand All @@ -38,11 +46,30 @@ jobs:
run: |
python3 -m json.tool schemas/run-artifact.schema.v0.1.json >/dev/null
python3 -m json.tool schemas/replay-artifact.schema.v0.1.json >/dev/null
python3 -m py_compile scripts/emit_run_artifact.py scripts/emit_replay_artifact.py
python3 -m json.tool schemas/bundle.schema.v0.1.json >/dev/null
python3 -m py_compile scripts/emit_run_artifact.py scripts/emit_replay_artifact.py scripts/validate_bundle.py
- name: Bridge binding/carrier projection unit tests
run: |
python3 -m unittest tests.test_sourceos_binding_projection tests.test_chronos_carrier_bridge -v
- name: Emit synthetic run and replay artifacts
run: |
rm -rf /tmp/agentplane-run-replay-fixture
python3 scripts/emit_run_artifact.py examples/run-replay/minimal-bundle.json qemu 0 --stdout artifact:stdout --stderr artifact:stderr
python3 scripts/emit_replay_artifact.py examples/run-replay/minimal-bundle.json qemu --bundle-rev synthetic-rev --bundle-path examples/run-replay/minimal-bundle.json
python3 -m json.tool /tmp/agentplane-run-replay-fixture/run-artifact.json >/dev/null
python3 -m json.tool /tmp/agentplane-run-replay-fixture/replay-artifact.json >/dev/null
- name: Emit synthetic run and replay artifacts carrying a CHRONOS carrier
run: |
rm -rf /tmp/agentplane-run-replay-fixture-chronos-carrier
python3 scripts/emit_run_artifact.py examples/run-replay/minimal-bundle-with-chronos-carrier.json qemu 0 --stdout artifact:stdout --stderr artifact:stderr
python3 scripts/emit_replay_artifact.py examples/run-replay/minimal-bundle-with-chronos-carrier.json qemu --bundle-rev synthetic-rev --bundle-path examples/run-replay/minimal-bundle-with-chronos-carrier.json
python3 -m json.tool /tmp/agentplane-run-replay-fixture-chronos-carrier/run-artifact.json >/dev/null
python3 -m json.tool /tmp/agentplane-run-replay-fixture-chronos-carrier/replay-artifact.json >/dev/null
python3 - <<'PY'
import json
run = json.load(open('/tmp/agentplane-run-replay-fixture-chronos-carrier/run-artifact.json'))
replay = json.load(open('/tmp/agentplane-run-replay-fixture-chronos-carrier/replay-artifact.json'))
assert run['chronosCarrier']['methodFamily'] == 'neurasp-adjudication', run
assert replay['inputs']['chronosCarrier']['methodFamily'] == 'neurasp-adjudication', replay
print('chronosCarrier passthrough OK')
PY
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ validate-wallguard-collaboration-admission:

test:
python3 -m pytest -q tools/tests

.PHONY: validate-workspace-prophet-control-receipt validate-prophet-mesh-agentplane-adapter
validate-workspace-prophet-control-receipt:
python3 tools/validate_workspace_prophet_control_receipt.py
Expand Down Expand Up @@ -401,3 +402,12 @@ validate: validate-composition-promotion-gate
.PHONY: validate-composition-promotion-gate
validate-composition-promotion-gate:
python3 tools/validate_composition_promotion_gate.py

# --- CHRONOS carrier passthrough (sociosphere-bridge additive extension, issue #329) ---
validate: validate-chronos-carrier-bridge
.PHONY: validate-chronos-carrier-bridge
validate-chronos-carrier-bridge:
python3 -m json.tool schemas/run-artifact.schema.v0.1.json >/dev/null
python3 -m json.tool schemas/replay-artifact.schema.v0.1.json >/dev/null
python3 -m json.tool schemas/bundle.schema.v0.1.json >/dev/null
python3 -m unittest tests.test_sourceos_binding_projection tests.test_chronos_carrier_bridge -v
44 changes: 44 additions & 0 deletions docs/sociosphere-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,47 @@ These are references only. `agentplane` must not rescan the workspace to redisco
## Non-goals
- `agentplane` is not the source of truth for repo inventory or lock drift.
- `sociosphere` is not the source of truth for executor placement or runtime replay artifacts.

## CHRONOS carrier passthrough (additive)

This bridge also accepts a second carried-object type: CHRONOS neuro-symbolic
carrier objects (per `sociosphere/docs/integration/neurosymbolic-chronos-alignment.md`).
This is the same seam widened to a second shape, not a second bridge — it reuses
the existing transport (declared refs on the `Bundle` spec, projected by the same
extraction functions that already project SourceOS bindings) and the same
consuming artifacts (`ValidationArtifact`, `RunArtifact`, `ReplayArtifact`).

A `Bundle` may optionally declare `spec.chronosCarrier`:

| Field | Meaning |
|---|---|
| `sourceEvidenceRef` | Reference to the upstream evidence the carrier grounds on |
| `methodFamily` | CHRONOS-owned method-family tag (e.g. NeurASP-style, dILP-style) |
| `claimStatus` | CHRONOS-owned claim status for the carrier |
| `validationStatus` | CHRONOS-owned validation status for the carrier |
| `nonAuthorityDeclaration` | Must be `true`: an explicit declaration that `agentplane` does not assert canonical authority over this carrier |
| `owningPlane` | The plane that owns this carrier's canonical definition (must not be `agentplane`) |
| `replayRef` | Reference agentplane can fold into its own `ReplayArtifact` |

`scripts/validate_bundle.py` fail-closes (like the existing SourceOS
image-production gate) when `spec.chronosCarrier` is declared but incomplete,
when `nonAuthorityDeclaration` is not `true`, or when `owningPlane` is
`agentplane` — i.e. an improperly-authorized carrier (one that omits or denies
its non-authority declaration, or that tries to route canonical ownership
through `agentplane`) is rejected at the bridge, the same way a malformed
SourceOS binding is rejected today.

`scripts/emit_run_artifact.py` and `scripts/emit_replay_artifact.py` project
whatever `chronosCarrier` fields are present into `RunArtifact.chronosCarrier`
and `ReplayArtifact.inputs.chronosCarrier` respectively, exactly as they already
do for `sourceosBindings`.

### Non-goals (CHRONOS carrier passthrough)
- `agentplane` does not take on carrier-schema or method-family taxonomy
authority — `methodFamily`, `claimStatus`, and `validationStatus` values are
passed through, not interpreted or enumerated here.
- This is a structural completeness/non-authority gate only, not cryptographic
attestation or full authority/delegation reconstruction (see
`docs/replay-boundary.md`).
- No canonical-schema authority moves into `sociosphere` or `agentplane`; it
stays with Ontogenesis / `sourceos-spec` per CHRONOS's own definitions.
35 changes: 35 additions & 0 deletions examples/run-replay/minimal-bundle-with-chronos-carrier.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"metadata": {
"name": "minimal-run-replay-fixture-chronos-carrier",
"version": "0.1.0"
},
"spec": {
"artifacts": {
"outDir": "/tmp/agentplane-run-replay-fixture-chronos-carrier"
},
"policy": {
"lane": "staging",
"policyPackRef": "policy-pack:synthetic-run-replay",
"policyPackHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111"
},
"vm": {
"backendIntent": "qemu"
},
"secrets": {
"required": []
},
"chronosCarrier": {
"sourceEvidenceRef": "urn:chronos:evidence:neurasp-adjudication-0007",
"methodFamily": "neurasp-adjudication",
"claimStatus": "proposed",
"validationStatus": "unvalidated",
"nonAuthorityDeclaration": true,
"owningPlane": "ontogenesis",
"replayRef": "urn:chronos:replay:neurasp-adjudication-0007"
},
"governanceContext": {
"fixture": "run-replay-artifact-validation-chronos-carrier",
"nonProductionOnly": true
}
}
}
27 changes: 27 additions & 0 deletions schemas/bundle.schema.v0.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,33 @@
},
"type": "object"
},
"chronosCarrier": {
"description": "Optional CHRONOS neuro-symbolic carrier passthrough (additive bridge extension; agentplane does not own this taxonomy -- see docs/sociosphere-bridge.md).",
"properties": {
"sourceEvidenceRef": {
"type": "string"
},
"methodFamily": {
"type": "string"
},
"claimStatus": {
"type": "string"
},
"validationStatus": {
"type": "string"
},
"nonAuthorityDeclaration": {
"type": "boolean"
},
"owningPlane": {
"type": "string"
},
"replayRef": {
"type": "string"
}
},
"type": "object"
},
"agentMachine": {
"description": "Optional SourceOS Agent Machine binding for local Mac/Windows/Linux Podman workspaces and cluster-local TopoLVM placement.",
"properties": {
Expand Down
5 changes: 5 additions & 0 deletions schemas/replay-artifact.schema.v0.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
"sourceosImageProduction": {
"type": "object",
"additionalProperties": true
},
"chronosCarrier": {
"description": "CHRONOS neuro-symbolic carrier passthrough fields projected from Bundle.spec.chronosCarrier when present (additive bridge extension; see docs/sociosphere-bridge.md).",
"type": "object",
"additionalProperties": true
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions schemas/run-artifact.schema.v0.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
"sourceosImageProduction": {
"type": "object",
"additionalProperties": true
},
"chronosCarrier": {
"description": "CHRONOS neuro-symbolic carrier passthrough fields projected from Bundle.spec.chronosCarrier when present (additive bridge extension; see docs/sociosphere-bridge.md).",
"type": "object",
"additionalProperties": true
}
}
}
30 changes: 30 additions & 0 deletions scripts/emit_replay_artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@
"smokeReceiptRef": "AGENTPLANE_SOURCEOS_SMOKE_RECEIPT_REF",
}

# CHRONOS neuro-symbolic carrier passthrough (additive to this bridge; see
# docs/sociosphere-bridge.md "CHRONOS carrier passthrough"). This is a
# permissive projection -- the fail-closed structural gate lives in
# scripts/validate_bundle.py, which runs upstream of this script.
CHRONOS_CARRIER_KEYS = (
"sourceEvidenceRef",
"methodFamily",
"claimStatus",
"validationStatus",
"nonAuthorityDeclaration",
"owningPlane",
"replayRef",
)


def die(msg: str, code: int = 2) -> None:
print(f"[replay-artifact] ERROR: {msg}", file=sys.stderr)
Expand Down Expand Up @@ -174,6 +188,21 @@ def extract_sourceos_image_production(spec: dict[str, Any]) -> dict[str, Any]:
}


def extract_chronos_carrier(spec: dict[str, Any]) -> dict[str, Any]:
"""Project a declared CHRONOS carrier's fields, if present.

Permissive by design: the fail-closed structural gate (required fields,
non-authority declaration, owning-plane check) lives in
scripts/validate_bundle.py and runs before this script does. This function
only records whatever was declared, the same way extract_sourceos_bindings
records whatever SourceOS binding was declared.
"""
carrier = spec.get("chronosCarrier") if isinstance(spec.get("chronosCarrier"), dict) else {}
if not carrier:
return {}
return _copy_non_empty(carrier, CHRONOS_CARRIER_KEYS)


def main() -> int:
ap = argparse.ArgumentParser(prog="emit_replay_artifact")
ap.add_argument("bundle", help="path to bundle.json")
Expand Down Expand Up @@ -225,6 +254,7 @@ def main() -> int:
"upstreamArtifacts": upstream,
"sourceosBindings": extract_sourceos_bindings(spec),
"sourceosImageProduction": extract_sourceos_image_production(spec),
"chronosCarrier": extract_chronos_carrier(spec),
}
if governance_context is not None:
inputs["governanceContext"] = governance_context
Expand Down
30 changes: 30 additions & 0 deletions scripts/emit_run_artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@
"smokeReceiptRef": "AGENTPLANE_SOURCEOS_SMOKE_RECEIPT_REF",
}

# CHRONOS neuro-symbolic carrier passthrough (additive to this bridge; see
# docs/sociosphere-bridge.md "CHRONOS carrier passthrough"). This is a
# permissive projection -- the fail-closed structural gate lives in
# scripts/validate_bundle.py, which runs upstream of this script.
CHRONOS_CARRIER_KEYS = (
"sourceEvidenceRef",
"methodFamily",
"claimStatus",
"validationStatus",
"nonAuthorityDeclaration",
"owningPlane",
"replayRef",
)


def die(msg: str, code: int = 2) -> None:
print(f"[run-artifact] ERROR: {msg}", file=sys.stderr)
Expand Down Expand Up @@ -183,6 +197,21 @@ def extract_sourceos_image_production(spec: dict[str, Any]) -> dict[str, Any]:
}


def extract_chronos_carrier(spec: dict[str, Any]) -> dict[str, Any]:
"""Project a declared CHRONOS carrier's fields, if present.

Permissive by design: the fail-closed structural gate (required fields,
non-authority declaration, owning-plane check) lives in
scripts/validate_bundle.py and runs before this script does. This function
only records whatever was declared, the same way extract_sourceos_bindings
records whatever SourceOS binding was declared.
"""
carrier = spec.get("chronosCarrier") if isinstance(spec.get("chronosCarrier"), dict) else {}
if not carrier:
return {}
return _copy_non_empty(carrier, CHRONOS_CARRIER_KEYS)


def main() -> int:
ap = argparse.ArgumentParser(prog="emit_run_artifact")
ap.add_argument("bundle", help="path to bundle.json")
Expand Down Expand Up @@ -241,6 +270,7 @@ def main() -> int:
"upstreamArtifacts": upstream,
"sourceosBindings": extract_sourceos_bindings(spec),
"sourceosImageProduction": extract_sourceos_image_production(spec),
"chronosCarrier": extract_chronos_carrier(spec),
}

if governance_context is not None:
Expand Down
Loading
Loading