feat(m8): Canvas-authored multi-blueprint live probe + provenance (LSDP)#52
Open
ClodoCapeo wants to merge 5 commits into
Open
feat(m8): Canvas-authored multi-blueprint live probe + provenance (LSDP)#52ClodoCapeo wants to merge 5 commits into
ClodoCapeo wants to merge 5 commits into
Conversation
Checked-in fixtures for the M8 Canvas-authored live test: two distinct,
pure Blue blueprints (score: literal+literal -> math.add -> output leaf
`value`; timer: literal -> output leaf `value`) and a rich multi-component
LSML 1.1 scene bundle. The scene binds both blueprints by scene-local key
via hand-prefixed bindings (`bind:{value:"score.value"}` / `"timer.value"`,
ADR Orion-001 §3.3), over a full-frame solid background of a known unusual
colour (#1A9E57) that the pre-flight modal-colour provenance check ties the
on-air pixels to. The bundle carries its own content-address scene_version
(sha256:c2e528...) computed the same way lumencast-go/lsml.HashBundle does,
so Canvas's A0 store address-check passes and /layouts/{H} resolves.
N >= 2 distinct blueprint ids + distinct keys; computes are core.* pure so
Orion's compile is clean by construction (no IMPURE_COMPUTE/COMPILE_FAILED).
Refs #44 #45
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
probe-m8-canvas-live.py authors a multi-blueprint Canvas+Blue scene, pushes it through the real Orion compile, drives the active-scene (M8 is the FIRST real driver of POST /orion/api/v1/show/active-scene), mints a fresh viewer show-token, and runs the proven M6 pre-flight + broadcast core against the Solar v0.2.0 LSDP URL it composed itself — then PROVES the on-air frame is that authoring. SETUP leg (m8_setup.py, gateway-first HTTP, stdlib-only): - ensure N Blue blueprints (idempotent by slug, published) - PUT the LSML bundle to Canvas A0, save + push (lsml_bundle_hash=H) - active-scene + round-trip GET /show (active_scene_id == scene_id) - mint show-token, compose Solar v0.2.0 LSDP URL (broadcast-url.ts parity) Provenance: (3) server-side round-trip active_scene_id == scene_id + the captured push scene_version, and (1) the captured CEF frame's modal colour ≈ the authored background (#1A9E57) — binds server state to pixels. Blank / wrong-colour => NO GO (no broadcast). Reuses M6's CEF spawn/reap, PNG decode, analyse_frame, RTMP metrics + bounded StartDestination retry by importing probe-m6-live.py; extends the non-blank predicate with the modal-colour assertion. Security (Bastion PV-1/CC-1): zero token committed (no baked-JWT DEFAULT_SOLAR_URL — the M6 trap); redactSolarUrl ported to Python and applied to every solar_url line; operator JWT is M8_OPERATOR_TOKEN (short-TTL admin, étage-1) and is hard-refused if equal to ORION_OPERATOR_TOKEN; run-m8.ps1 grep-asserts no credential leaks to stdout/PNG/VOD and fails the run on a leak regardless of probe exit. A gated, non-blocking CI job mirrors the M6 shape (typed skip exit 3). Wire = LSDP by default (--show-stream-path stream.lsdp), bespoke `stream` kept as a supported fallback. Refs #44 #46 #47 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Override m6.LIVE_VOD_DIR / PROOF_PNG / BUILD_DIR / DESTINATION_NAME before spawn so the reused broadcast core writes the M8 proof PNG, VOD, and uses an M8-specific Twitch destination name (clean teardown, no M6/M8 artefact collision). PulsarProcess.spawn reads LIVE_VOD_DIR for PULSAR_RECORD_DIR, so the override must precede spawn — it now does. Refs #46 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…broadcast Vigil request-changes: the M8 docstring claimed the broadcast leg reused the bounded anti-boot-race StartDestination retry, but m6.broadcast (reused verbatim by M8) did a single-shot StartDestination. The post-scene-switch boot race was observed flaking in CI, so make the claim true by adding the robustness, not by softening the doc. Factor start_destination_with_retry() into probe-m6-live.py (the shared broadcast core M8 imports), ported verbatim from probe-twitch-live.py's START_DEST_* pattern: budget 20s, cadence 1s, retry ONLY on the exact transient 'frontend streaming output unavailable' error, hard-fail on any other error or on an exhausted budget, zero masking. m6.broadcast now goes live through it, so the M8 broadcast path inherits the retry with no fork of the broadcast loop. Correct the M8 docstring + the broadcast comment to describe what is actually wired, and fix the truncated grep-assert comment in run-m8.ps1 (cosmetic). Redaction / grep-assert / provenance / legs left untouched. Refs #46 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The S7 provenance round-trip (get_show) called GET /orion/api/v1/show with auth=False. On the public gateway (zabgate.cyell.dev) this endpoint is operator-gated: 401 without a Bearer, 200 with the operator Bearer (verified by Keeper). So S7 raised SetupError(401) before pre-flight and the SETUP never reached broadcast. Flip get_show to auth=True so it rides the operator JWT like every other SETUP leg; expect=(200,) unchanged. Audited all SETUP legs: S5 push and S6 active-scene are operator-gated mutations and already auth=True (the _request default); the LSDP WS URL keeps the viewer show-token in ?token= and never carries the operator Bearer. S7 was the only leg with the bug. Refs #45 #46 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M8 — end-to-end live test driven by a Canvas-authored (+Blue) scene
Implements Pulsar #44 (rich fixture) + #45 (Blue blueprints) + #46 (probe) + #47 (redaction) per ADR Pulsar-002 (M8) + ADR Orion-001 (multi-blueprint envelope). The on-air frame is a scene this test authors — layout by ZabCanvas, logic by N≥2 distinct Blue blueprints, compiled by Orion, rendered by Solar v0.2.0 over the LSDP wire in Pulsar's CEF, broadcast by Pulsar — and is proven to be that authoring.
What's here
scripts/fixtures/m8-blueprint-{score,timer}.json— two distinct, pure Blue blueprints (core.literal@1/core.math.add@1/core.output@1), each writing leafvalue; bound under distinct scene-local keysscore/timer.scripts/fixtures/m8-scene.lsml.json— deterministic rich LSML 1.1 scene: full-frame#1A9E57background (provenance marker), two bound text labels (bind:{value:"score.value"}/"timer.value"— hand-prefixed per ADR Orion-001 §3.3), a shape. Carries its ownscene_versioncontent-address (computed the same waylumencast-go/lsml.HashBundledoes).scripts/m8_setup.py— gateway-first SETUP leg: ensure blueprints → PUT bundle to Canvas A0 → save+push (lsml_bundle_hash=H) → drive active-scene (M8 is its first real driver) → round-tripGET /show→ mint viewer show-token → compose Solar v0.2.0 LSDP URL (broadcast-url.ts::getSolarSceneUrlparity).scripts/probe-m8-canvas-live.py— orchestrator; reuses the proven M6 broadcast core (probe-m6-live.py: CEF spawn/reap, PNG decode,analyse_frame, RTMP metrics, boundedStartDestinationretry) and extends the non-blank pre-flight with the modal-colour provenance assertion.scripts/run-m8.ps1— wrapper with a hard grep-assert: fails the run if any credential leaks to stdout/PNG/VOD, regardless of probe exit.pipeline.yml— gated, non-blockingm8-provenanceCI job mirroring the M6 shape (typed skip exit 3 on LIGHT build).How provenance is proven
GET /orion/api/v1/show⇒active_scene_id == scene_id; the push responsescene_versionis captured + reported.#1A9E57within tolerance. Blank / wrong-colour / fallback ⇒ NO GO (no broadcast), typed diagnosis.This PR touches tokens / secrets / network surface (show-token mint, operator JWT, Solar URL, Twitch key). Mitigations in place: zero token committed (no baked-JWT
DEFAULT_SOLAR_URL— the M6 trap),redactSolarUrlported to Python and applied to everysolar_urlline, operator JWT isM8_OPERATOR_TOKEN(short-TTL admin, étage-1) and hard-refused if equal toORION_OPERATOR_TOKEN, grep-assert gate.detect-secrets+ manual scan clean on all new files.Not run here (separate validation step — Probe / Keeper)
The real go-live is not run by this PR (the stack is mid PG rotation; the broadcast leg needs the deployed VPS + Twitch key + the étage-1 operator token). Validated locally:
py_compilegreen on all modules, pure-helper asserts (hash determinism, redaction parity, URL composition, fixture validity) pass, config-error/CC-1 guard paths return exit 2, YAML valid, secret scans clean.Refs #44 #45 #46 #47
🤖 Generated with Claude Code