Cory Policht
← All references
REF · IP-SCP-45-11-CHANNEL-PRESENCE-MODEL · IP

Ip Scp 45 11 Channel Presence Model

source: Spatial-Cognition-Platform/Epic-S32-Coherence-Board-And-Channel-Presence/IP-SCP-45.11-Channel-Presence-Model.mdscrubbed extract

Scrubbed extract of Spatial-Cognition-Platform/Epic-S32-Coherence-Board-And-Channel-Presence/IP-SCP-45.11-Channel-Presence-Model.md — cited by the Chronicle (07-the-long-march). Redactions: phone / service detail / secrets / clearance / personal / internal hosts.


type: implementation-plan category: Work project: Spatial-Cognition-Platform priority: High status: review pr: 514 created: ‘2026-09-21’ epic: Epic-S32-Coherence-Board-And-Channel-Presence user-story: IP-SCP-45.11 effort: null points: 1 sizing: repos: 1 files: 2 reads: 3 read_files: 3 deliverables: 5 seams: 1 target_repo: spatial-cognition-xr precedence:

  • ‘[[../Epic-S27-Control-Room-Scene-And-Substrate/IP-SCP-40.11-Universal-State-Grammar-Contract]]’ seams: [channel-presence-contract] parallel_group: lane-core review-profile: standard model: null tokens: 0 verification_class: B verification_rung: R1 needs_unity: false execution_lane: L1-headless stage: ‘3’ tags:
  • implementation-plan
  • control-room
  • channel-presence

IP-SCP-45.11: Channel Presence Model

Epic: [[README|Epic S32]] · Stage: 3 · Gate: B/R1 · Points: 1

Mission

Engine-free channel-presence model: per-session etch state — where the session was born and which channel is watching it now, from the five spec channels (browser, editor, chat, hook, headset) mapped over the ADR-003 source enum with the shipped XR member (FR-AIS-007) and the resolver channel on trust_gate.resolved; a door-pip presence set for Zone F with a pulse flag while a remote channel is actively resolving; and the advisory handoff reducer — a 400 ms pinch-hold on the handoff verb (wrist strip or Critical slab) issues a deep-link handoff (FR-AIS-025 token, accepted by OUI via FR-OUI-005), the object shows “held by remote” until the first reconciled resolve event returns it, taking it back is the same verb, and an undeliverable link springs the verb back. No lock is modelled anywhere — both channels may act and the first reconciled event wins; presence unknown greys, never guesses.

Why

Card 18’s value — “the headset is one of several honest surfaces” — is entirely a projection-and-reducer question before it is ever a shader question; the etch glyphs, pip pulses and springback in 45.21 can only render what this model decides, and the sound pair (whoosh out / tick back) is emitted here as data.

Sizing

Declared table estimate: 1 point; 2 source files (tests/generated artifacts excluded), three concrete bootstrap reads, 5 acceptance boxes, one coherent channel-presence-contract boundary. Re-score after concrete file census; do not inflate scope to consume points.

Context Bootstrap

  1. C:\Users\coryp\Developer\spatial-cognition-xr\unity\SpatialCognition\Assets\Scp\Core\Scp.App\CommandArmingMachine.cs — the hold-window reducer precedent for the 400 ms pinch-hold detector.
  2. C:\Users\coryp\Developer\spatial-cognition-xr\unity\SpatialCognition\Assets\Scp\Core\Scp.App\Demo\DemoStageLayout.cs — shape reference for the Zone F pip-cluster placement row the ControlRoom profile carries (IP-SCP-40.15 owns the table).
  3. C:\Users\coryp\Developer\obsidian-sync\Projects\Spatial-Cognition-Platform\Guide-Control-Room-Layout-Constants.md — Zone E/F anchoring, exclusion-volume rule keeping pips out of the doorway volume.

Gate Policy

