feat patch companion-phase-4 feat/companion-app #8 / 15
aaronrene · 2 days ago · Jun 6, 2026 · Diff

feat(companion-phase-4): runtime manager decision core — pure lifecycle, integrity, backpressure, resource limits

Phase 4 of the Companion App build plan (feat/companion-app). Scope: pure-then-bind — NO runtime spawned, NO download performed, NO socket bound.

## Deliverables

lib/companion-runtime-manager.mjs — pure, I/O-free decision core: - Supply-chain integrity: SHA-256 + size verification with constant-time digest comparison (hash-of-hash via crypto.timingSafeEqual); source allowlist + HTTPS-only enforcement at spec-validation time; createIntegrityAccumulator (streaming) and verifyModelBytes (in-memory); fail-closed on any ambiguous spec field. - Lifecycle state machine: stopped→starting→ready→draining→stopped; canServeInference returns true ONLY for ready state; invalid transitions fail-closed; pure (no mutation). - Backpressure/concurrency admission: maxInFlight + queueBound hard caps; evaluateAdmission returns at_capacity/queue_full; recordInFlight/recordCompletion pure state advancement; evaluateRuntimeRequest is the single gate. - Resource-limit policy: RAM/VRAM/CPU ceilings; evaluateResourceLimits; injected ResourceObservation from Phase 5 adapter.statResources(). - Top-level gate (evaluateRuntimeRequest): lifecycle → admission → resource in order; never throws on any input; no secret/path/URL in any reason string. - RuntimeAdapterFns typedef: spawn/download/healthCheck/statResources — no vault, canister, JWT, or keychain in the adapter interface (ambient authority boundary).

test/companion-runtime-manager-*.test.mjs — 7-tier suite (219 cases, all green): unit(84) integration(20) e2e(7) stress(12) data-integrity(47) performance(11) security(38) Security tier covers: wrong/missing digest rejects before execution; 1-bit corruption detected; oversized download rejected; HTTP source banned structurally; foreign source rejected; empty allowlist fail-closed; lifecycle gate blocks all non-ready states; backpressure trips at exact bound (100 in-flight, 1000-request flood blocked); RAM/VRAM/CPU over-limit rejected; no ambient authority in exports; verdict shape is { ok, reason } only; no secret/URL/digest in any reason string; constant-time comparison timing-ratio bound; global fail-closed posture (null on any input → deny, no throw).

docs/COMPANION-APP-PHASE-4-RUNTIME-MANAGER.md — accepted design, module contract, adversarial threat note (supply-chain/resource exhaustion/ambient authority), integrity/backpressure/lifecycle rules, Phase 5 bind-gate obligations, remaining blockers to Phase 5 (G1: OAuth gate, G2: Phase 5 bind-gate design), recommended order.

Gate compliance: - No bundled runtime shipped (gate DOES NOT approve list). - No new local HTTP listener bound. - No binary/installer/auto-updater. - Phase 1 seam: companionAvailable flips true only after real health-check (Phase 5). - Owner policy: no docs-only PR to main.

Refs: docs/COMPANION-APP-DESIGN-AND-AUTHORIZATION-GATE.md §7/§10/§12 phase 4 docs/COMPANION-APP-PHASE-1-ADAPTER-SEAM.md (companionAvailable seam) docs/COMPANION-APP-PHASE-2-LOOPBACK-SECURITY.md (ambient authority boundary) docs/COMPANION-APP-PHASE-3-OAUTH-PKCE.md (pure-then-bind discipline)

