diff --git a/.changes/unreleased/+controlled-session-repository-design.yaml b/.changes/unreleased/+controlled-session-repository-design.yaml new file mode 100644 index 00000000..e276556e --- /dev/null +++ b/.changes/unreleased/+controlled-session-repository-design.yaml @@ -0,0 +1,2 @@ +kind: Docs +body: Document controlled sessions and federated repositories, including their trust boundaries and implementation direction. diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 9b31ada4..ff0bce09 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -1,6 +1,6 @@ --- status: Active -updated: 2026-07-29 +updated: 2026-08-04 summary: Active planning surface for Reploy design and implementation gaps. --- @@ -31,6 +31,64 @@ This file is the day-to-day queue for design and implementation gaps. ## Now +- [ ] `P1` Inventory the global sandbox prerequisites for controlled sessions. + Use `CONTROLLED_SESSION_DESIGN.md` as the policy source. Map every staged, + installed, command, and shell container-launch path against the approved + identity, seccomp, `no-new-privileges`, capability, namespace, device, + mount, mask, secret, network, and root invariants. Record verified current + behavior and turn each missing invariant into a focused implementation + slice before starting the controlled-session lifecycle core. + +## Pre-release + +- [ ] `P1` Accept APT install transaction records with the optional trailing + empty marker. Current APT versions may emit valid `Inst` records ending + in `) []`, which Reploy currently rejects as malformed. Accept exactly + the known optional ` []` suffix while preserving the existing package, + version, and architecture checks. Add regression coverage for ordinary + installs and upgrades, streaming chunk boundaries, and rejection of + nonempty, duplicated, or otherwise malformed trailing markers. + +- [ ] `P2` Add explicit controlled runtime command aliases for validated + executable outputs. Keep provider exports non-public by default, and let + a blueprint opt into mapping ordinary command names such as `rustc` to + qualified executable profiles. Materialize only those aliases in a + Reploy-owned executable directory, place that directory first on the + runtime `PATH` while preserving the base-image path, reject unsafe names + and collisions, and bind the alias table and effective path into final + validation, runtime-layer identity, build locks, and cache reuse. Cover + `reploy shell`, blueprint commands, and subprocess lookup without adding + a general filesystem-link surface or exposing whole package directories. + +- [ ] `P2` Allow application executable profiles to consume explicit base-image + exports. Accept `source: base` as a reference to the reserved base + contribution so an application command can use a tool guaranteed by the + selected immutable base without declaring a redundant OS package. Permit + applications whose only capabilities are base-backed executable profiles, + retain application-qualified command references such as `builder.rm`, and + carry the selected base output through final validation, runtime-path + protection, build locks, cache identity, and actionable missing-export + diagnostics. Do not add a parallel direct-command form such as `base.rm`. + +- [ ] `P2` Define cancellation at the admission boundary. + Specify the authoritative outcome when a waiting caller is promoted at + the same instant its context is cancelled. Preserve the invariant that + the operation either remains unstarted and is removed from the queue, or + is admitted and then cancelled with complete cleanup; never replay an + abandoned request. Add a deterministic race test covering both outcomes. + +- [ ] `P1` Define root-safe explicit output-file and output-dir contracts. + Preserve the prohibition on arbitrary host binds while treating a + caller-selected output destination as a narrow explicit grant. For + `--output-file`, perform a focused security review of fresh staging, + ownership and mode normalization, regular-file and link validation, + race-free publication without overwrite, interruption recovery, and + cleanup. For `--output-dir`, require an initially empty dedicated + directory, define ownership normalization and failure retention, and + reject unsafe targets before contacting Docker. Add cross-platform + integration tests proving a root workload can create the requested + outputs but cannot reach the destination parent or unrelated host data. + - [ ] `P1` Add blueprint-configured control-runtime modes. Let blueprints select `embedded` or `path` independently for staging and installation, defaulting both to the current self-contained `embedded` @@ -40,8 +98,6 @@ This file is the day-to-day queue for design and implementation gaps. resolved path for installed service definitions rather than depending on an interactive user's `PATH`. -## Pre-release - - [ ] `P1` Audit validation for every blueprint field. Inventory each field from strict decoding through interpolation and resolution to its final host, Docker, or workload sink. Verify structural, @@ -120,6 +176,15 @@ This file is the day-to-day queue for design and implementation gaps. ## Post-v1 +- [ ] `P2` Consider a Reploy host configuration surface. + Keep a standing inventory of concrete operator- or host-owned settings + that do not belong in blueprints, staging overrides, or installation + state. Do not add a general configuration file until the accumulated use + cases justify its scope, precedence, user/system ownership, validation, + and portability. Initial potential use case: overriding the otherwise + fixed host-owned limits for controlled-session endpoint streams and + connection-open rates. + - [ ] `P2` Evaluate and prioritize the Dingo development-environment gaps. Use `docs/DINGO_GAPS.md` as the needs and evidence record for portable checkout binding, development execution, shell initialization, pinned @@ -129,6 +194,105 @@ This file is the day-to-day queue for design and implementation gaps. turn accepted priorities into focused follow-up backlog items without treating this document as an implementation plan. +- [ ] `P2` Implement Reploy repository schemas and publication tooling. + Follow `docs/REPOSITORY_DESIGN.md` as the policy source. Define strict + schemas for the repository descriptor, current publisher authorization, + shared asset version and revision records, indexes, immutable asset + targets, publisher DID attestations, repository acceptance records, + lifecycle events, and portable tool definitions. Use the same SemVer, + PEP 440, integer, and opaque version implementation for blueprints and + tools, with a separate positive Reploy revision for each exact upstream + version. Keep repository records and locks structured even where the CLI + offers a compact full-pin selector. + + Implement deterministic repository compilation and static validation. + Current publisher authorization governs new publication only; historical + releases validate through their retained publisher attestation and + TUF-authenticated repository acceptance record. Retain immutable lifecycle + events for yank, archive, delete, publisher revocation, rescission, purge, + and ownership transfer, and make the current index reference their + effective state. Reject release-coordinate reuse, implicit ownership + transfer, and invalid transitions. Permit a Reploy repository to live in + a declared subdirectory of a larger Git repository without allowing input + or generated-output paths to escape that root. + + Keep the ordinary `reploy` executable consumption-only. Provide separate + publisher and repository-maintainer tools for DID signing, authorization, + validation, lifecycle administration, deterministic compilation, TUF + signing, and publication. Keep direct BURLs first-class; a present remote + publisher attestation must validate against the exact asset and a + currently authorized DID key, while durable historical key evidence is a + property of repository acceptance. + +- [ ] `P2` Implement Reploy repository clients and offline import. + Integrate a conformant TUF 1.x client; load static HTTPS and filesystem + repositories plus pretrusted plain-HTTP repositories; share the + URL-shaped locator model with blueprint sources while preserving typed + semantics; and implement explicit APT-like `repository trust` and + `repository update [REPOSITORY]` behavior without automatic network + refresh during resolution or build. Keep user and system trust separate, + authorize explicit asset surfaces, preserve mutable repository priority + and source pins, and fail equal-priority ambiguity. + + Cache authenticated snapshots and immutable objects; bind the exact + repository, version scheme, upstream version, Reploy revision, asset + digest, publisher attestation, and repository acceptance record into build + locks; and validate and atomically import complete repository bundles for + disconnected systems. Retain the selected asset and both attestations in + the deployment-owned provider-store closure, and transfer that closed set + during installation. Keep trusted roots, accepted TUF metadata, accepted + indexes, and effective lifecycle state as active repository state. + Treat the separate global immutable-object cache as acceleration only so + size-, age-, or recency-based eviction never requires discovering staged + or installed deployments and never breaks lock replay. + Existing locks must never follow moving repository state, and repository + failure must not corrupt the last valid local snapshot. Ordinary yank, + archive, and delete semantics preserve local replay where the design + allows it; an accepted publisher-security revocation deliberately blocks + affected locked and cached replay while retaining safe teardown commands. + A client that has not received the revocation cannot enforce it. + +- [ ] `P2` Publish the official Reploy repository and documentation. + Publish an independently updated official repository using the common + protocol. Keep only human-authored source and tests on the primary branch. + Put every generated target, TUF metadata update, signature, and publishing + commit on a separate persistent, automation-owned `publish` branch after + deterministic compilation, signing, and validation succeed. Any temporary + signing branches must be deleted without merging into the primary branch. + Generate blueprint and tool pages from validated repository records. Tool + pages show supported operating systems, releases, architectures, + contributed OS package roots, executables, network behavior, artifacts, + validation, and final-image placement. Do not embed a fallback index in + Reploy. + +- [ ] `P2` Migrate Java to an official portable tool definition. + Replace the hard-coded `tool:java` package mapping and validation switches + with an official repository definition while preserving its existing + project-owned, build-only behavior and build-lock identity. Add focused + Debian-derived integration coverage before removing the old path. + +- [ ] `P2` Add an official portable Rust toolchain definition. + Model Rust as one versioned toolchain rather than independent `rustc` and + Cargo tools so the compiler, Cargo, and Rustdoc remain compatible. Resolve + and lock exact platform artifacts and provenance, materialize them + offline beneath a Reploy-owned root, and expose `rustc`, `cargo`, and + `rustdoc` through the shared controlled runtime-command mechanism rather + than a Rust-specific `PATH` path. Add version, platform, cache-reuse, + shell, and Cargo-subprocess coverage, and do not depend on a host + toolchain or a networked `rustup` bootstrap during materialization. + +- [ ] `P2` Add official Playwright portable tool support. + Add the reviewed resolver primitive and official `tool:playwright` + definition using the shared asset version and revision model. Resolve the + compatible browser payload, contribute documented OS package roots, keep + project source and host credentials out of networked acquisition, + materialize offline, and lock and validate exact platform, browser, + artifact, and definition identities. Require explicit browser selection + and list the target-supported browser values when it is missing or + unsupported. Prove multi-browser selection produces one order-independent, + deduplicated OS-requirement union and retains exact identity for each + browser payload. + - [ ] `P2` Generate a maintained official base-image index. Add a server-side tool that clones `docker-library/official-images` and produces one deterministic, versioned index file containing the official diff --git a/docs/CONTROLLED_SESSION_DESIGN.md b/docs/CONTROLLED_SESSION_DESIGN.md new file mode 100644 index 00000000..838944c2 --- /dev/null +++ b/docs/CONTROLLED_SESSION_DESIGN.md @@ -0,0 +1,1162 @@ +--- +status: Active +updated: 2026-08-02 +summary: Capability-scoped execution sessions that inherit Reploy's global container sandbox. +--- + +# Controlled Execution Session Design + +## Status + +- Decision state: Focused review complete; high-level decisions approved +- Implementation state: Not started +- Initial runtime: Linux containers under Docker +- Motivating clients: OmegaFlow recording, sandboxed AI agents, security + inspection, and untrusted-code execution + +This document records the decisions for a reusable Reploy controlled-session +capability and the global Reploy container sandbox policy on which it depends. +It does not define OmegaFlow recording syntax, browser actions, media formats, +or publication behavior. + +## Decision Summary + +Reploy will let a controller such as OmegaFlow control one +host-created session in an exact staged environment generation without +receiving Docker or arbitrary host authority. + +The controller owns the session from its perspective. A host Reploy operation +performs the authorized Docker work, records the runtime resources under a +lease, and independently attests their termination. It does not understand +OmegaFlow beats, browser handoffs, or recording state. + +A controlled session provides: + +- one persistent PTY and shell; +- ordered input and output bytes; +- terminal resize; +- recorded terminal interrupts such as ordinary Ctrl-C; +- administrative termination and cancellation; +- structured exit and failure events; +- access to explicitly granted workload endpoints; +- generation-bound admission, lifecycle, cleanup, and recovery. + +These are global Reploy container defaults, not additional treatment for +controlled sessions: + +- no public or local network access; +- no host application-data paths unless explicitly granted by a runtime + contract; +- no inherited host environment; +- no Docker, runtime, or daemon socket; +- no privileged container; +- no Linux capabilities unless separately and explicitly designed; +- verified seccomp and `no-new-privileges`; +- no host namespaces or host devices; +- runtime identity inherited from the Reploy execution scope for application + containers; +- read-only project source access only when explicitly granted. + +This baseline applies to every container Reploy creates. Provider-resolution, +build, validation, and materialization helpers may receive narrowly scoped +root, network, capability, or filesystem grants required by their provider +contract. Those are explicit construction authorities, not implicit exceptions +or authorities inherited by application containers. + +Reploy does not configure a second container-local username. Staged and +installed user-scope containers run as the invoking host user's numeric UID, +GID, and supplementary GIDs. Installed system-scope containers run as the host +account explicitly selected by `environment.install.system.account`, using +that account's numeric identity inside the container. This design renames the +existing `environment.install.system.run_as` field because the setting selects +the installation's host account; it is not a second container-user setting. + +If the effective runtime user is root, Reploy emits a precise warning that the +application can interfere with more of its container. Root does not implicitly +grant capabilities, host input or shared-state mounts, network access, +privileged mode, or daemon access. Root-safe `--output-file` and `--output-dir` +are separate global runtime contracts and remain rejected until their focused +pre-release review and implementation are complete. + +## Context + +Controlled execution separates two environments: + +1. A trusted controller environment containing orchestration, policy, capture, + inspection, or agent-supervision software. +2. An isolated workload environment containing untrusted source, dependencies, + commands, services, and declared endpoints. + +OmegaFlow maps these roles to a controller containing OmegaFlow, asciinema, +Playwright, Chromium, ffmpeg, codecs, narration, and publishing tools, and a +workload containing the recorded project. A sandboxed agent or security +inspection controller can instead supervise untrusted code without changing +the Reploy session architecture. + +Giving a controller a host Docker socket would also give it authority over +unrelated containers, images, mounts, secrets, and host paths. Installing every +controller implementation inside its workload would erase the trust boundary +and burden workload blueprints with controller-specific details. + +Distribution of portable controller dependencies is a separate concern defined +in [`REPOSITORY_DESIGN.md`](REPOSITORY_DESIGN.md). +Controlled sessions consume a prepared controller environment; they do not +define tool repositories, Playwright browser acquisition, or application +blueprint distribution. + +Reploy already has useful foundations: + +- staged desired state and exact generation identity; +- provider build locks and current-build verification; +- attached transient shell execution; +- live-run admission, cancellation, generation checks, and cleanup; +- managed mounts, private workload environment injection, and endpoint + publication; +- deployment-scoped crash-recovery state. + +The missing capability is a programmable, capability-scoped session contract +that a containerized controller can use without emulating Reploy internals. +OmegaFlow is the first concrete consumer, but the same primitive supports +sandboxed agents, prompt-injection policy components inside a controller, +security inspection, and execution of untrusted code without granting Docker +or unrelated host authority. + +`reploy validate` already performs basic blueprint syntax and semantic +validation without creating staging state, contacting Docker, resolving +providers, or building. Remote references may update the source cache. A +controlled-session API must not describe this existing command as absent or +claim that basic validation proves provider resolution or build success. + +## Goals + +1. Let a trusted controller drive one isolated staged environment without raw + Docker authority. +2. Preserve a long-lived shell and PTY across multiple controller operations. +3. Keep terminal behavior faithful enough for interactive tools and recording. +4. Bind every operation to one admitted run and exact environment generation. +5. Make runtime termination independently verifiable by host Reploy. +6. Deny workload code access to the host-controlled session channel. +7. Keep network, mount, identity, secret, and output authority explicit. +8. Reuse the primitive for sandboxed AI agents, security inspectors, untrusted + code harnesses, and other controllers where the same trust model applies. +9. Keep OmegaFlow recording semantics entirely outside Reploy. + +## Non-goals + +The initial controlled-session work does not: + +- expose Docker, Docker Compose, or arbitrary runtime operations; +- define OmegaFlow beats, terminal-to-browser handoff, capture timelines, + screenshots, casts, narration, diagnostics, or publication; +- implement arbitrary remote execution; +- provide a permanent Reploy daemon; +- support reconnecting or transferring ownership of a session; +- provide unrestricted numeric signal forwarding; +- design general Internet, DNS, domain, or proxy policy; +- implement a portable disposable writable-source filesystem; +- introduce shared or persistent workload caches; +- guarantee containment against a container-runtime or kernel escape; +- support privileged workload containers. + +## Actors and Terminology + +**Host Reploy operation** +: A normal, attached Reploy process running with the existing authorized Docker + access. It performs runtime operations, owns the resource lease, and observes + Docker state. It is not a permanent daemon. + +**Controller** +: Trusted software that requests and drives a session. OmegaFlow is the + motivating controller. + + A controller may internally compose an orchestrator, policy or + prompt-injection detection subagents, recorders, and inspectors. Reploy sees + one controller connection and one fixed capability set; that internal + composition does not create additional session owners or authorities. + +**Controller container** +: The trusted controller environment. For OmegaFlow it contains orchestration, + asciinema, the PTY proxy, Playwright, Chromium, and media tools. Other + profiles may contain an agent orchestrator, policy subagent, security + inspector, or test harness. + +**Workload container** +: The isolated Reploy application environment containing the untrusted shell, + source, tools, services, and declared endpoints. For OmegaFlow this is the + recorded application; for an agent controller it is the agent workspace. + +**External session supervisor** +: The attached Host Reploy operation that owns the Docker TTY attachment, + session protocol, workload signaling, lifecycle state machine, and + authoritative runtime observation. No trusted Reploy process runs inside the + workload container. + +**Session watchdog** +: A short-lived host Reploy child process scoped to one live lease. It receives + an immutable cleanup manifest, watches a private parent pipe, and removes the + exact leased resources if the attached Host Reploy operation disappears. It + has no listener, accepts no later resource selection, and is not a permanent + daemon. + +**Lease** +: Host Reploy's binding between one controller connection, admitted run, + generation, capability set, and the runtime resources created for it. + +**Session handle** +: An opaque identifier valid only within its lease. It never conveys arbitrary + deployment selection. + +**Session channel** +: A private channel between the controller and the attached Host Reploy + operation. It is created for one already planned lease and carries PTY data, + bounded controller requests, declared endpoint streams, and host-observed + lifecycle events. It grants no session-creation or general host-runtime + authority and is never mounted into the workload container. + +## Architecture + +```text +Host attached Reploy operation +├── validates one complete immutable session plan +├── creates the lease and inert Docker resources +├── records their exact identities and starts the session watchdog +├── starts the controller and workload containers +├── owns the Docker TTY attachment and framed session protocol +├── forwards only predeclared workload endpoints +├── monitors and cleans every leased runtime resource +└── independently observes lifecycle completion + ⇅ + ⇅ private session channel + ⇅ +Controller container +├── controller orchestration +├── optional policy, inspection, or capture components +└── optional controller-local endpoint adapter + +Workload container +├── untrusted workload shell on the Docker-managed PTY +└── declared services and endpoints +``` + +The host invocation selects the staged generation and complete runtime plan +before either container starts. Host Reploy validates that fixed plan, admits +one live run, creates both containers, and binds the session channel to the +resulting lease. The controller never requests creation of a deployment or +container and cannot select mounts, identity, environment, output destinations, +networks, or another generation through the channel. + +Startup is synchronized. Host Reploy creates the leased resources without +starting untrusted workload execution, establishes the controller channel and +Docker TTY attachment, then starts the workload process and reports the +session ready. After that point the runtime plan is immutable. The channel +accepts only operations on the already-created session. + +Host Reploy remains in both the PTY and lifecycle paths. It transports terminal +bytes without interpreting them, applies resize through Docker, performs +termination through container lifecycle operations, and independently observes +the exact containers. Workload code never receives the session channel, +even when its effective runtime identity is root. + +## Trust Model + +### Trusted + +- the host Reploy executable and its state; +- the Docker runtime within its ordinary trust boundary; +- the controlled-session protocol implementation; +- the intended controller and controller image. + +### Untrusted + +- workload source and dependencies; +- workload commands and subprocesses; +- terminal output and escape sequences; +- network services exposed by the workload; +- files supplied by the project; +- the workload container after untrusted code starts. + +The design also considers a compromised controller. It can +control and disclose everything explicitly granted to its session. It must not +thereby gain access to unrelated host data, Docker, other deployments, +undeclared paths, or undeclared networks. + +### Protected Assets + +- host Docker and runtime authority; +- unrelated deployments and their resources; +- host paths not explicitly granted; +- deployment `.env` and internal `.reploy` state; +- secrets not granted to this session; +- local and public networks not granted to this session; +- session-control integrity and lifecycle truth; +- private outputs and diagnostics until their owning client publishes them. + +## Global Reploy Container Sandbox + +Controlled sessions do not receive a special sandbox tier. Every container +Reploy creates starts with the same deny-oriented baseline: + +- verified seccomp and `no-new-privileges`; +- no Docker or runtime socket; +- no privileged mode; +- no host namespaces or host devices; +- no inherited host environment; +- no undeclared mount, network, capability, or secret access. + +Purpose-specific container classes then receive only their declared authority. +The application-runtime class includes: + +- staged workloads, commands, and shells; +- installed user-scope workloads, commands, and shells; +- installed system-scope workloads, commands, and shells; +- controlled-session workload containers. + +The effective blueprint, installation scope, and host invocation determine +identity, mounts, environment, endpoints, and other explicit grants before +startup. The controller cannot expand or change them or select arbitrary host +paths, Docker resources, identities, or networks. + +Every application runtime container: + +- uses an explicit numeric runtime identity rather than the image's configured + `USER`; +- drops all Linux capabilities unless a separately designed feature grants a + specific capability; +- enables `no-new-privileges`; +- uses a verified seccomp filter; +- receives no privileged mode, host namespace, host device, or runtime socket; +- uses a read-only container root filesystem plus only declared writable + storage; +- receives no public or local network access unless explicitly granted; +- receives only declared mounts and private environment inputs; +- is subject to bounded process, memory, CPU, temporary-storage, and output + policy where supported. + +Reploy explicitly requests Docker's built-in seccomp profile. Before launching +untrusted application code, the trusted runtime bootstrap verifies that filter +mode and `no-new-privileges` are active and that the effective, permitted, and +bounding capability sets are empty. An engine or platform that cannot prove +this baseline cannot run Reploy application containers under this policy; it +does not silently degrade only because the selected identity is non-root. + +Provider-resolution, build, validation, and materialization containers execute +package managers and other purpose-specific operations. Their provider +contracts must separately declare and justify any root identity, network, +capability, writable filesystem, or host-input access. Controlled sessions and +application containers never inherit those construction authorities. + +## Controlled-Session Delta + +A controlled session adds orchestration, not a stronger or weaker workload +sandbox. Its workload consumes the ordinary Reploy application-runtime policy. +Relative to an ordinary Reploy shell or application command, it adds: + +- a controller-owned lease bound to one deployment generation and live run; +- a persistent PTY and typed host-mediated protocol; +- a private controller-to-host session channel; +- an immutable, prevalidated runtime plan; +- controller-loss teardown and independent host-observed termination; +- a session-scoped cleanup watchdog; +- bounded output transport and structured session diagnostics. + +It does not add another runtime identity, broader storage or network access, a +Docker socket, or a privileged container mode. OmegaFlow recording and an AI +agent controller consume the same generic session mechanism and the same global +runtime sandbox. + +## Capability and Authorization Model + +Before starting either container, Host Reploy produces a host-side authorization +record containing: + +- the deployment identity; +- the exact current generation reference and build identity; +- the admitted live-run identity; +- the effective runtime plan; +- the effective runtime identity inherited from the execution scope; +- the network and endpoint grants; +- the mount and source grants; +- the permitted session and endpoint operations; +- the lease lifetime and owner connection. + +The controller does not receive a generic session-creation capability. After +creation, protocol operations do not accept a deployment name, mount, identity, +environment key, output destination, network, or raw endpoint destination. +They act only on the session and logical endpoint identities established by the +host-created plan. A generation change invalidates admission of a pending +session; it does not retarget a live session. + +A unique private endpoint and opaque handle prevent accidental cross-session +use, but secrecy is not the sole security boundary. Isolation relies on: + +- a session endpoint made available only to the intended controller; +- transport and process permissions; +- a typed handshake bound to host-created session state; +- server-side capability checks; +- exact generation and run identity; +- independent host lifecycle observation. + +## Session Protocol + +The protocol is versioned, typed, length-framed, and binary-safe. Terminal +bytes are never parsed as protocol messages. + +### Controller Requests + +- `input(bytes)`: write exact bytes to the PTY. +- `resize(columns, rows)`: set the PTY window size. +- `terminate`: request bounded graceful session termination. +- `complete`: after Host Reploy has emitted `workload_outputs_finalized`, declare + that the controller has finalized its client-owned results. It does not stop + an active workload and is rejected before workload output reaches a terminal + state. +- `open_endpoint(request_id, endpoint_id)`: request one byte stream to a logical + endpoint fixed in the immutable session plan. `request_id` correlates the + result with this request; it is not the stream identity. +- `acknowledge_terminated`: confirm receipt of the authoritative `terminated` + event. This payload-free protocol handshake is mandatory housekeeping, not a + granted capability, and is accepted only after Host Reploy has successfully + emitted the terminal result. + +Admission cancellation is host-owned and is not a session-protocol request. +Host-terminal Ctrl-C while waiting removes the caller's queued operation. Once +admitted, host cancellation terminates that caller's session and cleans its +lease. The exact promotion-versus-cancellation boundary is a global admission +queue invariant tracked as separate pre-release work. + +### Session Events + +- `opened`: reports the effective dimensions, identity, generation, and fixed + session capabilities. +- `output(bytes)`: ordered PTY output bytes. +- `workload_exit(status, reason)`: reports host-observed workload-shell + exit. +- `terminating(cause)`: reports that the host-owned terminal transition began. +- `diagnostic(code, message)`: reports protocol, runtime, or cleanup failure + without embedding secret values. +- `endpoint_opened(request_id, endpoint_id, stream_id)`: reports a successful + endpoint open and assigns its host-generated session-unique stream identity. +- `endpoint_open_failed(request_id, endpoint_id, code, message)`: reports an + unsuccessful endpoint open without assigning a stream identity. +- `endpoint_closed(stream_id, endpoint_id, reason)`: reports one forwarded + endpoint stream ending. +- `workload_outputs_finalized(status, reason)`: establishes that no further + workload output can arrive. `status` is `drained` when every byte was + delivered and `failed` when bounded finalization had to close an incomplete + output surface. + +Every well-formed `open_endpoint` request receives exactly one correlated +`endpoint_opened` or `endpoint_open_failed` outcome. Request IDs are nonzero +controller-generated 64-bit values and must be unique while a request is +pending. Stream IDs are nonzero host-generated 64-bit values and are unique for +the session. Protocol-invalid frames are handled as protocol errors rather than +endpoint-open outcomes. + +Host Reploy emits the authoritative lease lifecycle result: + +- `terminated(cause, workload_status, controller_finalization_status, + cleanup_status, recovery_action)`. + +`controller_finalization_status` reports the controller protocol outcome: +`completed`, `lost`, `finalization-timeout`, `not-completed`, or +`startup-failed`. It is never the controller process or container exit state; +the controller remains alive to receive and acknowledge this event. Its actual +exit state becomes available only after the result channel closes and is +reported with delivery-tail cleanup in the invoking host operation's +post-teardown result. + +The reported cleanup status covers the workload and all lease resources that +can be removed while the result channel remains available. It cannot truthfully +cover the controller, private session channel, or other delivery-tail resources +needed to deliver that same event. Their cleanup is verified afterward and is +part of the invoking host operation's final result. + +### Ordering and Backpressure + +Output frames preserve the byte order read from the PTY master. The protocol +uses bounded buffers. A slow controller applies backpressure; Reploy does not +silently drop or reorder terminal bytes. Limits and timeout diagnostics are +explicit. + +PTY, endpoint, and lifecycle streams use independent bounded flow-control +windows. A stalled browser transfer cannot indefinitely block terminal output, +termination, or the authoritative lifecycle result. + +Host Reploy owns workload-output finalization; it never waits indefinitely for +workload cooperation. Once termination begins, it rejects new output surfaces, +performs bounded graceful shutdown followed by forced container stop, and +continues draining the PTY plus every existing endpoint stream. The immutable +session plan carries a finite output-finalization deadline. The initial +implementation may use a fixed host-owned value, but the effective value is +reported by `opened` and applies to workload shutdown, final buffered-byte +delivery, and controller backpressure. + +If every final byte is delivered and every output surface reaches EOF before +the deadline, Host Reploy emits `workload_outputs_finalized(drained)` only after +all earlier output has been consumed through its flow-control window. If the +deadline expires, or a runtime error makes complete delivery unverifiable, +Host Reploy forcibly closes the remaining surfaces and emits +`workload_outputs_finalized(failed, reason)`. The multiplexing layer guarantees +that no output frame can follow either outcome. Failure is explicit and cannot +be converted into successful completion by `complete` or terminal +acknowledgement. + +The barrier covers every workload-originated output surface declared by the +session plan. Initially these are the PTY and forwarded endpoint streams. A +future workload output-file or output-directory contract joins the same +barrier after its files are closed, validated, and published or have recorded +an explicit failure; protocol v1 does not otherwise speculate about file +payloads. + +Every endpoint byte frame in either direction carries its `stream_id`. Host +Reploy assigns that ID only after the endpoint connection succeeds, never +reuses it within the session, and rejects data or closure operations for an +unknown or already closed ID. The logical `endpoint_id` remains the capability +being exercised; it is not sufficient to distinguish concurrent connections +to that endpoint. + +The initial implementation also enforces fixed Host Reploy maxima of 32 active +streams per logical endpoint, 64 active endpoint streams per session, and 64 +new endpoint streams per second per session with a burst of 128. Reploy reserves +capacity before dialing or allocating stream state and releases it when the +stream closes. An excess `open_endpoint` request is not queued or dialed; it is +rejected immediately with a correlated `endpoint_open_failed` event whose code +is `resource_exhausted`. +Blueprints and controllers cannot raise these host-owned limits. A future +general Reploy configuration surface may make them operator-configurable after +concrete use cases justify that surface. + +A PTY merges standard output and standard error. The contract does not pretend +to recover separate streams. + +### Resize + +The initial dimensions are part of session creation. A resize request applies +the platform PTY resize operation. Normal terminal behavior, including +`SIGWINCH` delivery to the foreground process group, follows from that +operation. + +### Ctrl-C and Signals + +Ctrl-C that belongs in a recording is ordinary PTY input byte `0x03`. The +remote terminal driver handles it normally, so echo such as `^C`, foreground +process signaling, shell behavior, and resulting output are observable and +recordable. + +Administrative cancellation is distinct from recorded input. The public +protocol exposes bounded termination, not arbitrary numeric signals. Host +Reploy uses a fixed grace period followed by forced container termination. + +### Session Ownership + +The initial protocol has one controller, no detach, no reconnect, and no +ownership transfer. Loss of the controller connection begins bounded +termination. Future reconnection would require a separate authorization and +output-replay design. + +## Protecting the Session Channel + +Untrusted workload code must not be able to read, write, inherit, duplicate, +or impersonate the control connection. + +The session channel exists only between the intended controller and the +attached Host Reploy operation. It is never mounted into the workload +container. Its handshake binds the connection to the host-created lease, exact +generation, protocol version, fixed capability set, and expected controller +identity. Server-side checks enforce every operation; an opaque or private +endpoint is not treated as authorization by itself. + +The initial Linux transport is one Unix-domain socket in a fresh, +lease-private host directory mounted only into the controller. Filesystem +ownership and mode restrict access to the effective controller identity. The +controller establishes one multiplexed connection, after which Host Reploy may +remove the socket pathname. No endpoint path, token, or descriptor appears in +the workload container, image metadata, or workload environment. + +Host Reploy owns the Docker TTY attachment, keeps control framing separate from +terminal bytes, and performs all signaling and process-tree teardown. The +workload container contains no trusted session shim and no control descriptor +for same-UID or root workload code to inspect or interfere with. + +Hostile terminal output remains opaque bytes. JSON text, terminal escape +sequences, fake exit messages, and protocol-looking output cannot create +control or lifecycle events. + +Root workload code has more authority inside its own container, but it still +cannot reach the host-controlled session channel. A forged terminal message, +workload exit, or closed endpoint stream cannot become an authoritative +successful termination. + +## Runtime Identity + +### Effective Runtime Identity + +Every Reploy application runtime container uses the ordinary Reploy runtime +identity: + +- staged execution uses the invoking host user's numeric identity; +- installed user-scope execution uses the invoking host user's numeric + identity; +- installed system-scope execution uses the host account explicitly selected + by `environment.install.system.account`, resolved to its numeric identity. + +Using the invoking identity for user-scope execution preserves ordinary host +file ownership and avoids predictable permission failures. The container +image's configured `USER` is not the runtime authority, and the image does not +need a matching named account. Reploy passes the effective numeric `UID:GID` +and the host account's supplementary GIDs, then supplies its ordinary transient +writable home. A non-root account with a root primary or supplementary group is +rejected rather than importing privileged host group membership into the +container. + +A controlled-session client inherits this identity and cannot override it. A +different system-scope identity is an installation configuration decision, not +a session capability. + +### Root Runtime Identity + +Root applies when the effective runtime UID is `0`: because staged or +user-scope Reploy was invoked as root, or because a system-scope installation +explicitly selected root. It is never inherited merely from the base image's +configured `USER`. + +A root runtime identity emits a warning equivalent to: + +> The application will run as root inside its container. Root can bypass +> application-level file permissions. Host input and shared-state mounts are +> prohibited. Explicit root output contracts require their separately reviewed +> safeguards. Network access and Linux capabilities remain restricted unless +> separately granted. + +A root runtime identity does not imply: + +- Docker or daemon access; +- privileged container mode; +- additional capabilities; +- host input or shared-state mounts; +- public or local networking; +- access to other sessions or deployments. + +Additional Linux capabilities, if ever supported for application runtime +containers, are separate explicit grants and require their own threat analysis. + +## Source and Filesystem Access + +No host path is visible by default. + +Non-root application containers may receive explicitly declared read-only or +writable host binds from the effective Reploy runtime plan. Writable binds +support declared configuration, data, and output paths. They are not arbitrary +paths selected through a command or session protocol, and Reploy validates that +the effective runtime identity can use them safely. + +The ordinary source grant is an explicit read-only bind mount rooted at an +approved project directory. A client cannot turn it into an arbitrary host-path +selector through the session protocol. Original project source is never exposed +through a writable bind. + +Root inside any Reploy application container may not receive host input or +shared-state binds, including read-only binds. Read-only prevents modification +but does not make exposed content confidential from container root. Reploy +validates the complete effective mount plan and rejects the operation before +contacting Docker if a prohibited bind source would be visible. A separately +validated output-only bind is a narrow explicit result grant, not general host +filesystem authority. + +Root application containers may use image content, Docker-managed volumes, +tmpfs, or a disposable copied workspace because those do not expose the +original host path. An existing Docker-managed volume is allowed only when the +effective environment plan already declares it; no command or session request +may select an arbitrary volume by name. Root can read, mutate, and change +ownership throughout an authorized persistent volume. Fresh scratch storage is +Reploy-owned and scoped to the operation or lease. + +Until disposable copied workspaces are implemented, a root operation that +needs local project source is unsupported rather than weakened with a host +bind. + +This is an explicit global application-runtime policy, independent of the +Docker daemon's UID mapping. Additional bind categories require a later design +decision justified by a compelling use case; they are not implementation escape +hatches. + +The original project source is never writable by a Reploy application runtime +container. Workloads, recordings, or agents that require source mutation must +use an explicitly requested disposable writable copy. A portable writable-copy +implementation is a separate design. Likely implementations include an +ephemeral copied volume, a temporary image plus container layer, or a +platform-specific copy-on-write filesystem. + +### Explicit Runtime Outputs + +The existing `reploy app --output-file` and `--output-dir` contracts remain +supported. They are intentional, caller-authorized result channels and are not +replaced by the provider store or disposable session scratch. + +The controller container is a Reploy application runtime and uses the same +contract for controller-owned artifacts such as asciinema casts, screenshots, +and rendered media. Its immutable session plan carries the prevalidated output +destination into the controller runtime plan; the workload does not receive +that mount. OmegaFlow finalizes and closes those files before sending +`complete`, and ordinary container teardown leaves the host output intact. The +session protocol therefore needs no artifact-transfer operation or separate +publication mechanism. + +For a non-root runtime identity, the existing direct output bind remains an +explicit host-filesystem grant. A root-safe output-only contract is separate +global pre-release work rather than controlled-session behavior. Until that +work lands, Reploy rejects root with either output option before contacting +Docker. + +The target root `--output-file` contract retains fresh private staging, +single-regular-file validation, race-free atomic publication without overwrite, +and interruption recovery. It additionally requires a focused review of link +behavior plus ownership and mode normalization before publication. The target +root `--output-dir` contract permits a direct bind only to an explicitly +selected, initially empty dedicated directory and defines ownership +normalization and failure retention. Neither output exception grants access to +the destination parent, source, configuration, staging state, or unrelated host +data. + +### Sensitive Path Masks + +Every source grant supports exclusion masks. Reploy always protects any exposed +deployment `.env` and `.reploy` path using its existing private-runtime mask +rules. A project-source grant additionally masks `.env` and `.reploy` at the +granted source root by default. The effective runtime plan may add validated +relative file or directory masks for project-specific sensitive material. + +Mask planning must: + +- reject absolute and escaping paths; +- resolve host symlinks defensively; +- distinguish files and directories; +- apply masks to every visible alias of a parent bind; +- reject conflicting nested mount types; +- snapshot and revalidate realized mount sources immediately before creation; +- fail closed when a mask cannot be enforced. + +Read-only source does not replace masking: root inside a container may read a +read-only sensitive file. + +## Secrets and Environment + +Host process environment is never inherited wholesale. + +Blueprint variables remain interpolation values, not automatic workload +environment variables. Deployment-local `.env` values continue to use +Reploy's private one-shot environment injection. The host file is not mounted +and is masked from every visible parent bind. + +A runtime operation may narrow explicitly declared environment inputs but +cannot invent additional ones. Names and values must not appear in image +metadata, container configuration, Docker command lines, build locks, Reploy +state, or generated diagnostics. Workload output is untrusted; Reploy cannot +prevent a workload from printing values it receives. + +OmegaFlow remains responsible for deciding which capture artifacts may be +published. Reploy provides bounded private output mechanisms, not +media-specific allowlisting. + +## Network and Endpoints + +All Reploy application runtime containers default to: + +- public Internet disabled; +- local network disabled. + +These are independent policy switches. A controlled workflow applies them +separately to the controller and workload environments. Local +denial includes host gateways, Docker peers outside the granted operation, +loopback redirection, private and link-local address ranges, IPv6 local ranges, +and infrastructure metadata endpoints. + +A controller may receive an explicit session-local grant to a declared +workload endpoint. That grant is not treated as general local-network +access. + +The first OmegaFlow prototype needs only: + +```text +controller browser -> Host Reploy -> one declared workload HTTP endpoint +``` + +The controller and workload do not share a Docker network. Docker publishes +only the declared workload port to an ephemeral host-loopback port. A +controller-local adapter accepts Chromium connections on controller +loopback and multiplexes their byte streams over the private session channel. +Host Reploy maps the fixed logical endpoint identity to the loopback-published +port. The protocol accepts no raw host, IP address, port, or URL destination. +The workload cannot use this one-way forwarding path to reach the controller. + +The loopback-published port is never disclosed to the controller, but any local +host process that discovers it may connect while the session is active. The +initial implementation accepts this host-local exposure; its session grant +constrains the controller, not unrelated host processes. It must not claim +per-lease endpoint privacy on a multi-user host. The port, adapter streams, and +associated Docker state remain lease-owned and are removed with the session. +The future L3 policy gateway must eliminate this direct host reachability or +enforce equivalent per-lease access control. General public/local network denial +remains a separate prerequisite; this endpoint forwarding path is not a general +router, HTTP policy engine, or domain-aware firewall. + +General network isolation and auditability are a separate design surface. +Future work may include an HTTP/HTTPS proxy, destination policy, controlled +DNS, and agent-sandbox audit records. HTTPS `CONNECT` can filter and audit a +destination hostname without TLS interception, but cannot inspect encrypted +URLs or content. Direct egress must be blocked to prevent proxy bypass. +Redirects, DNS rebinding, CDNs, WebSockets, QUIC, and workload-to-network +policy require explicit treatment. + +Until that design is implemented, rough public and local kill switches must +fail closed and must not be described as domain-level isolation. + +## Browser and Terminal Placement + +For the OmegaFlow profile: + +- orchestration runs in the controller container; +- asciinema and the session client run in the controller container; +- Playwright and Chromium run in the controller container; +- Host Reploy owns the Docker TTY attachment and external session supervision; +- the shell runs on the Docker-managed PTY in the workload container; +- the demonstrated web service runs in the workload environment; +- Chromium reaches that service only through its controller-local adapter and + the one granted Host Reploy endpoint stream. + +Terminal-to-browser handoff is an OmegaFlow orchestration concern inside the +controller. Reploy does not model beats, handoffs, browser actions, or capture +state. It provides only the PTY, endpoint, network, and lifecycle primitives. + +## Asciinema Integration + +OmegaFlow retains asciinema as the initial terminal recorder. It records a +local Reploy session-client command: + +```text +asciinema +└── Reploy session client in the controller + ⇄ private session channel + ⇄ Host Reploy external supervisor + ⇄ Docker TTY attachment + ⇄ workload shell +``` + +The proxy forwards input bytes, output bytes, resize operations, and terminal +completion. This keeps asciinema and recording dependencies out of workload +images while preserving the existing cast format and controller ownership. + +The prototype must test: + +- absence of double input echo; +- raw and canonical terminal modes; +- ordinary Ctrl-C behavior and recording; +- initial dimensions and resize propagation; +- byte ordering and timing; +- headless capture; +- large-output backpressure; +- abrupt loss of the controller, workload, Host Reploy, or Docker + observation. + +OmegaFlow may later write casts directly from session events, but that is not +required by this design. + +## Lifecycle and Verified Termination + +Host Reploy serializes every session through one state machine: + +```text +preparing -> active -> terminating -> terminated +``` + +The first accepted termination cause is latched and never rewritten. Causes +include controller-requested termination, workload exit, host cancellation, +controller loss, Docker-observation loss, and startup failure. Later events +remain diagnostic observations. Workload status, controller finalization +status, and pre-delivery cleanup success are reported separately in the session +result, so a cleanup failure can fail the operation without hiding its original +cause. Controller exit and delivery-tail cleanup are reported separately by the +invoking host operation after teardown. + +Channel closure is never successful completion. The controller must explicitly +send `complete` after receiving `workload_outputs_finalized` and finalizing its +client-owned results; for OmegaFlow these include the recording artifacts. +Repeated terminate or host cancel operations are idempotent. Input, resize, and +new endpoint streams are rejected after `terminating` begins. A single +`complete` remains valid during termination while Host Reploy is waiting for +controller finalization. A `failed` workload-output result makes the session +fail regardless of whether the controller preserves and finalizes partial +artifacts. + +Normal completion is: + +1. Host Reploy observes workload exit, or a controller or host operation + requests termination. +2. Host Reploy atomically latches the cause and enters `terminating`. +3. Host Reploy performs bounded graceful termination followed by forced + termination when necessary. +4. Host Reploy independently observes the exact workload container stopped. +5. Host Reploy drains and closes every declared workload-output surface under + the finite output-finalization deadline, then emits the one ordered + `workload_outputs_finalized` outcome. +6. Host Reploy gives the live controller a bounded finalization period in which + to close its client-owned output and send `complete`. A failed output outcome + remains a session failure even when partial client artifacts are finalized. +7. Host Reploy removes the workload container, endpoint publication, temporary + mounts, networks, and every other lease resource not required to deliver the + final result. It keeps the controller and private session channel alive. +8. Host Reploy records the original cause, controller-finalization result, + workload status, controller protocol status, and pre-delivery cleanup result, + then emits the one authoritative `terminated` event. Only successful event + delivery arms the acknowledgement wait. +9. Host Reploy waits for a bounded `acknowledge_terminated` response. Channel + closure is not an acknowledgement. Timeout or disconnect does not block + teardown. +10. Host Reploy closes the channel, stops and removes the controller, removes the + remaining delivery-tail resources, and independently verifies that cleanup. + A failure here fails the invoking host operation and is persisted for + reconciliation; it cannot be reported over the channel being removed. + +A controller disconnect latches `controller_lost` and starts the same teardown. +A workload exit is reported to the still-live controller so it can finalize +its client-owned results; the session cannot succeed if the controller +disappears before that finalization. Neither terminal output nor an +endpoint-stream close can substitute for host-observed Docker state. + +### Session Watchdog + +Host Reploy starts one short-lived watchdog for each live controlled session. +It first creates inert Docker resources and durably records their exact +identities. Before starting either container, it passes the watchdog an +immutable cleanup manifest containing the exact lease, container, endpoint, +network, volume, and host boot identities. The attached operation retains one +end of a private parent pipe. A crash during inert resource creation leaves no +untrusted code running and is handled by ordinary next-operation +reconciliation. + +Successful verified delivery-tail cleanup disarms the watchdog. Unexpected +process death, including `SIGKILL`, closes the pipe in the operating system and +causes the watchdog to stop, forcibly terminate when needed, remove, and verify +only the manifested resources. The watchdog exposes no listener, accepts no +later resource selection, and exits after verified cleanup. Although its +underlying Docker connection has ordinary trusted-host authority, its code path +is limited to the immutable resource set. + +If Docker is unavailable, the watchdog retries until Docker returns or the host +reboots. If both the attached operation and watchdog are killed, durable labels +and deployment-scoped live-run state let the next locked Reploy operation +reconcile the abandoned resources. This final fallback is eventual rather than +immediate. + +### Docker Restart and Host Reboot + +Controlled-session containers use no Docker restart policy. That alone does not +end a session during a Docker daemon restart because Docker live-restore may +keep both containers executing while management, attach, events, input, or +networking are unavailable. + +Loss of authoritative Docker observation therefore immediately latches +`runtime_observation_lost`, fails the recording, and closes its session and +endpoint streams. The session is never resumed or accepted as valid after +observation returns. Host Reploy and the watchdog retry Docker access and +forcibly remove any survivors when control returns. Immediate termination while +Docker itself is unreachable is not promised. + +A real host reboot ends the processes. The no-restart policy prevents their +automatic return, and prior-boot queue entries are discarded under Reploy's +existing boot-session admission rules. + +## Staging and Generation Semantics + +Basic preflight validation uses the existing `reploy validate` behavior. +Creating a session requires a successfully staged and built current generation. +The session is pinned to that generation for its complete lifetime. + +Updating a staging directory with the same environment follows ordinary +stage-update behavior. Attempting to stage a different environment into the +same directory is rejected by default. + +An explicit forced replacement: + +- stops and removes Reploy-managed runtime resources for the old environment; +- replaces Reploy-managed staging state; +- stages the new environment; +- preserves user-owned files such as overrides, private environment + configuration, and unrelated paths; +- never treats force as permission to recursively delete the staging + directory. + +A generation update never retargets a live controlled session. + +## Audit and Diagnostics + +Reploy records security-relevant facts without recording secret values: + +- session and lease identity; +- deployment and generation; +- effective runtime identity and whether it is root; +- capability names; +- mount targets and mask identities, without secret file contents; +- network policy class and granted endpoint identities; +- lifecycle transitions, cancellation, timeout, and recovery actions; +- exit status and structured failure codes. + +Terminal content belongs to the controller's private output stream and is not +duplicated into Reploy audit metadata. + +Diagnostics identify which operation failed, what Reploy attempted, whether +the session channel or Docker lifecycle was observed, what cleanup ran, and the +safe next action. + +## Resource and Timeout Policy + +Controlled sessions have explicit limits for: + +- startup and handshake; +- idle or total session duration when requested by policy; +- termination grace; +- buffered terminal output; +- controller request size; +- active endpoint streams and endpoint-open rate; +- process, memory, CPU, and temporary-disk resources where supported. + +Limit failures produce a structured diagnostic. Endpoint-admission limits +reject only the excess request as specified above; a timeout or session-wide +resource failure that makes safe continuation impossible produces bounded +teardown. A timeout never converts into successful completion. + +## Implementation Plan + +The initial implementation uses Linux containers under Docker, but it is not +one prototype megaslice. Each slice receives focused assertions, tests, review, +and a separate commit. + +### Slice 1: Global Sandbox Prerequisites + +Apply the approved identity, seccomp, `no-new-privileges`, capability, +namespace, device, mount, mask, secret, network, and root rules consistently to +ordinary Reploy application containers. Prove staged workloads, installed +workloads, transient commands, shells, and later controlled sessions consume +the same baseline. This is global runtime work, not controlled-session code. + +### Slice 2: Controlled-Session Lifecycle Core + +Using synthetic controller and workload images with networking disabled: + +- validate one immutable plan and admit its exact generation; +- start both containers without giving the controller Docker access; +- establish the private controller channel and external Docker TTY supervision; +- implement ordered terminal bytes, initial dimensions, resize, ordinary + Ctrl-C, bounded termination, exit status, and bounded backpressure; +- implement the host-owned state machine and authoritative terminal result; +- prove hostile terminal output and connection closure cannot forge lifecycle + success. + +### Slice 3: Crash Containment + +Add the session-scoped watchdog, immutable cleanup manifest, labels, +reconciliation, and idempotent teardown. Test controller death, workload +death, Host Reploy `SIGKILL`, watchdog interruption, Docker daemon restart with +live-restore, Docker unavailability, and host-reboot recovery without touching +unrelated resources. + +### Slice 4: Declared Endpoint Forwarding + +Add the controller-local adapter and Host Reploy forwarding to one exact +host-loopback-published workload endpoint. Prove Chromium can use HTTP and +WebSocket streams while the workload cannot reach the controller and neither +container receives unrelated local or public access. Keep general proxy, DNS, +domain, redirect, QUIC, and audit policy outside this slice. + +### Slice 5: OmegaFlow Proof + +Integrate OmegaFlow, asciinema, Playwright, and Chromium only after the generic +session slices pass. Prove one persistent shell across multiple operations, +faithful Ctrl-C recording, resize, terminal-to-browser handoff, explicit +recording finalization into the controller's declared Reploy output destination, +survival of that output across teardown, and actionable failure diagnostics. + +### Slice 6: User-Facing Documentation + +After the generic runtime and at least one integration profile are proven, +publish user-facing documentation before public release. Explain the +controller/workload model and trust boundary, how to create and run a +controlled session, the capability, endpoint, output, lifecycle, and failure +contracts, and the security defaults and limitations. Include focused examples +for OmegaFlow recording, sandboxed agents, and security inspection without +presenting any one profile as the controlled-session abstraction itself. + +### Independent Pre-release Runtime Fixes + +The admission promotion-versus-cancellation invariant and root-safe +`--output-file`/`--output-dir` contracts are separate global backlog slices. +Controlled sessions consume their completed behavior and do not grow private +variants. Until root output work lands, that combination is rejected clearly. + +The initial implementation does not include domain filtering, remote +execution, reconnection, persistent caches, writable source copies, or multiple +concurrent sessions per controller. + +## Deferred Designs + +### Reploy Repositories and Portable Tools + +Define and implement the independently updated, federated repository mechanism +and its portable tool surface for capabilities such as Java and Playwright in +[`REPOSITORY_DESIGN.md`](REPOSITORY_DESIGN.md). +This is a controller packaging dependency, not part of the session transport or +lease protocol. + +### Network Isolation and Audit + +Define general public and local kill switches, direct-egress enforcement, proxy +behavior, DNS control, IPv6, metadata protection, and auditability as a +separate Reploy/agent-sandbox design. The one-way, exact endpoint forwarding +used by the initial controlled session is intentionally narrower than that +future surface. + +### Disposable Writable Workspaces + +Define portable snapshot or copy semantics, cost, ownership, exclusions, +cleanup, persistence boundaries, and failure recovery. The original source +must remain immutable. + +### Cross-platform Session Transport + +The first protocol uses Linux/Docker primitives. Windows named pipes, macOS and +Docker Desktop behavior, rootless runtimes, and Podman require platform +evidence before becoming supported contracts. + +### Elevated Application Capabilities + +Root identity is supported globally, but additional Linux capabilities and +administrative demonstrations need separate explicit grants and threat +analysis. Privileged application containers remain outside this design. + +## Consequences + +- Controllers can drive exact Reploy environments without receiving general + host authority. +- OmegaFlow retains ownership of recording behavior and dependencies. +- Reploy gains a primitive useful for agent sandboxes and other controlled + execution clients. +- Controlled sessions reuse the global application-runtime sandbox instead of + defining an OmegaFlow-only security tier. +- Host Reploy remains in both the PTY and lifecycle paths; the containers do not + receive a direct control connection to one another. +- Staged and installed user-scope application containers retain practical host + ownership by using the invoking host identity, which may be unnamed inside + the image. +- Installed system-scope application containers use the configured host + service account's numeric identity without requiring a corresponding + container-local username. +- Root application containers are possible but visibly weaker. +- Root application containers never receive host input or shared-state binds; + local source requires the separately designed disposable-copy capability. + Explicit root output-only binds remain unavailable until their separate + pre-release contract is reviewed and implemented. +- Strong default network denial and arbitrary sensitive-path masks require new + implementation work. +- Disposable writable source is intentionally more expensive and deferred. +- Verified termination requires independent runtime observation; session + protocol success alone is never sufficient. diff --git a/docs/FUTURE_DIRECTIONS.md b/docs/FUTURE_DIRECTIONS.md index ab77a750..9f47fc8f 100644 --- a/docs/FUTURE_DIRECTIONS.md +++ b/docs/FUTURE_DIRECTIONS.md @@ -30,29 +30,13 @@ Open questions: - How should unsupported deployment operations fail on otherwise supported CLI platforms? -## Blueprint Index +## Reploy Repositories -The blueprint index may evolve toward an `apt-get update` style workflow: a -cached local catalog used for shorthand resolution, discovery, search, and -possibly trust metadata. - -Possible commands: - -```text -reploy index update -reploy index search arbiter -reploy index show arbiter-server -``` - -Open questions: - -- Should the index remain a simple JSON catalog or become a richer signed - metadata source? -- Should index entries include app ids, descriptions, supported platforms, - latest versions, and blueprint package refs? -- Should search work offline from the cached index? -- What trust or verification model is needed before installing from indexed - shorthand names? +The former blueprint-index direction has been superseded by the unified, +multi-asset Reploy repository design. Repositories publish versioned blueprints +and portable tool definitions through one TUF-authenticated index, with +explicit surface trust and APT-like update behavior. See +[`REPOSITORY_DESIGN.md`](REPOSITORY_DESIGN.md). ## Deployment Environments @@ -200,8 +184,8 @@ reploy install git:https://github.com/org/repo.git#package_name/reploy/app.bluep Open questions: -- Should a future blueprint index map Reploy versions or app versions to - upstream commit hashes? +- Should published blueprint provenance map Reploy versions or application + versions to upstream commit hashes? - Should additional provider schemes be added for GitLab or Bitbucket after there are fixtures and parser tests for their URL layouts? - If GitLab is supported, how should Reploy handle nested groups without diff --git a/docs/REPOSITORY_DESIGN.md b/docs/REPOSITORY_DESIGN.md new file mode 100644 index 00000000..4edcf7f0 --- /dev/null +++ b/docs/REPOSITORY_DESIGN.md @@ -0,0 +1,1138 @@ +--- +status: Draft +updated: 2026-08-01 +summary: Federated, TUF-authenticated Reploy repositories for published blueprints and portable tool definitions. +--- + +# Reploy Repository Design + +## Status + +- Decision state: High-level policy decided; wire schemas require focused review +- Implementation state: Not started +- Initial tool examples: `tool:java` and `tool:playwright` + +This document defines one repository protocol for versioned Reploy assets. The +initial asset surfaces are published blueprints and portable tool definitions. +It also defines how direct Blueprint URLs coexist with repositories, how +repository and publisher trust compose, and which data becomes part of a +deployment rather than remaining dependent on a global cache. + +## Decision Summary + +- A Reploy repository is one static, mirrorable, TUF-authenticated publication + that may contain both blueprints and tool definitions. +- Reploy operates an official repository, but the protocol is open and other + organizations may operate independently trusted repositories. +- Every repository has one TUF trust domain. Clients grant it authority for + explicit asset surfaces such as `blueprints` or `tools`. +- The repository owns an authenticated publisher authorization list. Clients + do not maintain per-publisher, per-namespace, or per-asset grants inside an + already authorized surface. +- Every published blueprint and tool definition carries a detached publisher + DID attestation over its exact immutable contents. TUF authenticates + repository inclusion; the DID signature authenticates authorship. +- Repository trust is APT/PPA-like: repositories are configured independently, + may publish overlapping qualified names, have mutable priority, and may be + pinned explicitly. TUF supplies the authentication and update security. +- Published assets are versioned and immutable. Blueprints and tools use one + shared version-scheme, release-revision, selection, locking, and lifecycle + model. +- Current publisher authorization controls new publication only. Historical + releases remain attributable through their publisher attestations and + repository acceptance records. +- Blueprints and tools share yank, archive, delete, publisher-security + revocation, rescission, purge, and ownership-transfer lifecycle rules. +- Direct `file:`, `pypi:`, `github:`, and other supported BURLs remain a + first-class low-friction path. Remote direct sources warn about missing + repository evidence; the warning does not tell consumers to publish. +- Repository index refresh is explicit through `reploy repository update`. + Update downloads authenticated metadata and indexes, not asset definitions or + payloads. +- Once selected, the exact blueprint or tool definition, publisher attestation, + and repository acceptance record are retained in the deployment-owned + provider-store closure. The global immutable object cache is acceleration + only and may be evicted safely. +- The ordinary `reploy` executable is consumption-only. Publisher signing and + repository administration are separate privilege domains implemented by two + separately distributed tools. +- Tool definitions are declarative data interpreted through reviewed + Reploy-owned primitives. They cannot contain arbitrary commands, scripts, + package-manager expressions, or generic download instructions. + +## Terminology + +- **Git repository**: an authoring source controlled with Git, whether hosted + by GitHub or another service. +- **Reploy repository**: one logical TUF-authenticated publication of Reploy + assets. Avoid bare `repo` where it could mean a Git repository. +- **Repository source**: a URL-shaped transport locator for a Reploy + repository. It is not the repository's permanent identity. +- **Repository index**: the authenticated, machine-readable inventory of + published asset identities, versions, lifecycle state, compatibility, and + immutable target digests. There is no separate catalog concept. +- **Asset surface**: a client-authorized repository capability. The initial + surfaces are `blueprints` and `tools`. +- **Published asset release**: one immutable version and Reploy revision of a + blueprint or tool definition, together with its detached publisher + attestation and repository acceptance record. +- **Publisher DID**: a DID Core identifier whose keys authenticate an asset's + detached publisher signature. +- **Mirror**: another transport endpoint serving the same authenticated Reploy + repository. +- **BURL**: a direct Blueprint URL such as `file:`, `pypi:`, or `github:`. A + BURL locates a blueprint directly rather than selecting it from a trusted + repository index. + +## Context + +Reploy currently has two distribution pressures: + +1. Application users need a short, durable way to discover, install, and update + published blueprints. +2. Portable tools such as Java and Playwright need independently updated, + reviewable build and runtime definitions that should not be hard-coded into + each Reploy release. + +The former shorthand index was only a pointer list. A real repository asserts +more: it retains immutable blueprint releases, validates them before +publication, authenticates the publisher, and supports lifecycle operations. +The tool design independently required authenticated indexes, immutable +definitions, repository trust, and offline transfer. Maintaining two protocols +would duplicate trust and distribution machinery while making repository +terminology harder to understand. + +One multi-asset repository provides the shared trust, identity, versioning, +publication, search, and update layer. Blueprint semantics and tool semantics +remain distinct asset contracts within it. + +## Goals + +1. Make published blueprints and portable tools discoverable, authenticated, + versioned, updateable, and lockable through one protocol. +2. Preserve explicit repository and publisher provenance without putting + Reploy in the business of centrally verifying every real-world identity. +3. Support independently operated repositories, static hosting, mirrors, and + deliberate offline transfer. +4. Preserve a direct BURL path for development, personal deployment, and + deliberate user installation. +5. Keep deployment replay independent of global repository cache retention. +6. Update downstream tool knowledge independently from Reploy binaries. +7. Keep tool definitions declarative and materially smaller than a generic + package manager or arbitrary build system. +8. Generate useful user and publisher documentation from validated repository + records. + +## Non-goals + +The initial protocol does not: + +- centrally author, repair, fork, or supplement third-party application + blueprints or per-project build recipes; +- publish application binaries or locally built package artifacts; +- make repository publication mandatory for staging or installation; +- infer trust from a blueprint, tool definition, namespace, source priority, or + untrusted search result; +- implement a web of trust or reputation score across publisher DIDs; +- define a plugin or executable-extension system; +- accept arbitrary commands, scripts, hooks, package-manager expressions, or + generic download schemas from repository assets; +- guarantee support for packages that perform undeclared dynamic downloads; +- implement a general build-network escape hatch. + +Repository maintainers decide what they publish and may maintain third-party +blueprints, but Reploy itself does not become a Conda-Forge-like central owner +of downstream project recipes. This preserves +[`ADR 0001`](adr/0001-local-source-build-recipes.md). + +## Asset Model + +### Published Blueprints + +A published blueprint release contains the exact blueprint document, detached +publisher attestation, and repository acceptance record. Its qualified name, +upstream-facing `blueprint.version`, packaging revision, content digest, +publisher DID, repository identity, and repository snapshot identity are +retained through resolution and installation. + +Repository publication performs strict static blueprint parsing, schema and +semantic validation, reference validation, and policy checks without executing +untrusted project code. A repository may additionally require CI image builds +or other tests as publication policy, including stronger checks for less +trusted publishers, but those dynamic checks are not a universal protocol +requirement. + +Repository publication retains each accepted immutable blueprint release until +an explicit lifecycle operation changes its availability. The repository does +not merely point at a moving external blueprint. + +### Portable Tool Definitions + +A portable tool definition is a strict, versioned data record that maps one +portable capability onto supported target systems and Reploy-owned +implementation primitives. Concrete tool definitions are repository data, not +compiled into the Reploy executable. + +The Reploy client contains only supported definition schemas, trusted resolver +and materialization primitives, validation, provider composition, caching, and +locking behavior. An official definition may be updated independently of the +client as long as the consuming Reploy version understands its schema and named +primitives. + +The publisher of a tool definition is its Reploy definition maintainer, not +necessarily the upstream software vendor. Upstream vendor, source, licensing, +and artifact provenance are recorded separately. + +### Direct Blueprint Sources + +Direct BURLs remain first-class. A user may stage or install a supported +`file:`, `pypi:`, `github:`, or other BURL without discovering, configuring, or +trusting a Reploy repository first. + +An explicit local `file:` BURL shows resolved provenance but does not emit a +trust warning: the user deliberately selected local content. A direct remote +BURL outside a trusted repository reports the missing trust evidence +factually. It does not suggest that the consumer publish the blueprint or add a +repository. Repository publication is promoted through publisher-facing +documentation and publisher tooling instead. + +A direct remote source may contain an adjacent detached `attestation.json`. +When present, Reploy verifies the attestation against the exact blueprint, +resolves the current publisher DID document, and requires the attestation key +to remain authorized by that DID. A malformed, mismatched, invalid, or stale +rotated-out attestation is an error, not an unsigned fallback. A valid signature +establishes current publisher authorship but not repository acceptance, +historical key-binding evidence, or publication-validation evidence. Without +an attestation, Reploy warns that neither publisher identity nor trusted +repository publication was established. + +Automatic client-side resolution for such an untrusted attestation initially +supports only `did:web`. Reploy derives the method-defined HTTPS URL, requires a +hostname rather than an IP literal, and uses the system TLS trust store. Before +connecting it resolves the hostname and rejects the complete result if any +address is loopback, private, link-local, reserved, infrastructure metadata, or +otherwise not globally routable. The HTTPS connection is pinned to the +validated address while retaining the original hostname for certificate +validation, preventing a second DNS lookup from changing the destination. + +Resolution rejects every redirect and applies fixed response-size and elapsed- +time limits. The returned DID document must have an `id` exactly equal to the +requested DID. Reploy reads only the verification material needed for the +attestation and never dereferences `@context`, `service`, `alsoKnownAs`, or any +other URL found in the document. Unsupported DID methods fail with an explicit +diagnostic rather than invoking a generic resolver. A publisher without its own +domain may use a `did:web` document hosted beneath a service such as GitHub +Pages. + +This network resolution is specific to direct remote BURLs. For a selected +repository asset, the client validates the TUF-authenticated publisher +attestation and repository acceptance record retained with that asset; it does +not contact the publisher's current DID endpoint during ordinary resolution, +installation, build, or lock replay. + +Reploy locks the exact fetched content digest. That digest proves content +identity after retrieval; it does not establish trust in the retrieval source. + +## Repository Topology + +A Reploy repository is a static, mirrorable publication containing: + +1. standard TUF 1.x metadata; +2. one required authenticated `repository.json` identity target; +3. one required authenticated `publishers.json` authorization target; +4. one versioned repository index snapshot covering authorized asset surfaces; +5. immutable blueprint and tool-definition targets with detached publisher + attestations and repository acceptance records; +6. immutable lifecycle-event targets; +7. additional declarative objects referenced by supported tool definitions. + +Logical target paths remain friendly and versioned. These filenames are +illustrative; the exact asset-document filenames remain a schema detail: + +```text +blueprints/acme/editor/1.2.0/2/blueprint.yaml +blueprints/acme/editor/1.2.0/2/publisher-attestation.json +blueprints/acme/editor/1.2.0/2/repository-acceptance.json +tools/acme/playwright/1.55.0/3/tool.yaml +tools/acme/playwright/1.55.0/3/publisher-attestation.json +tools/acme/playwright/1.55.0/3/repository-acceptance.json +``` + +Content hashes live in publisher attestations, TUF target metadata, locks, and +internal content-addressed storage. When TUF consistent snapshots require +hash-prefixed physical filenames, publication tooling generates them without +changing the friendly logical names in the repository index. + +Supported repository sources include ordinary `https:`, configured `file:`, a +provider-specific `github:` form, mirrors, and `http:` only under the restricted +bootstrap rule below. GitHub Pages, GitHub Releases, object storage, internal +web servers, and removable media are transports rather than repository +identities. + +A Reploy repository is rooted by its repository descriptor rather than by a +version-control boundary. Its authoring source and generated publication may +live at a subdirectory of a Git repository, and one Git repository may contain +multiple sibling Reploy repositories. Each Reploy repository still has its own +descriptor, permanent repository ID, TUF root, canonical origin, and trust +domain. An HTTPS canonical origin includes the complete normalized base path, +not merely the scheme and host. + +Publisher and repository-maintainer tooling accepts an explicit repository +directory and does not require that directory to contain `.git`. Compilation +confines all repository input and generated output to that declared directory; +symlinks, archive entries, or references that escape it are rejected. + +## Repository Authentication and Trust + +### TUF Authentication + +Repository authentication follows +[The Update Framework 1.x specification](https://theupdateframework.io/spec/). +Reploy does not define a parallel repository-signing protocol. Every repository +publishes the required top-level roles: + +- `root` establishes repository keys, thresholds, and root rotation; +- `targets` authenticates the descriptor, publisher authorization, index, + immutable asset and acceptance targets, and lifecycle-event targets by path, + length, and digest; +- `snapshot` binds one consistent metadata view; +- `timestamp` establishes freshness. + +Consistent snapshots are required. Mirrors are untrusted transports; +acceptance depends on TUF validation rather than mirror identity or TLS alone. +TUF establishes repository authorization, integrity, consistency, and +freshness. Reploy still strictly validates every authenticated Reploy schema, +publisher relationship, compatibility constraint, and named primitive. + +`repository.json` is a required TUF-authenticated identity target. It contains +a strict schema version, opaque permanent `repository_id`, canonical origin, +user-facing `repository_name`, `display_name`, and an identity generation. The +repository ID is generated once from a cryptographically secure random UUID +when the repository is initialized. It is copied unchanged to every mirror and +never derives from a URL, name, owner, or signing key. A deliberate repository +fork receives a new ID. + +The repository ID is the authoritative stable identity. The authenticated +names make that identity recognizable to users but are not assumed to be +globally unique. They cannot change through an ordinary publication or catalog +update. A dedicated offline TUF delegated identity role authenticates +`repository.json` and versioned rename transitions. Repository-maintainer +tooling changes either name only through an explicit operation against the +repository authoring directory, for example: + +```bash +reploy-repository rename /path/to/repository \ + --name acme-platform \ + --display-name "Acme Platform" +``` + +The operation keeps `repository_id`, increments the identity generation, +records the previous and replacement names, and republishes the identity target +and transition through TUF. Clients accept a rename only when its transition is +authorized by the repository identity role and continues the locally trusted +repository ID and generation. They retain the authenticated name history, +reject rollback, and report the rename during `repository update`. A rename +does not require fresh repository trust. A later authenticated snapshot that +changes the repository ID or changes a name without such a transition is +rejected without replacing the last accepted local snapshot. + +### Surface Authorization + +Trusting a repository grants one or more explicit client-side asset surfaces. +Trust for `blueprints` does not authorize tools, and trust for `tools` does not +authorize blueprints. Repositories cannot widen those grants through their own +metadata. + +```bash +reploy repository trust URL --surface blueprints +reploy repository trust URL --surface tools +reploy repository trust URL --all-surfaces +``` + +Within an authorized surface, the repository owner decides which publishers +and namespaces it accepts. Clients do not maintain another per-publisher, +per-namespace, or per-asset allowlist. Priority and source pinning cannot bypass +surface authorization. + +The official repository may be configured with bundled Reploy trust policy. +Every external repository has its own root and must be trusted explicitly for +each desired surface. + +### Publisher Authorization and DID Attestations + +Every repository publishes an authenticated `publishers.json`. Each entry +binds one publisher DID to the surfaces and namespaces in which that publisher +may publish. Publication rejects a new release whose publisher, surface, +namespace, or signature does not match the current authorization. Client +validation of an already accepted release does not reapply the current +authorization list; otherwise ordinary removal or key rotation would +retroactively invalidate historical releases. + +Every published blueprint and tool definition has a detached publisher +attestation covering at least: + +- asset surface and qualified name; +- version scheme, asset version, and Reploy revision; +- exact document digest; +- publisher DID; +- the public verification method and public key used for the signature; +- publisher signature. + +Publication resolves the DID document and verifies that the signing key is +currently authorized for the publisher. It then creates an immutable repository +acceptance record covering at least the repository identity, qualified release, +asset and publisher-attestation digests, publisher DID and key fingerprint, +acceptance generation, static-validation policy, and the authorization facts +verified at acceptance time. TUF authenticates the asset, publisher attestation, +and repository acceptance record in one repository snapshot. The asset document +itself remains free of embedded signatures. + +The public key retained in the publisher attestation verifies the historical +signature. The TUF-authenticated repository acceptance record establishes that +the repository verified that key as belonging to the publisher DID when it +accepted the release. A repository therefore needs only current authorization +and current publisher keys in `publishers.json`; it does not need an unbounded +central ledger of every former publisher key. + +DID documents may expose keys and links to domains, GitHub accounts, or social +profiles so humans and repository maintainers can gather identity evidence. +The repository maintainer remains responsible for deciding which DID controls +a namespace. Reploy validates cryptographic statements but does not operate an +identity-verification service or infer transitive trust from how many other +parties recognize a DID. A web-of-trust or curated cross-repository reputation +service is a possible later extension. + +Removing or narrowing publisher authorization prevents future publication in +that scope. It does not silently yank, delete, archive, revoke, or otherwise +change already published immutable releases. + +### Initial Trust and Root Rotation + +The normal canonical bootstrap fetches the initial TUF root from the exact +HTTPS repository origin using the system trust store. Cross-origin redirects +are not accepted implicitly, and the authenticated repository descriptor must +identify that same canonical origin. HTTPS establishes current domain control; +explicit operator confirmation supplies the judgment that the origin is the +intended repository and authorizes the requested surfaces. + +Mirror bootstrap never requires contacting the canonical origin. Reploy fetches +the root, metadata, repository descriptor, and selected repository contents +entirely from the mirror. It validates their internal TUF consistency and shows +the transport URL separately from the authenticated canonical origin, +repository ID, names, and initial root fingerprint. The operator's explicit +confirmation trusts that root as the initial authority for the displayed +repository identity. The mirror's HTTPS identity authenticates only the +transport; after bootstrap, repository authenticity and root rotation depend +on the accepted TUF root lineage. Any other mirror presenting the same +authenticated repository ID and valid root lineage is interchangeable without +access to the canonical origin. + +The preview shows the repository URL, authenticated ID, display name, requested +surfaces, TUF root fingerprint, and initial-trust provenance. Examples include: + +```text +Initial trust: HTTPS domain control via system trust store +Initial trust: Local TUF root /path/to/root.json +Initial trust: Bundled Reploy policy +Initial trust: Administrator-managed system policy +``` + +Advanced bootstrap accepts standard JSON root metadata through `--root FILE` +or pins the fetched root with `--root-sha256 SHA256`. These provide stronger +out-of-band authentication for either canonical or mirror bootstrap but are not +required for an explicitly confirmed HTTPS mirror. A local root contains public +keys, role assignments, thresholds, version, expiration, and signatures, never +private keys. Plain HTTP requires an independently obtained root or exact root +digest; HTTPS-to-HTTP redirects are rejected. + +After bootstrap, only a valid sequential TUF root-rotation chain can change +repository signing authority. A later domain compromise alone cannot replace +the root with unrelated keys. + +### User and System Trust + +Repository trust is user-scoped by default and applies to that user's staging +and user-scoped deployments. `--system` creates administrator-managed +machine-wide trust for system installations. Repository listings show every +effective record and its scope because user and system records may grant +different surfaces or priorities. + +A system installation may rely only on system-scoped trust. It never silently +promotes user trust, including under `install --system --yes`. Automation may +perform the same explicit validated action non-interactively: + +```bash +sudo reploy repository trust https://repo.example \ + --surface tools --system --yes +``` + +`--yes` suppresses confirmation but does not bypass URL, TLS, TUF, root, +repository identity, publisher, surface, schema, or compatibility validation. + +## Names, Versions, and Repository Selection + +A qualified asset name contains a publisher namespace and asset name, such as +`acme/editor` or `acme/playwright`. In the compact selector +`tool:acme/playwright`, `tool:` identifies the asset surface and is not part of +the qualified name. The structured YAML form expresses the same distinction as +the `tool` field with value `acme/playwright`. Namespaces are repository-local: +the same qualified name may be authorized to different publisher DIDs in +different repositories. The globally unambiguous source identity is the +permanent repository ID, asset surface, and qualified name together. The +authenticated publisher DID is retained as provenance for that source identity. + +### Shared Asset Versioning + +Blueprints and tools use the same `VersionScheme`, version-requirement parser, +release-revision model, ordering, lifecycle targeting, lock representation, and +diagnostics. The implementation is shared rather than two similar surface- +specific implementations. User-facing labels may call the second coordinate a +blueprint packaging revision or a tool definition revision, but both are the +same Reploy revision field. + +Within one repository, every qualified asset name chooses one immutable +Reploy-supported version scheme: + +- `semver`: exact and ordered Semantic Versioning constraints; +- `pep440`: exact and ordered Python packaging version constraints; +- `integer`: exact and ordered integer constraints, such as Java levels; +- `opaque`: arbitrary upstream strings with exact equality only. + +Repositories cannot supply parsers or comparison code. Reploy does not add an +outer epoch or generation to version ordering. A scheme interprets its own +native epoch when it has one. Changing the scheme for an existing qualified +name is not an ordinary update; the initial protocol requires a new qualified +name, with any future cross-scheme migration requiring a focused design. + +Each upstream-facing version contains monotonically increasing positive integer +revisions starting at `1`. A revision corrects blueprint packaging or tool +definition data for that exact upstream version without inventing a new +upstream version. Ordering compares the scheme-native version first and the +Reploy revision second. Ecosystem package versions contributed by an asset are +provider-native inputs and remain separate from both coordinates. + +For ordered schemes, an omitted constraint selects the highest compatible, +non-yanked stable version and then its highest eligible revision. Prereleases +are excluded unless requested. An `opaque` identity has no ranges or implicit +ordering and must designate its compatible default explicitly. Existing locks +never follow a moving default. + +An exact upstream version still permits any eligible revision. The compact +selector `2.4.0~1` pins both version `2.4.0` and revision `1`; `2.4.0` alone pins +the version while selecting its newest eligible revision. Revision constraints +are valid only with an exact upstream version. Because some version schemes may +use `~` themselves, structured `version` and `revision` fields and equivalent +CLI options provide the unambiguous form. Repository records and locks always +store the two coordinates separately. + +New unconstrained resolution may select a newer upstream version and revision. +A range-constrained update may move within the range and then select the newest +eligible revision. An exact-version update may move only its revision. A request +that specifies both coordinates is fully pinned. Build, replay, and ordinary +repository-index refresh never move either coordinate; only an explicit +deployment update performs selection again. Every lock records the exact +version, revision, asset digest, attestations, and repository identity. + +Repository-backed blueprint discovery enables the short consumption path: + +```bash +reploy install omegaconf-inspector +``` + +The accepted local indexes determine the available blueprint candidates; the +command does not search or trust arbitrary remote repositories implicitly. + +An unqualified name resolves only when exactly one authorized qualified +identity matches. Otherwise Reploy lists the qualified candidates. Multiple +trusted repositories may publish the same qualified identity, just as multiple +APT sources may publish the same package. + +Repository priority is mutable user or administrator policy stored against the +permanent repository ID. For future resolution Reploy filters by surface, +authenticated repository acceptance, effective lifecycle state, compatibility, +and requested version and revision; applies any explicit source pin; otherwise +considers only the highest repository priority. An equal-priority tie between +repositories is a hard error. Reploy never breaks it using source order, +release revision, or content equality. + +### Cross-Repository Conflict Resolution + +Repository selection resolves every overlapping-source conflict explicitly: + +- An explicit repository pin selects the source. Otherwise the highest-priority + eligible repository wins, and an equal-priority tie fails. +- Before interpreting an unpinned version constraint, Reploy identifies the + version schemes declared by all otherwise eligible repositories. If they + differ, resolution fails and requires an explicit repository pin; repository + priority never silently changes the meaning of a version constraint. +- Within one repository, the version scheme of an asset identity is immutable. + An explicit repository pin selects that repository's scheme before the + constraint is parsed. +- Reusing one repository, qualified identity, version, and revision coordinate + for different content is rejected. +- If one publisher DID signs different content for the same qualified + coordinate across repositories, Reploy reports publisher equivocation as a + security error; repository priority does not hide it. +- Different repositories may authorize the same namespace and qualified name + to different publisher DIDs. Normal repository selection chooses the source; + the repository's authenticated acceptance record identifies the publisher. +- Yank, archive, delete, and security-revocation state affects only the + accepting repository's eligible lineage. Platform, Reploy-version, + dependency, or parameter incompatibility removes a candidate; when none + remain, resolution reports the incompatible requirements. + +Locks retain the selected repository, qualified name, publisher DID, version +scheme, exact upstream version, Reploy revision, and content identity, so later +policy changes cannot reinterpret an accepted result. + +A tool requirement may pin a repository explicitly: + +```yaml +requires: + - tool: acme/playwright + repository: https://tools.acme.com/ +``` + +The source must already be trusted for tools or enter the explicit trust +workflow. Pinning bypasses priority, not authentication, authorization, +compatibility, or version constraints. Existing locks retain their exact +repository and asset identity when priority later changes. + +A blueprint declares every external repository needed for unpinned tool +resolution; the official repository remains implicit. A pinned tool source +also declares that dependency and need not be duplicated: + +```yaml +blueprint: + schema: 1 + version: 0.1.0 + requires_reploy: ">=0.6" + tool_repositories: + - https://tools.acme.com/ +``` + +The declaration does not grant trust or assign priority. Interactive staging +may present the normal trust preview; unattended operation fails with the exact +trust command required. + +## Asset Lifecycle + +Lifecycle semantics apply equally to blueprint releases and tool-definition +releases unless stated otherwise. An operation may target one exact +version/revision release, every revision of one upstream version, or the complete +qualified identity. Publisher security revocation is publisher-wide. + +Every lifecycle transition is an immutable event retained as a TUF target. The +current repository index carries only effective state and the event identifiers +needed to explain it; ordinary clients do not download the complete history. +Repository-maintainer tooling consults the retained history to reject release +coordinate reuse, implicit ownership changes, and invalid transitions. Old +events remain available for audit after the TUF snapshots that first published +them expire. + +This is a repository-maintained append-only invariant. TUF authenticates the +published event records but does not prevent a malicious repository owner that +still controls its signing threshold from rewriting its own history. A public +transparency-log system is a possible later extension, not an initial protocol +requirement. + +### Yank + +Yanking follows PyPI/PEP 592 semantics. Ordinary resolution and updates ignore +a yanked release. An existing lock may continue to use it, and an exact request +may select it when no non-yanked candidate satisfies that request. Reploy warns +whenever it selects a yanked release and includes the repository-provided +reason. Yanking one revision leaves other revisions of that upstream version +eligible; a version-level yank covers every revision. A repository may rescind +or reapply a yank. Yanking does not remove immutable content. + +### Archive + +Archiving follows PyPI project-archival semantics and applies to the complete +qualified blueprint or tool identity. It prohibits publishing new versions but +leaves every existing release available for resolution, installation, update, +and lock replay. Discovery marks archived assets and new selection warns. +Archival means unmaintained, not unsafe, and never bypasses compatibility +checks. + +### Delete + +Deletion removes its target from repository selection and retrieval. New +resolution, updates, and exact remote requests cannot select deleted content. +An existing deployment can replay only when its own provider-store closure +already contains every exact immutable object; deletion does not claim to erase +downloaded copies. + +A deleted qualified-name/version/revision coordinate is permanently retired and +cannot be republished with different content. A correction after deleting one +release requires a new revision. A version-level delete retires the version and +requires a new upstream version. If every release is deleted, the same publisher +DID may restore the qualified identity using a new, previously unused version. + +A different publisher may assume an existing qualified name only through an +explicit repository-admin ownership transfer. The old and new publisher +identities remain auditable in repository history. An ordinary edit to +publisher authorization never transfers ownership implicitly. + +### Publisher Security Revocation and Rescission + +When a publisher is determined to be malicious and the potential damage from +running any of its prior material outweighs availability, a repository +maintainer may perform an explicit publisher-wide security revocation, also +described operationally as the publisher “nuke.” An updated client refuses new +resolution and refuses replay of that publisher's releases from locks or local +caches. It still permits safe teardown operations such as stop, down, remove, +inspection, and evidence export. + +The revocation applies only to releases accepted by the issuing repository and +only on asset surfaces for which the client trusts that repository. It does not +revoke the publisher's releases accepted by another repository or extend from +one authorized surface to another. A client may warn that another trusted +repository has revoked the same publisher DID, but does not enforce that event +outside the issuing repository's authority. + +Revocation is not remote erasure. It cannot recall copies held by offline +clients, terminate already running workloads, or remove content from systems +that have not accepted the event. Repository-held release bytes remain retained +but unavailable so the action can be audited and, if the security determination +was wrong, reversed safely. + +A strongly authorized rescission names the exact revocation event and remains a +new immutable event rather than deleting history. Rescission does not +automatically restore publication authority or availability. It may explicitly +restore exact byte-identical releases, while future publishing requires a +separate current publisher authorization. A distinct `purge` operation +physically destroys repository-held release bytes; purge is irreversible and +cannot be undone by rescission. + +The initial protocol does not define a separate quarantine state. Suspected +content may be yanked while investigated; confirmed unsafe publisher material +uses publisher security revocation. + +A future independently trusted security authority could publish +cross-repository publisher revocations, and an official Reploy client could +ship with that authority's trust root. Its signing thresholds, update channel, +scope, rescission rules, and failure behavior require a separate design; the +initial repository protocol grants no repository global revocation authority. + +## Client Operations + +The consumption CLI is grouped under `repository`: + +```text +reploy repository list +reploy repository show REPOSITORY +reploy repository trust URL [TRUST OPTIONS] +reploy repository configure REPOSITORY [CONFIGURATION OPTIONS] +reploy repository update [REPOSITORY] +reploy repository distrust REPOSITORY +``` + +`REPOSITORY` accepts a configured source or permanent authenticated ID. +`configure` owns mutable client policy such as priority. Removing one surface +grant leaves other surface grants intact. `distrust` revokes the whole +repository, including use by existing locks, but does not silently delete +stored data. + +```bash +reploy repository configure REPOSITORY --priority 700 +``` + +There is no persistent “added but untrusted” repository state. One-off remote +discovery is explicit: + +```bash +reploy search --url https://repo.example/ KEYWORD +``` + +It fetches and strictly parses the remote index for search only. Results are +visibly untrusted, remain segregated from trusted repository state, and cannot +participate in resolution, staging, installation, or update. Selecting a result +shows the exact trust operation required before repository use. + +Because this is a host-side fetch of an untrusted URL, Reploy resolves the +requested hostname once, pins the connection to the validated address while +retaining the hostname for TLS certificate validation, rejects redirects, and +applies fixed response-size and elapsed-time limits. By default it rejects any +resolved address that is loopback, private, link-local, reserved, +infrastructure metadata, or otherwise not globally routable. + +One-off discovery of an intentionally internal enterprise repository requires +`--allow-private-network`. That option permits private and IPv6 unique-local +addresses only for the exact requested hostname; it does not permit redirects, +IP-literal substitution, loopback, link-local, infrastructure-metadata, +multicast, reserved, or unspecified destinations, and it does not weaken HTTPS +validation. If that repository is subsequently trusted with the same explicit +authorization, Reploy stores the private-network permission with the canonical +repository identity so later authenticated updates do not require a repeated +override. The permission grants no general access to the private network. + +`repository trust` authenticates, configures, grants the requested surfaces, +and atomically accepts the initial repository snapshot. It implies everything +needed to use the repository; there is no separate persistent `add` operation. + +### Explicit Repository Update + +The optional argument changes scope, not content: + +- `reploy repository update` refreshes every trusted repository; +- `reploy repository update REPOSITORY` refreshes only that repository. + +Each refresh atomically accepts one coherent view containing: + +- the valid TUF root-rotation chain, timestamp, snapshot, and targets metadata; +- `repository.json` and `publishers.json`; +- the authenticated repository index and lifecycle state. + +Update does not download blueprint documents, tool definitions, browser +archives, or other payloads. Selected immutable assets are fetched on demand. +Stage, install, build, and ordinary trusted search resolve against the accepted +local index without silently refreshing mutable repository metadata or indexes. +Stage, install, and build may contact the selected trusted repository only to +fetch an authenticated immutable asset that is absent from the local object +cache; doing so never accepts a newer index or metadata generation. Ordinary +trusted search does not fetch asset payloads. When no usable authenticated +index exists for a new resolution, Reploy fails with the exact +`repository update` operation required. + +Repository-supplied updates cannot change client-approved surfaces, trust +scope, priority, or initial-trust provenance. Root changes require the existing +TUF rotation chain. + +## Resolution, Deployment Retention, and Cache + +New resolution uses an eligible accepted local index. It authenticates and +validates a selected asset, publisher attestation, and repository acceptance +record; resolves all ordinary provider inputs; and records exact identities in +the build lock. A lock includes at least repository and snapshot identities, +asset qualified name, version scheme, exact version and revision, document and +attestation digests, selected tool profile and binding where applicable, and +downstream provider inputs. + +The exact selected blueprint or tool document, publisher attestation, and +repository acceptance record enter the deployment-owned provider-store closure. +Installation transfers that closure. Staged and installed deployment replay +therefore does not depend on a global repository cache, repository availability, +or discovering other staging and installation directories. + +Trusted roots, accepted TUF metadata, repository policy, and the accepted index +are active client state, not disposable cache. Separately, Reploy may cache +fetched immutable asset objects by authenticated identity and digest to speed +later resolutions. That global object cache is non-authoritative and may be +evicted by size, age, or recency without affecting an existing deployment. + +TUF expiration prevents accepting expired metadata for new resolution. It does +not revoke a deployment-owned immutable definition already authenticated and +locked. Such replay remains subject to ordinary provider, build, and +compatibility verification and never follows newer repository state. An +accepted publisher-security revocation is deliberately stronger: it blocks +replay of affected local releases even when their immutable closure remains +present. A client that has not received the revocation, including an offline +client, cannot enforce it. + +The exact global object-cache size, age, inspection, and cleanup interface is +an implementation decision rather than a correctness dependency. + +## Offline Repository Transfer + +A portable repository bundle supports disconnected or manually controlled +updates. It contains the root-update chain and unexpired TUF metadata needed for +one snapshot, the complete index snapshot, selected immutable asset objects, +and repository identity and generation information. + +Import verifies the root chain, roles, thresholds, versions, expiry, safe +archive paths, bounds, schemas, repository acceptance records, publisher +signatures, effective lifecycle state, and every content digest before +atomically activating the imported snapshot. It never merges loose files into +an authenticated index or widens client-approved surface authority. Existing +TUF rollback and mix-and-match protections apply. + +## Publisher and Repository-Maintainer Tooling + +The ordinary `reploy` executable remains consumption-only. It may search, +trust, configure, update, distrust, verify, resolve, cache, and import +repositories. It cannot sign publisher submissions, authorize publishers, +change asset lifecycle, manage repository signing keys, or publish TUF state. + +Two separately distributed executables use shared protocol, canonicalization, +schema, and validation libraries: + +1. A publisher tool prepares an immutable asset submission, validates it, + constructs the detached attestation, and signs it with the publisher DID. +2. A repository-maintainer tool manages publisher authorization, ownership + transfer, lifecycle, policy, deterministic index compilation, TUF signing, + and publication. + +The split prevents publishers from needing repository-administration code or +credentials and keeps publication dependencies out of the already substantial +client binary. Exact executable names remain open. The repository formats are +public protocols; compatible third-party tooling may produce valid output. + +## Authoring and Publication + +A repository may use one Git repository with two persistent histories: + +- The primary branch contains human-authored repository policy, publisher + authorization source, blueprint and tool submissions, tests, documentation + inputs, and compiler/workflow configuration. +- A separate automation-owned `publish` branch contains only generated static + repository output: indexes, immutable targets, attestations, generated + documentation as applicable, and TUF metadata. + +Ordinary pull requests modify only human-owned source and tests. CI validates +that source and deterministically compiles a complete preview. Publication +updates the `publish` branch only after validation and configured signature +thresholds succeed. Any transient signing-event branches are automation-owned, +deleted after completion or abandonment, and never merged into the primary +branch. + +The publish branch is a deployment artifact rather than a trust source. Clients +authenticate it with TUF exactly as they would object storage, a CDN, an +internal server, or a filesystem mirror. + +Repository publication always performs strict static validation without +running untrusted blueprint code. Optional dynamic CI builds are repository +policy and may vary by publisher confidence. Publication also verifies asset +identity, version and revision immutability, the publisher DID signature and +current authorization for new releases, repository acceptance records, +lifecycle-event history and transitions, ownership, target compatibility, +deterministic index generation, and generated documentation completeness. + +## Documentation Surface + +Validated records generate repository search data and human-facing pages. +Blueprint pages show publisher identity, versions, lifecycle, supported Reploy +versions and targets, required external repositories, validation evidence, and +source provenance. Tool pages additionally show: + +- supported downstream versions, operating systems, releases, architectures, + bindings, and selectable parameters; +- exact root OS packages contributed per target profile; +- executable and capability interfaces; +- build-only or runtime placement; +- acquisition network behavior and artifact provenance; +- validation performed, approximate installed size where known, licensing, + and known limitations. + +Publication rejects an asset whose required generated documentation cannot be +produced. Repository promotion belongs in publisher-facing documentation and +the publisher tool, not in consumer warnings for direct BURLs. + +## Portable Tool Contract + +### Definition Shape and Safety Boundary + +A tool definition represents: + +- stable qualified tool identity; +- one exact upstream-facing version and Reploy revision; +- supported Reploy versions, targets, and use contexts; +- human summary, upstream and licensing provenance; +- exact OS-provider root packages per target; +- named executable and capability exports with target-specific validation; +- strict parameter schemas and supported values; +- zero or more application-facing bindings; +- named Reploy-owned resolver primitives for curated non-package artifacts; +- network behavior, final-image placement, and documentation metadata. + +Unknown fields, schemas, primitives, targets, parameter values, or executable +contracts fail closed. Definitions cannot provide executable implementation +code. A future primitive requires a reviewed Reploy implementation and release; +ordinary definition updates may only select primitives the client already +supports. + +A runtime tool belongs to the application that declares it. Public executables +become application-scoped executable outputs and are validated in the +materialized application environment. Colliding exports are errors unless a +future explicit alias design resolves them. A build-only tool declared by a +local project recipe exposes executables only within that isolated source +builder. + +### Tool Requirements and Definition Revisions + +Tool requirements accept a compact string or a structured mapping. Both +normalize immediately to the same internal surface, qualified name, symbolic +selections, version requirement, revision, repository pin, binding, and typed +parameter fields: + +```yaml +tools: + - "tool:acme/playwright[chromium,webkit]>=1.55.0,<1.56.0" +``` + +The equivalent structured requirement is: + +```yaml +tools: + - tool: acme/playwright + select: [chromium, webkit] + version: ">=1.55.0,<1.56.0" +``` + +The compact grammar is: + +```text +tool:[,...] +``` + +The bracketed portion is optional and contains definition-declared symbolic +selections. It is normalized as an order-independent set. The version suffix +is also optional and uses the selected asset's version-scheme grammar. Exact +upstream version `==21` still selects the newest eligible Reploy revision; +`==21~2` pins both coordinates. Syntax that is ambiguous under the selected +version scheme, plus repository pins, bindings, and complex keyed or typed +parameters, requires the structured mapping. Unknown selections or missing +required selections fail with the target-supported values. + +The public structured `version` field is an upstream-facing constraint, not a +definition revision: + +```yaml +tools: + - tool: acme/playwright + version: ">=1.55.0,<1.56.0" +``` + +Tool requirements use the shared asset versioning and Reploy revision model +defined above. The surface calls that common revision a definition revision. It +may correct packages, target data, validation, acquisition, or documentation +for one exact upstream version without changing that version. Requirements may +specify an exact `revision` only when `version` is exact; otherwise resolution +selects the newest eligible revision after selecting the upstream version. + +### Bindings + +A binding selects an application-facing ecosystem interface to one shared tool. +For example, one Playwright tool owns browser payloads, OS requirements, +validation, and commands while `python` and `node` bindings contribute their +respective ecosystem packages. + +An explicit supported binding wins. If only one exists, Reploy infers it. When +several exist, Reploy may infer exactly one matching an already active +application provider; ambiguity lists supported values. An explicit binding +may activate its provider. The initial requirement selects at most one binding. + +Bindings are strict provider mappings, not arbitrary package-manager +expressions. Their constraints merge with ordinary application constraints so +the same ecosystem package is resolved and installed once. Selected or inferred +binding is part of request, lock, cache, diagnostics, and documentation +identity. + +### Parameters and Sub-payloads + +A definition may expose symbolic selections for declared sub-payloads and +strict typed parameters for other bounded choices: + +```yaml +tools: + - tool: acme/playwright + select: [chromium, webkit] +``` + +Selections and parameters declare names or symbols, types, required/default +behavior, allowed values, and target availability. Missing required or +unsupported values fail before acquisition and list target-supported values. A +selection or parameter cannot introduce a URL, command, package expression, or +undeclared repository object. + +Multiple selections contribute one normalized, deduplicated, order-independent +union of common and selection-specific provider requirements. Publication +rejects definitions whose selectable payloads contain incompatible exact +requirements. + +### Runtime Placement and Provider Composition + +Runtime tool requirements live with the owning application: + +```yaml +environment: + applications: + application: + packages: + tools: + - tool: acme/playwright +``` + +The selected definition contributes ecosystem packages, artifacts, OS package +roots, capabilities, and executable exports to that application. Reploy +activates the appropriate OS provider or contributes packages to the established +one based on the selected base image and target OS. Tool portability may map a +common capability to different native packages; literal OS package requests +remain literal and are never normalized across distributions. + +The existing local project recipe form remains build-only: + +```yaml +requires: + - tool:java +``` + +### Playwright + +`tool:playwright` is the first capability expected to exercise the complete +model. Official support should resolve one exact Playwright release and +compatible browser payloads; contribute reviewed target-specific OS roots; +acquire browser payloads through a named Reploy-owned primitive without +exposing project source, host credentials, or arbitrary paths; materialize +offline; and lock platform, browser revision, provenance, artifact digest, and +definition digest. + +Browser selection is explicit because payloads are large and materially change +requirements. Omitting it lists supported browsers. Multiple browsers produce +one canonical OS dependency union while retaining separate exact payload +identities. `chromium` and branded `chrome` remain distinct. The first +OmegaFlow definition may support only `chromium` and uses the `python` binding. + +The tool exports the supported Playwright CLI into the application executable +namespace. Browser payload executables remain internal unless the definition +deliberately exposes a stable named interface. + +### Unsupported Dynamic Installers + +The protocol does not translate arbitrary install scripts or post-install +downloaders. Unsupported software may use ordinary OS/ecosystem packaging, a +reviewed tool definition, or a prepared base image. Reploy reports the blocked +operation and available alternatives rather than granting project build code +network access silently. + +A future explicit network-enabled build escape hatch remains possible only +after concrete unsupported cases establish its authority and diagnostics. It +is not reserved in the initial public schema. + +## Initial Implementation Slices + +1. Finalize the repository descriptor, publisher authorization, index, + publisher-attestation, repository-acceptance, lifecycle-event, shared + version/revision, and asset target schemas within TUF 1.x. +2. Implement the deterministic repository compiler, strict static validation, + publisher and maintainer tooling boundaries, and primary/publish branch + workflow. +3. Integrate a conformant TUF client with trust scopes and surfaces, explicit + update, untrusted URL search, atomic accepted state, priority, source pins, + and exact resolution. +4. Retain selected blueprint/tool records in deployment provider-store closures + and implement disposable global object caching and validated offline import. +5. Publish the independently updated official repository and generated + documentation. +6. Move Java's existing portable-tool mapping from Go switches into an official + definition without changing its current project-owned build-only behavior. +7. Add the reviewed Playwright resolver primitive, definition, OS matrix, + documentation, and integration evidence. + +## Deferred Implementation Details + +The following do not block the high-level protocol decision: + +- exact JSON field encodings, opaque repository-ID representation, and + canonical signature serialization; +- exact asset-document filenames and transport-specific adjacent-attestation + discovery conventions for direct BURLs; +- exact auxiliary executable names; +- global disposable object-cache limits, inspection, and cleanup CLI; +- detailed publisher DID evidence presentation and any future curated + cross-repository search or web-of-trust service; +- additional shared asset version schemes, multi-binding requirements, and + unsupported dynamic-installer escape hatches; +- any public transparency log or cross-repository lifecycle-history service; +- the final Playwright browser profile beyond the approved initial Chromium and + Python-binding scope.