Trigger Gate type Condition
Ambiguity / missing contract Confidence Resolve from the epic binding contracts; record remaining uncertainty rather than invent behavior.
Scope exceeds declared size Confidence Re-score concrete files/seams; above 3 points requires decomposition before expansion.
Failing or missing verification artifact Trust No acceptance or status promotion; exit code alone is insufficient.
Core asmdef gains an engine reference Trust Stop work — no UnityEngine under Assets/Scp/Core/** (ADR-SCP-010).
Any edit to AgentOps scene/kits/prefabs/Blender families Trust Refuse; this IP touches engine-free source only.
A figure not in the spec (pip spacing, pulse rate) Confidence Mark tunable; resolve in the gym.
Budget rows from the manifest Perf Replication rides existing session deltas — no new polling loop; the 400 ms hold window is the spec’s.

Deliverables

  • ChannelPresence.cs (per-session etch: born-channel + watching-channel over the five spec channels plus unknown/grey; pip set with per-entry remote-resolving pulse flag) and ChannelHandoffReducer.cs under Scp.Projection/Scp.App — no Unity types, deterministic 1/72 s steps.
  • 400 ms pinch-hold detector: a hold shorter than the window never issues; exactly the window (spec value, pinned once) issues the deep-link handoff; release-after-springback can re-issue (no latch).
  • Advisory-race tests with inverted proofs: two resolve events from different channels → the first reconciled one wins and the second is absorbed silently; no state anywhere in the model expresses “locked”.
  • Springback: undeliverable-link input returns the verb to idle and leaves the slab object untouched; foreign-born sessions carry their origin etch and XR never overwrites it.
  • Cue data: reducer emits whoosh on departure toward the door pip and tick on return — staleness-adjacent silence is 45.10’s rule, not duplicated here; independent tests red-first, dotnet test Scp.Core.sln green on the stage PR.

Execution Phases

Worktree feat/IP-SCP-45.11-channel-presence-model from BASE (post-Wave-1 main); red test commit then feat commit, PR, review; cloud lane (L1-headless) per frontmatter. Standard TDD/review per [[ADR-017-Human-Review-Branching-And-TDD-Workflow|ADR-017]].

Verification and evidence

  • R1 (CI): ci.yml run 15862, SHA 23d62a5 — green.

  • R2-batchmode: n/a — needs_unity: false / R1-only (L1-headless); no Editor launched, no scene/kit/prefab/.inputactions in the diff.

  • Inverted proofs: 19 proof-named tests; the InvertedProof_ prefix is this unit’s convention, and the count matches the implementer’s own report exactly. Names grepped from this unit’s own test files at its documented head:

    • ChannelHandoffReducerTests.InvertedProof_APressTargetingAnUnknownChannelIsRejectedRatherThanGuessed — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_AnUnattributableResolveGreysTheWatcherRatherThanGuessingWeb — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_BothChannelsMayActOnTheSameSessionWithoutRefusal — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_EquivalentStepSequencesProduceIdenticalStates — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_HoldShorterThanTheWindowNeverIssues — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_NoStateAnywhereExpressesLocked — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_NonMonotonicTicksAndRateChangesAreRejected — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_PresenceCuesCarryNoStalenessOrFrostVocabulary — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_ReleaseBeforeTheWindowAbandonsTheHandoff — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_SecondPressWhileHeldByRemoteDoesNotStackASecondIssue — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_TheWindowIsPinnedToTheSpecValueAndCeilsAtSeventyTwoHertz — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_TwoResolveEventsFromDifferentChannelsFirstReconciledWinsAndSecondIsAbsorbedSilently — guard: (not characterised; read the named test)
    • ChannelHandoffReducerTests.InvertedProof_XrNeverOverwritesAForeignBornEtch — guard: (not characterised; read the named test)
    • ChannelPresenceTests.InvertedProof_AbsentOrUnrecognizedSourceGreysInsteadOfDefaultingToWeb — guard: (not characterised; read the named test)
    • ChannelPresenceTests.InvertedProof_KnownPresenceContributesNoLifecycleStateToTheGrammar — guard: (not characterised; read the named test)
    • ChannelPresenceTests.InvertedProof_PipPulsesOnlyWhileARemoteResolveIsPending — guard: (not characterised; read the named test)
    • ChannelPresenceTests.InvertedProof_PresenceSurfaceIsEngineFree — guard: (not characterised; read the named test)
    • ChannelPresenceTests.InvertedProof_TheHeadsetPipNeverPulsesBecauseTheHeadsetIsNotRemote — guard: (not characterised; read the named test)
    • ChannelPresenceTests.InvertedProof_ThePipSetHasNoGreyEntryToGuessWith — guard: (not characterised; read the named test)
  • Local R2-MCP / R3 / R4: n/a — no Unity, no headset, no device (ADR-SCP-015 §3 unchanged).

  • [[README#Binding contracts|Epic S32 binding contracts]] — mandatory on this dispatch.
  • [[../Feature-Requests/SCFR-028-channel-presence-and-cross-surface-handoff|SCFR-028]] — the source proposal.
  • [[../Prompt-Control-Room-Asset-Build|Control Room asset-build prompt]] · [[../Guide-Asset-Pipeline-Process|asset pipeline guide]] · [[IP-Sizing-Rubric]].
  • Provider reads: FR-AIS-007 (source: XR, done), FR-AIS-025, FR-OUI-005 (AI-Service-Implementation / ADP-Orchestration-UI Interface-Requests/).
  • Forward: [[../Epic-S27-Control-Room-Scene-And-Substrate/IP-SCP-40.11-Universal-State-Grammar-Contract|IP-SCP-40.11]] — declared predecessor; [[IP-SCP-45.21-Channel-Etch-And-Door-Pips-View|IP-SCP-45.21]] — first consumer of channel-presence-contract.