sha256:3c71452a68bfee676b1e54695a6d54acb254b3271bb2b31f727090f9618d3f27 sha
+81 symbols
sha256:f74312917c7b982c8a28aed3840a72425e92f29bff2b869fbaee54b212a53745 snapshot
+81
symbols added
0
dead code introduced
Semantic Changes 81 symbols
+ Companion App — Phase 4: Bundled Runtime Manager (Decision Core) section Companion App — Phase 4: Bundled Runtime Manager (Decision Core) L1–363
+ Adversarial / threat note section 1. Adversarial / threat note L33–68
+ (a) SUPPLY-CHAIN — tampered/poisoned model file section (a) SUPPLY-CHAIN — tampered/poisoned model file L35–46
+ (b) RESOURCE EXHAUSTION — inference flood → OOM section (b) RESOURCE EXHAUSTION — inference flood → OOM L46–56
+ (c) AMBIENT AUTHORITY — runtime must never reach vault/canister/JWT section (c) AMBIENT AUTHORITY — runtime must never reach vault/canister/JWT L56–68
+ mjs section 2. Module contract — lib/companion-runtime-manager.mjs L68–207
+ 1 Design constraints (security invariants) section 2.1 Design constraints (security invariants) L70–78
+ 10 Injected adapter interface (RuntimeAdapterFns) section 2.10 Injected adapter interface (RuntimeAdapterFns) L190–207
+ code[js] variable variable code[js] L194–202
+ 2 RUNTIME_MANAGER_REASONS section 2.2 RUNTIME_MANAGER_REASONS L78–95
+ code variable variable code L82–94
+ 3 Supply-chain integrity — createIntegrityAccumulator (streaming) section 2.3 Supply-chain integrity — createIntegrityAccumulator (streaming) L95–109
+ code[js] variable variable code[js] L98–102
+ 4 Supply-chain integrity — verifyModelBytes (in-memory) section 2.4 Supply-chain integrity — verifyModelBytes (in-memory) L109–119
+ code[js] variable variable code[js] L112–116
+ 5 Source validation section 2.5 Source validation L119–125
+ 6 Lifecycle state machine section 2.6 Lifecycle state machine L125–147
+ code variable variable code L130–137
+ 7 Backpressure / concurrency admission section 2.7 Backpressure / concurrency admission L147–163
+ code variable variable code L150–153
+ 8 Resource-limit policy section 2.8 Resource-limit policy L163–175
+ code variable variable code L166–170
+ 9 Top-level admission gate — evaluateRuntimeRequest section 2.9 Top-level admission gate — evaluateRuntimeRequest L175–190
+ code[js] variable variable code[js] L178–182
+ Lifecycle/integrity interaction — the single path to ready section 3. Lifecycle/integrity interaction — the single path to ready L207–251
+ code variable variable code L209–246
+ Backpressure and resource enforcement rules section 4. Backpressure and resource enforcement rules L251–271
+ Backpressure section Backpressure L253–263
+ table section table L255–260
+ Resource limits section Resource limits L263–271
+ What Phase 5 must do to bind the runtime safely section 5. What Phase 5 must do to bind the runtime safely L271–319
+ 1 Model download and integrity (supply-chain gate) section 5.1 Model download and integrity (supply-chain gate) L275–282
+ 2 Runtime spawn section 5.2 Runtime spawn L282–289
+ 3 Health-check loop section 5.3 Health-check loop L289–295
+ 4 Per-request gate section 5.4 Per-request gate L295–300
+ 5 Wire shape the runtime must speak section 5.5 Wire shape the runtime must speak L300–308
+ 8 gate control) section 5.6 Minimal logging (§4.8 gate control) L308–313
+ 7 No ambient authority section 5.7 No ambient authority L313–319
+ Test obligations satisfied (gate §10, 7 tiers) section 6. Test obligations satisfied (gate §10, 7 tiers) L319–335
+ table section table L323–332
+ Deferred (explicitly not Phase 4) section 7. Deferred (explicitly not Phase 4) L335–348
+ Remaining blockers to Phase 5 section 8. Remaining blockers to Phase 5 L348–363
+ table section table L352–356
+ Simple summary section Simple summary L12–23
+ Technical summary section Technical summary L23–33
~ lib/companion-runtime-manager.mjs .mjs 20 symbols added
+ abort method method abort L291–293
+ canServeInference function function canServeInference L455–458
+ createAdmissionState function function createAdmissionState L481–489
+ createIntegrityAccumulator function function createIntegrityAccumulator L219–295
+ createLifecycleState function function createLifecycleState L407–409
+ createResourceLimits function function createResourceLimits L625–636
+ evaluateAdmission function function evaluateAdmission L507–528
+ evaluateResourceLimits function function evaluateResourceLimits L649–680
+ evaluateRuntimeRequest function function evaluateRuntimeRequest L720–749
+ finalize method method finalize L257–277
+ getReceivedBytes method method getReceivedBytes L283–285
+ recordCompletion function function recordCompletion L556–564
+ recordDequeued function function recordDequeued L589–597
+ recordInFlight function function recordInFlight L541–546
+ recordQueued function function recordQueued L574–579
+ transitionLifecycle function function transitionLifecycle L427–443
+ update method method update L237–246
+ validateIntegritySpec function function validateIntegritySpec L159–174
+ validateSourceUrl function function validateSourceUrl L122–149
+ verifyModelBytes function function verifyModelBytes L313–336
+ makeDigest function function makeDigest L41–43
+ download method async_method download L49–49
+ healthCheck method async_method healthCheck L50–50
+ makeDigest function function makeDigest L36–38
+ makeStubAdapter function function makeStubAdapter L45–53
+ simulatePhase5Session function async_function simulatePhase5Session L57–120
+ spawn method async_method spawn L48–48
+ statResources method async_method statResources L51–51
+ makeDigest function function makeDigest L35–37
+ makeDigest function function makeDigest L39–41
+ assertNoSecretInReason function function assertNoSecretInReason L325–332
+ makeDigest function function makeDigest L44–46
+ timeVerify function function timeVerify L401–410
+ timeWith function function timeWith L386–398
+ makeDigest function function makeDigest L32–34
+ makeDigest function function makeDigest L44–46

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:3c71452a68bfee676b1e54695a6d54acb254b3271bb2b31f727090f9618d3f27 --body "your comment"