RFC: authenticated remote RLM children (prime-agent.remote-child/v1) #1571
Replies: 1 comment
2026-08-23 修订版(本 Discussion 的更新)以下为对本 RFC 的完整修订:证据基线更新到 RFC 草稿:authenticated remote RLM children(
|
| 操作 | 发起方 | 语义 |
|---|---|---|
list |
parent | 只列 direct children:现有 filter 以 parentActiveSessionId === current + rlmChildId 合并:agent-session.ts#L9474-L9550。remote row 必须带 runtime/state/attempt/heartbeat。 |
observe |
parent | 对 remote child 只返回 bounded summary、checkpoint 新鲜度与合法 lifecycle preview;不读取任意路径,不伪装本地 transcript。现有 observe 走 family target + bounded preview:daemon-mode.ts#L3209-L3238。 |
message |
W→P | lease 不携带 from;daemon 由 lease 派生 sender,target 由 ledger 解析,payload 里的身份字段被忽略。沿用 16,384 chars / 每 target 20 pending / 3 次每秒等上限:agent-messages.ts#L13-L16。 |
steer / follow_up |
P→W | durable {commandId,seq};W ack;重连重发未 ack 命令,重复 commandId 幂等。 |
stop |
P | 先封锁新 model/tool admission,W 终止自有进程、尽力 checkpoint 后 ACK;只有 termination ACK 才置 cancelled;deadline 无 ACK 则 revoke lease 并置 uncertain/lease_expired + audit,不声称外部副作用已回滚。 |
resume / attach |
W | 凭 child lease + 最后 ack cursor;匹配 parent/child/audience;新 connectionEpoch 立即 fence 旧连接;同 ticket retry 复用 child/session、attempt+1;过期后按规则 terminal 或需 parent 重新授权。 |
heartbeat |
W | 单调 event seq + activity/工具/stdout 摘要;lease 续期有上限,不得无限延长 invitation。 |
checkpoint |
W | 上传真实 transcript/kernel state 的 content hash + attempt + last event seq;daemon 校验后才推进 resumable cursor;无法确认的窗口标 uncertain,不自动重放。 |
complete |
W | 只接受当前 attempt/epoch;final ack + result/artifact refs 后原子 terminal;迟到旧 attempt/epoch 拒绝。 |
delete |
P | direct-parent only:先 revoke capability/fence transport,再写 ledger tombstone,保留 audit 与 identity;运行中先走 stop 语义;幂等。现有 direct-only 由 selector 解析与官方测试锁定:agent-session.ts#L9561-L9570、#L9614-L9677、agent-session-recursion.test.ts#L3967。 |
Python 侧 list_subagents()/delete_subagent() 仍走当前 session host bridge:prime-agent-runtime/src/rlm/__init__.py#L217-L237;remote 只是在 parent session 中新增 row/runtime,不新增 Python 身份参数。
8. Capability 与防护
- Invitation:parent-minted、≥256-bit opaque random、daemon 只存 hash、分钟级 TTL、single-use、
aud=remote-child-admit,绑定 parent session + repo/workflow/ref/environment/ticket + GitHubrun_id/run_attempt。token 不进 argv/log/artifact/report。 - Workload proof:优先 GitHub OIDC 短时 claims(repo/workflow/ref/run id/attempt)经 daemon 信任的 verifier 校验。verifier 在接口后,v1 只要求一个具体实现;broker assertion 不是 authority。
- Child lease:
ADMITTED后 mint,绑定 child/session/parent/attempt/connection_epoch + worker proof-of-possession key;操作集仅attach/heartbeat/checkpoint/message(parent)/complete/cancel。不含list/create/attach arbitrary/prompt/bash/kill/shutdown。 - Parent capability:parent 侧控制由 daemon 当前 parent session authority 派生,只能控制自己的 direct remote child;ticket 映射不是授权。
- Replay fence:invitation JTI single-use;admission 用
nonce + admission_request_id幂等;post-admission 每 mutation 带{attempt, connectionEpoch, sequence, idempotencyKey};daemon 持久化 high-water marks;新 epoch fence 旧 epoch、新 attempt fence 旧 lease;重复 id 返回记录结果,旧帧拒绝或小窗口缓冲。 - Family isolation:sender/target 全部由 capability + ledger 派生,忽略 remote payload 自报
from/rlmChildId/sessionId/parentSessionId;默认 W→P only。 - Audit / quotas:按 invitation/child/parent/repo/connection 记 admission、denial、epoch、控制命令、terminal、quota violation;限制 frame 大小、message/heartbeat/event rate、buffer bytes、retries、并发 children。
- Cancellation / restart:Action cancel trap 正常上报;SIGKILL 由 heartbeat expiry 收割并给 parent terminal notice。daemon restart 从 remote record 恢复 lease hash/cursors,未确认 side effect 不自动 replay。
- 凭据分离:remote-child capability 不是模型 provider credential。v1 不假定存在“GitHub OIDC → 短时 Prime/Codex/Claude 执行凭据”的 issuer;该发行器是独立的未解决前提,两个 token 不得合并。
v1 默认值与安全下限(全部可配置;配置不得低于安全下限,测试锁定下限):
- Invitation TTL 默认 5 min,允许 1–15 min;只存 hash、单次消费。
- Child lease 默认 60 min;续期单次 ≤10 min、累计 ≤24 h;heartbeat 间隔默认 15 s、下限 5 s,grace = 3×interval(超时 revoke)。
- PoP:ADMIT 时 W 提交 Ed25519 公钥,daemon 把 fingerprint 写入 lease/record;每个 attach/heartbeat/complete/cancel 帧带签名;换 key 走重新 ADMIT。
- 帧上限默认 256 KiB、绝对上限 1 MiB;message 沿用现有 16,384 chars/每 target 20 pending/3 次每秒;heartbeat 事件率与帧大小双重限流;buffer/retries/并发 children 均设显式上限。
- audit 保留 ≥90 天(可加长),记录不含 invitation/lease 明文。
9. 分层:application protocol 与 broker
prime-agent.remote-child/v1 是 application protocol:admission、family message、lifecycle、capability、quota/audit 语义。它由 admission 显式协商版本,承载在可插拔 transport 上。
- 双方出站 broker(parent 与 W 都向 relay 发 TLS 连接)只是 推荐的后续 transport,不是协议依赖。Core MVP 全程跑 in-memory transport;RFC 不假定已有托管服务、网络入口、provider credential issuer 或本机开放端口。
- broker 最小信任:只按 channel/capability 转发,有配额/大小/审计,不持有本机 daemon token 或 provider 长期凭据;需要隐藏内容再加应用层会话加密并写入威胁模型。
- 禁止 raw daemon v7 relay;local public socket 仍保持 local-only trust。
10. 无网络 mock transport 原型矩阵
使用 daemon-backed parent + InMemoryRemoteChildTransport(bounded async queue、确定性故障注入、无端口/凭据)+ MockRemoteWorker,其 startModel() 断言已收到持久化 ADMITTED。
| 类别 | case | 必须断言 |
|---|---|---|
| Admission | 成功 / ledger、remote record、session header 任一写失败 / 响应丢失后同请求重试 | 只有全 durable 才返回 ADMITTED;失败零开工、零幽灵 child;重试返回同一 IDs,不二次分配。 |
| Invitation/claims | 过期、撤销、二次使用、错 audience/repo/workflow/ref/run/ticket/parent | fail closed,不分配 child、不泄露 parent 细节,audit 原因。 |
| Identity | payload 伪造 from/childId/sessionId/parentId | 忽略 payload 身份,由 lease+ledger 派生;审计拒绝。 |
| Family | parent/sibling/cousin/other root/grandchild selector | remote W 默认 parent-only;其余拒绝;W 内 rlm() 显式 unsupported。 |
| Visibility | parent list/observe/agents view | runtime="remote"、诚实 remote_state,不伪造本地 transcript/tool rows。 |
| Provenance | 伪造 usage/checkpoint、旧 attempt 的 completion/usage | usage/checkpoint 校验失败 → mark unverified 或 reject;旧 attempt 的 completion/usage 一律拒绝;parent 侧不写 provider-native usage。 |
| Round trip | W→P message;P→W steer/follow-up | 派生 sender、现有 size/rate/pending 上限、ack/重连可恢复、无重复投递。 |
| Disconnect | heartbeat 丢失、grace 内 attach、grace 后 attach | disconnected 可见;grace 内同 IDs + epoch+1;过期拒绝旧 lease。 |
| Replay/order | duplicate/out-of-order seq、old epoch、old attempt | dedupe 或拒绝;steer/stop/complete 不重复执行。 |
| Retry split-brain | 同 ticket 两个 worker 并发 retry | 只有一个 epoch 获胜;same child/session + attempt+1;旧 worker fenced。 |
| Parent control | graceful stop、无 ACK 超时、delete running child | 仅 ACK 置 cancelled;超时 revoke/uncertain+audit;delete 先撤权且幂等。 |
| Action cancel | cancel trap 正常、runner SIGKILL | 正常终态;异常由 TTL 收割且 parent 收 notice。 |
| Daemon restart | admit 后、command 未 ack、complete 前重启 | invitation 消费不回滚;cursors 恢复;不确定 side effect 不自动 replay。 |
| Broker fault | 重复/延迟/丢帧、断线、broker 冒充 command | epoch/seq/capability 挡住;本机 raw daemon 不可达。 |
| Quota | oversize frame、heartbeat/message flood | bounded memory;现有限额回归不退化。 |
| Local regression | 普通 local child spawn/list/message/observe/delete | 现有 tests 全过;local runtime 行为不变。 |
可直接扩展的现有测试锚点:post-handle startup failure agent-session-recursion.test.ts#L1284-L1299、direct-only delete #L3967、nuclear-family reject daemon-mode.test.ts#L2749-L2834、process-level daemon worker daemon-supervisor-process.test.ts#L310-L329。
11. Version / 向后兼容策略
remote-child/v1独立版本,admission 时协商;不暴露、复用或隧穿 local daemon protocol v7(当前DAEMON_PROTOCOL_VERSION=7、DAEMON_SCHEMA_REVISION=22:daemon-protocol.ts#L53-L70)。- host remote child 所需的 local 改动是 additive:new server/client capability、registry/UI optional fields、remote record;未升级 client、纯本地 daemon、无此特性的 worker 行为不变。
- 兼容新增可走 capability-gate 或 schema revision;不兼容 wire 变更才 bump protocol(现有规则:
daemon-protocol.ts#L44-L70、docs/daemon.md#L91)。本设计不改create/send_message的现有本地认证语义,因此不要求 v8。 - Python
RLMSubagentdataclass 当前字段固定为 6 项:prime-agent-runtime/src/rlm/__init__.py#L43-L50;新增 optionalruntime/remote_state/attempt/last_heartbeat_at属于 CLI/SDK/UI 真实改动,不是只改 server。
12. PR 切分(每段独立可 review/验收)
- Core MVP:
RlmChildRuntimeseam + local adapter、remote record/state machine、registry schema、ledger 关联、invitation/workload-proof/lease 抽象与验证、no-network mock 矩阵。无网络、无 broker、无端口。 - Security / transport:一个具体 workload-identity verifier(GitHub OIDC claims)和 SPI 后第一个真实 transport(双方出站 broker client);fencing/idempotency/quotas/audit 的 wire 化。自带验收对端:in-repo 测试 relay/回环对端覆盖握手/重连/fence(无外部依赖);若需真实网络路径,最小自托管 broker server 与 client 同段交付、以回环地址验收。PR4 的托管服务仍为可选,不构成 PR2 依赖。
- CLI / SDK / UI:parent invite/revoke/status/retry;remote worker entrypoint/SDK;TUI agents view 显示
connected/disconnected/attempt/last_heartbeat,提供 steer/stop/delete。 - Broker(可选):托管 relay 或用户自托管实现;若 Prime 团队不提供,协议仍可运行。broker secret 不进 repo。
13. 查重结论与不重复提交
查询时间 2026-08-23,范围:Prime 公开 Issues(312)、Discussions(144)与 main @ e319a66 源码词面/符号。
- Issue Feature: ACP client-backed external child agents #739(ACP client-backed external child agents):本地 ACP command 作为 child backend;未定义跨主机 worker、detached old parent admission、durable start permit、family authority、remote lifecycle record。已随 discussion-first 政策关闭(state reason
not_planned),不能承接本题。 - Issue Prime Agent v0.8: five-stack integration tracker #1182(v0.8 five-stack integration tracker):正文是 Core/MCP/Release/Prompts/ACP-Evaluation 的集成 checklist,其中 “remote reviewed refs” 指已推送到远端的 Git refs,不是 remote agent runtime。把本安全协议挂进去会污染 release tracker,且该票明确把上游 prerequisites 分开;不承接。
- 相关 Discussions:Expose plugin-initiated detached sessions on ExtensionActions (it already works via DaemonClient) #1488 是 extension 用本地
DaemonClient创建 detached top-level session,不产生 RLM family edge;RLM parent lineage options are not forwarded during session replacement #1470 是本地 lineage 在 session replacement 时丢失;[Feature] Local browser dashboard for daemon-backed sessions and subagent trees #1421 是本地浏览器 dashboard;[Feature] Sibling reply doctrine: top-level sessions should reply to agent-message senders #1529/[Feature] Set reasoning effort per subagent in rlm() #1506/Prime Agent 0.7.2: isolated RLM worker reaches the normal V8 heap limit and aborts on Linux/WSL2 #1503 等分别涉及 reply doctrine、per-subagent reasoning effort、worker heap,均不含 remote admission。 - Discussion RFC: authenticated remote RLM children (prime-agent.remote-child/v1) #1571 已由同一作者以同标题提交并保持打开,是本提案的现有承载。本稿是它的修订候选(主要变化:证据基线从旧 commit 更新到
main @ e319a66,并继续满足 durable admission、分层、mock 矩阵、version、PR 切分),因此不重复新开 Discussion。 - 源码负证据:在
e319a66的packages/coding-agent/src、packages/coding-agent/docs、packages/coding-agent/test、prime-agent-runtime/src中,没有RemoteRlmChildRuntime、remote-child、child lease、outbound broker transport 或 remote ADMITTED record 的实现;最近的 schema 演进(revision 22)仍只涉及 ACP MCP replacement 与本地 daemon 能力:daemon-protocol.ts#L56-L70。
14. 开放决策
RlmChildRuntimeseam 是否采用上述 factoring,还是另设 host-owned runtime adapter?- crash-recoverable admission transaction 的存储 owner 是谁(同时保持
RlmSpawnLedgertopology 权威)? - Prime core 直接理解哪些 workload identity claims,哪些留在 verifier 接口后?
observe对 remote child 展示哪些 bounded 字段,才不会变成误导性 mirror transcript?- v1 是否保持 remote child 为 parent-only leaf;sibling reach 与远程孙代何时开放?
- 若 upstream 接受,是否把 RFC: authenticated remote RLM children (prime-agent.remote-child/v1) #1571 转成 maintainer Issue,并邀请 Core MVP 实现?
Uh oh!
There was an error while loading. Please reload this page.
Problem
Prime Agent runs a child
AgentSessionunder a resident parent, keeps the family edge, and routes family messages — but only for a child process on the same machine. It cannot admit an agent running on another host as that child.The target case: a detached, still-running parent session P on a user's workstation, and a coding worker W in a GitHub-hosted Actions job. W must become a real child of that exact P before it starts a model or touches the checkout, and P must then list, observe, message, steer, stop, and delete W under the same family rules as a local RLM child.
Required semantics:
rlm_child_id,session_id,parent_session_id, and depth from admission; it cannot choose or override them.ADMITTED.list_subagents()shows W asruntime="remote"with an honest state; W'sagent_messagecan reach P; P can steer, stop, and delete W.Current state (the gap)
The runtime contract is local.
RlmSubagentRuntimeholds a concreteAgentSession, andSubagentRuntimeHost.createRlmSubagentRuntime()must return one (rlm-runtime.ts:214-254). The extension API adds tools, commands, events, and providers, but cannot register a kernel host handler, bind a subagent host into a running daemon parent, write the RLM family ledger, or grant family sender authority (extensions/types.ts:957-1148).A standalone start is not a child. The daemon
createrequest has no parent-admission fields; a runtime without explicit parent metadata is top-level (main.ts:975-1013,agent-session-runtime.ts:73-85). Startingprime-agentseparately yields another root session, even with a ticket mapping beside it.The current handle is not a start barrier.
_startRlmChildRun()allocates thesub-*directory and an in-memory run and returns the handle before ledger persistence (agent-session.ts:9492-9518); a caller can already hold a handle when startup later fails (agent-session-recursion.test.ts:1158-1185). That is acceptable for local children, but a remote launcher needsADMITTEDto be a durable start permit and nothing earlier.The daemon socket is a local trust boundary. It listens on an owner-only Unix socket / named pipe; a connection is marked authenticated because filesystem access is the authentication, and the command set includes create/attach/kill/prompt/steer/bash/delete (
daemon-socket.ts:9-43,daemon-supervisor.ts:1019-1057). The source itself calls this the local daemon protocol, not the final remote gateway (daemon-protocol.ts:43-50). Tunnelling it would hand that broad authority to an Actions job, so a remote path must expose only child-scoped operations and must not forward raw daemon frames.Prior art
The closest existing item is Issue #739, "ACP client-backed external child agents": it launches a configured ACP command as a child backend. It does not specify a worker on another host, admission into a detached parent, a durable start permit, family authorization, or a remote lifecycle record, and it was closed when public intake moved to Discussions. A local ACP backend could later implement the child-runtime seam below, but it does not own remote admission.
Other near items keep execution local: Discussion #1488 (plugin-initiated detached top-level sessions via local
create/prompt), Discussion #1470 (lineage survival across local session replacement), Discussion #1421 (loopback browser dashboard for local sessions). Issue #1182 (v0.8 integration tracker) uses "remote" to mean remotely-available Git refs, not remote agent processes; this proposal should not be attached there. No existing issue, discussion, or source symbol defines remote admission into an exact old parent.MVP semantics
One seam: local vs remote child runtime
Split child control from the concrete local
AgentSession:LocalRlmChildRuntimewraps today'sAgentSessionwith no behavior change.RemoteRlmChildRuntimeis a parent-daemon control object backed by durable remote state; the real session, kernel, model loop, tool calls, and checkout live in the remote job. Parent orchestration depends only onRlmChildRuntime; direct transcript subscription and provider-usage reads move behind the local adapter. Attempt and epoch are not part of identity — they do not exist until a child does (see admission).Admission is the only start permit
Admission must be crash-recoverable and idempotent, and the ADMIT request carries no attempt or epoch:
invitation_id, a single-usenonce, a client-generatedadmission_request_id, supported protocol versions, and verifiable workload claims. Admission anti-replay rests on single-use invitation consumption + nonce + idempotent request id — not on attempt/epoch, which do not yet exist.child_idandsession_iditself.attempt=1, andconnection_epoch=1.ADMITTED. Attempt and epoch are assigned here, after admission, never before.ADMITTED.A retry with the same
admission_request_idand identical claims returns the same committed admission; a second use of the invitation, or changed claims, fails closed.RlmSpawnLedgerstays the append-only family-topology authority (rlm-ledger.ts:24-95); the remote record only supplements that edge with runtime, connection, attempt, and lease state.Family: parent-only by default
Prime's family predicate permits parent, same-parent siblings, and direct children, rejecting cousins and more distant nodes (
agent-messages.ts:216-249). A remote worker in v1 is parent-only: W may message its exact parent P and nothing else. Sibling and every other family target is rejected — even a sibling the local predicate would allow — because W's job sandbox is less trusted than a co-resident local child. The daemon derives the sender from the authenticated lease and the target from its ledger; it ignores anyfrom,child_id,parent_session_id, or relationship claimed in a worker payload. A ticket mapping grants no family access.v1 remote children are leaves:
rlm()inside W fails with an explicit unsupported error rather than creating an untracked descendant. Broadening W's reach to siblings or wider family, and remote grandchildren via delegated admission, are maintainer future decisions (see Open decisions).Lifecycle: stop, parent closure, and replacement
STOPis a durable parent command. W first blocks new model/tool admission, aborts current work, terminates child processes it owns, writes a final checkpoint if it can, and acknowledges cancellation. Only a received termination ACK marks the attemptcancelled.uncertainorlease_expiredper the last acknowledged activity, and audits it. Revocation never claims an external side effect was rolled back and never fabricates acancelled.STOPunder the same rule:cancelledonly with a termination ACK, otherwiseuncertain/lease_expired+ audit.delete_subagent()stays direct-parent only (agent-session-recursion.test.ts:2886-2904): revoke authority, fence the epoch, request stop when reachable, write the topology tombstone, and retain the audit record needed to reject late frames. Deletion is idempotent.Provenance, not fabrication
W owns the real transcript, kernel checkpoint, and usage. The parent may store a small session header and typed
remote_child_*lifecycle records; it must not write fabricated assistant, tool-call, tool-result, stdout, token, or cost entries to make W look local.observelabels remote data and checkpoint freshness. Reported usage carries explicit provenance (source=remote_worker_report, attempt, checkpoint hash, verification status) and never overwrites provider-native usage.Threat invariants
In scope: invitation theft/replay/reuse; a worker for the wrong repo/workflow/run/ticket/parent; payload identity spoofing and confused-deputy family requests; lease theft; duplicate workers, delayed old frames, reconnect races, retry split brain; daemon crash mid-admission; cancellation, runner loss, stale processes; oversized frames and message/heartbeat floods; false transcript/checkpoint/usage claims. Out of scope: compromise of the local OS user or the remote job sandbox itself — a compromised worker can do whatever its sandbox permits; the design only bounds which Prime family and controls it can reach.
Three capabilities, all minimal and all required for durable admission:
remote-child-admit, constrained to P plus workload identity; stored as a hash, not plaintext.ADMITTED, bound to child/session/parent/attempt/connection-epoch and a worker proof-of-possession key. Its operation set is limited to attach, heartbeat, checkpoint, parent-family message, complete, and cancel. It cannot list, create, prompt, bash, kill, or shut down arbitrary daemon sessions.Fencing invariants (post-admission): every mutation carries
{attempt, connection_epoch, sequence, idempotency_key}; a later epoch fences the former, a later attempt fences every former lease, duplicate ids return the recorded result, out-of-order frames are rejected or buffered in a small fixed window. Quotas apply per invitation/child/parent/repo/connection (frame size, event/message/heartbeat rate, buffered bytes, retained duration, retries, concurrent children). Audit records admissions, denials, capability changes, epochs, control commands, terminal transitions, and quota violations without recording secrets. The child capability is unrelated to model-provider credentials: v1 defines no OIDC-to-provider issuer, and a deployment must solve provider authorization separately with job-bound credentials.No-network mock (Core MVP acceptance slice)
The invitation, workload-proof, and lease abstractions above, plus their verification, are one acceptance slice — they do not wait on any broker, network, or transport PR. The prototype uses a daemon-backed parent, an
InMemoryRemoteChildTransport(bounded async queues, deterministic fault injection, no port, no credential), and aMockRemoteWorkerwhosestartModel()asserts a committedADMITTEDwas received.ADMITTED; parent lists one remote child.rlm()fails explicitly.disconnected; reattach same IDs at a new epoch; reject an expired lease.cancelled; timeout/closure yieldsuncertain/lease_expired+ audit, never a fabricated stop or rollback claim.Existing tests already anchor these boundaries — post-handle startup failure and cancellation (
agent-session-recursion.test.ts:1158-1219), family/cousin rejection (daemon-mode.test.ts:2653-2738), and daemon process behavior (daemon-supervisor-process.test.ts:310-337); the remote suite should extend them, not build a second, weaker family policy.Layering, versioning, and delivery
Layered over a pluggable transport.
prime-agent.remote-child/v1is an application protocol — admission, family messaging, lifecycle, capability semantics — carried over a transport chosen at deployment. Any outbound broker on either side (a parent or a worker reaching a hosted relay) is only a recommended future transport, never a dependency: the Core MVP runs entirely over the in-memory transport and assumes no broker, network, port, credential, or hosted service exists.Versioning is independent and additive-only.
remote-child/v1is versioned on its own and negotiated at admission; it does not expose, reuse, or tunnel the local daemon protocol (currently v7). The local additions needed to host a remote child are additive and capability-gated, so an unpatched client, a local-only daemon, and a worker without the feature all keep their current behavior.Delivery — each stage independently reviewable and acceptance-gated:
RlmChildRuntimeseam, durable admission (invitation / workload-proof / lease), family/lifecycle/provenance semantics, and the no-network mock matrix above. Acceptable on its own, with no transport.list_subagents,observe, messaging, and steer/stop/delete.Open decisions
RlmChildRuntimeseam (localAgentSessionbehind an adapter) the right factoring?RlmSpawnLedgerstays the family-topology authority?observewithout a misleading mirror transcript?The wire operations, envelope layout, broker deployment shape, and version-negotiation mechanics are intentionally deferred to the accepted design. This RFC fixes the problem, the current-state gap, the MVP semantics and threat invariants, the layering/versioning/delivery stance above, and the no-network acceptance slice — not a full wire protocol.
All reactions