Skip to content
Open
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
75 changes: 75 additions & 0 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,81 @@ jobs:
retention-days: 7
if-no-files-found: ignore

# ── Stage 3d : M8 Canvas-authored provenance pre-flight ──────────
# M8 (ADR Pulsar-002 + Orion-001) authors a multi-blueprint Canvas+Blue
# scene, pushes it through the REAL Orion compile, drives the active
# scene, mints a viewer show-token, and PROVES the on-air Solar frame is
# that authoring (round-trip active_scene_id + modal-colour). This job
# runs the PROVENANCE PRE-FLIGHT only (--preflight-only via run-m8.ps1):
# it needs a reachable deployed stack (VPS via tunnel, Orion in dual mode
# serving Solar v0.2.0) + a short-TTL operator JWT, so it is GATED on the
# M8 secrets being present and is non-blocking when they are absent
# (the full broadcast leg + the VPS bring-up are a separate, serialised
# run Probe/Keeper drive — ADR §A1.7). Mirrors the M6 job: typed skip
# (exit 3) on a LIGHT build, fail (1) on any assertion, pass (0) only on
# a confirmed provenance pre-flight. The wrapper grep-asserts no
# credential leaks (criterion 7) regardless of probe exit.
m8-provenance:
name: M8 Canvas-authored provenance pre-flight
needs: build
runs-on: windows-2022
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Download pulsar-rundir
uses: actions/download-artifact@v4
with:
name: pulsar-rundir
path: .

- name: Setup Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install probe deps
shell: bash
run: |
python -m pip install --upgrade pip
pip install websockets

- name: Run M8 provenance pre-flight (grep-asserted wrapper)
# The wrapper tees stdout, runs the probe in --preflight-only, then
# FAILS the run if any credential leaks to stdout / PNG / VOD —
# redaction is a gate here, not a nicety (Bastion PV-1/CC-1).
# Skip cleanly when the M8 secrets aren't configured on this repo.
env:
M8_OPERATOR_TOKEN: ${{ secrets.M8_OPERATOR_TOKEN }}
M8_GATEWAY_URL: ${{ secrets.M8_GATEWAY_URL }}
shell: pwsh
run: |
if (-not $env:M8_OPERATOR_TOKEN -or -not $env:M8_GATEWAY_URL) {
Write-Host "::notice::M8 secrets (M8_OPERATOR_TOKEN / M8_GATEWAY_URL) not configured — skipping the provenance pre-flight (non-blocking; the real run is the serialised VPS go-live driven by Probe/Keeper)."
exit 0
}
pwsh scripts/run-m8.ps1 -PreflightOnly -ShowStreamPath stream.lsdp -SolarVersion 0.2.0 -PythonExe python
$rc = $LASTEXITCODE
if ($rc -eq 3) {
Write-Host "::notice::M8 typed skip (exit 3) — LIGHT build without CEF. Needs scripts/build-win.ps1 -Full."
exit 0
}
exit $rc

- name: Upload M8 provenance proof PNG
if: always()
uses: actions/upload-artifact@v4
with:
name: pulsar-m8-provenance-proof
path: |
build/m8-canvas-scene.png
build/m8-probe-stdout.log
retention-days: 30
if-no-files-found: ignore

# ── Stage 4 : publish proof MP4 to gh-pages ──────────────────────
publish-gh-pages:
name: publish proof to gh-pages
Expand Down
54 changes: 54 additions & 0 deletions scripts/fixtures/m8-blueprint-score.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"_fixture": "M8 score blueprint (Pulsar #45). A pure, bounded compute graph: two core.literal@1 constants (40 + 2) feed a core.math.add@1, whose result is written to the core.output@1 sink leaf `value`. Bound in the scene under blueprint key `score` -> leaf path `score.value` (40 + 2 = 42, the deterministic 'M8 OK 42' marker). Every node is is_pure/is_bounded in Blue's stdlib manifest, so Orion's compiler accepts it by construction (no IMPURE_COMPUTE / COMPILE_FAILED). Field names mirror Blue's graph schema (src/blue/schemas/graph.py) which Orion's FetchBlueprint reads two-call: GET /blueprints/{id} -> current_version, GET /blueprints/{id}/versions/{n} -> graph.{nodes,edges}.",
"blueprint": {
"slug": "pulsar-m8-score",
"name": "Pulsar M8 — score",
"kind": "function",
"tags": ["pulsar-m8", "fixture"],
"interface": {
"inputs": [],
"outputs": [
{ "name": "value", "type": "core.primitive.number" }
],
"side_effects": []
}
},
"graph": {
"nodes": [
{
"id": "lit.a",
"definition": "core.literal@1",
"config": { "value": 40 },
"outputs": [{ "id": "lit.a.out", "name": "out", "type": "core.primitive.number" }]
},
{
"id": "lit.b",
"definition": "core.literal@1",
"config": { "value": 2 },
"outputs": [{ "id": "lit.b.out", "name": "out", "type": "core.primitive.number" }]
},
{
"id": "add",
"definition": "core.math.add@1",
"config": {},
"inputs": [
{ "id": "add.x", "name": "x", "type": "core.primitive.number" },
{ "id": "add.y", "name": "y", "type": "core.primitive.number" }
],
"outputs": [{ "id": "add.out", "name": "out", "type": "core.primitive.number" }]
},
{
"id": "out.value",
"definition": "core.output@1",
"config": { "name": "value" },
"inputs": [{ "id": "out.value.in", "name": "in", "type": "core.primitive.number" }]
}
],
"edges": [
{ "id": "e.a", "from_node": "lit.a", "from_port": "out", "to_node": "add", "to_port": "x" },
{ "id": "e.b", "from_node": "lit.b", "from_port": "out", "to_node": "add", "to_port": "y" },
{ "id": "e.out", "from_node": "add", "from_port": "out", "to_node": "out.value", "to_port": "in" }
],
"variables": []
}
}
36 changes: 36 additions & 0 deletions scripts/fixtures/m8-blueprint-timer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"_fixture": "M8 timer blueprint (Pulsar #45). The SECOND, DISTINCT Blue blueprint that makes the M8 scene a genuine N>=2 multi-blueprint scene (ADR Orion-001 / ADR Pulsar-002 A1.3). A single pure core.literal@1 constant feeds a core.output@1 sink leaf `value`. Bound under blueprint key `timer` -> leaf path `timer.value`. Distinct blueprint id + distinct scene-local key from `score`, both declaring leaf `value`: without the <key>. prefix the two would collide; with it they split into score.value / timer.value (ADR Orion-001 §3.3). Pure/bounded by construction.",
"blueprint": {
"slug": "pulsar-m8-timer",
"name": "Pulsar M8 — timer",
"kind": "function",
"tags": ["pulsar-m8", "fixture"],
"interface": {
"inputs": [],
"outputs": [
{ "name": "value", "type": "core.primitive.string" }
],
"side_effects": []
}
},
"graph": {
"nodes": [
{
"id": "lit.t",
"definition": "core.literal@1",
"config": { "value": "12:00" },
"outputs": [{ "id": "lit.t.out", "name": "out", "type": "core.primitive.string" }]
},
{
"id": "out.value",
"definition": "core.output@1",
"config": { "name": "value" },
"inputs": [{ "id": "out.value.in", "name": "in", "type": "core.primitive.string" }]
}
],
"edges": [
{ "id": "e.t", "from_node": "lit.t", "from_port": "out", "to_node": "out.value", "to_port": "in" }
],
"variables": []
}
}
44 changes: 44 additions & 0 deletions scripts/fixtures/m8-scene.lsml.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"lsml": "1.1",
"scene_id": "0c8a9e57-0000-4000-8000-000000000m80",
"scene_version": "sha256:c2e52819d3f465b8228a23f764249b8c86d06f1d5887e68bcaba47bc3dac59c7",
"layout": {
"kind": "frame",
"id": "root",
"size": { "w": 1920, "h": 1080 },
"background": "#1A9E57",
"children": [
{
"kind": "stack",
"id": "col",
"direction": "vertical",
"gap": 24,
"align": "center",
"justify": "center",
"children": [
{
"kind": "text",
"id": "score-label",
"style": { "fontSize": 96, "fontWeight": 800, "color": "#FFFFFF", "textAlign": "center", "fontFamily": "Inter" },
"bind": { "value": "score.value" }
},
{
"kind": "text",
"id": "timer-label",
"style": { "fontSize": 48, "fontWeight": 600, "color": "#0A0A0A", "textAlign": "center", "fontFamily": "Inter" },
"bind": { "value": "timer.value" }
},
{
"kind": "shape",
"id": "chip",
"geometry": "rect",
"size": { "w": 320, "h": 96 },
"fill": "#0AF0C8",
"cornerRadius": 16,
"stroke": { "color": "#0A0A0A", "width": 3 }
}
]
}
]
}
}
Loading
Loading