/** * The hot-path render seam — build contract §1.6. * * The runtime is the one place that knows a screen landed, so the runtime is the * one place that emits: every store write to `app.tsx` goes through the checks * floor's component gauntlet here and, iff it paints, becomes today's * `data-vendo-view` part — same payload shape, same stable per-app stream id, * same server-authoritative field stripping. A write that does not paint emits * NOTHING: the last good view stays on screen and the brokenness reaches the * harness through `validate`, never the user. * * `HarnessEvent` stays closed — a harness cannot yield a view, by construction. * * The interception point is **`commit()`** (orchestrator seam answer, 2026-07-30, * after lane B landed): the workspace façade STAGES writes in memory, so a * `writeFile` is not a store write — `commit()` is, and `CommitResult.changed` * names exactly the paths that reached the store. Hooking the write instead would * emit views for content that never landed, and would miss the sandbox sync-back * path, which commits without ever calling `writeFile` on this façade. * * That last clause is why the app's own SOURCE is persisted from here too * (contract §2.2/§3.2, the `commitSource` seam): a builder working inside a box * reaches the store through this same `commit()`, so this is the one place that * sees its files at all. Before it, an app's code lived only in the sandbox * snapshot behind `machine.snapshotRef` — lose the snapshot, lose the app. */ import { type AppId, type CommitResult, type TurnId, type VendoViewPart, type WorkspaceFs } from "@vendoai/core"; import { type AppFloor } from "../../contract/index.js"; /** §1.6 — the file that syncs mid-turn. Everything else waits for turn end. */ export declare const HOT_PATH_FILES: readonly ["app.tsx"]; /** * §3.5's hot paths as WATCH SHAPES — what a machine's mid-turn collect asks for, * where `*` stands for exactly one segment (both machines' rule). * * BOTH mounts, for the same reason `HOT_PATH` reads either: a team app's * skeleton has to paint mid-turn like a personal one's. Watching only * `/user/apps/*` left an `/orgs` app with nothing to sync until turn end — a * blank pane for the length of the turn instead of a skeleton in seconds. * * Shapes, never a list of files that already exist: on the one ask the skeleton * exists for ("make me an app") the appId is invented DURING the turn, so an * enumeration watches nothing at all — measured 52.8s of silence against 5.0s. */ export declare const HOT_PATH_WATCH: readonly string[]; /** The appId a hot-path write belongs to, or undefined if this is not one. */ export declare function hotPathAppId(path: string): AppId | undefined; /** The apps `result`'s commit painted, or undefined for a result this seam did not * produce — which is "not known", never "nothing painted". */ export declare const paintedIn: (result: CommitResult) => readonly AppId[] | undefined; /** * Why `appId`'s landed write never reached the screen, or undefined when it * painted — and for a result this seam did not produce, the same "not known" * `paintedIn` answers. * * The seam's own refusal channel is a console line to the OPERATOR, which the * hand that wrote the screen cannot read. Without this the writer had the bare * fact "nothing painted" and no reason to give, so a person heard the loop's * last-resort sentence instead of what actually happened. */ export declare const unpaintedIn: (result: CommitResult, appId: AppId) => UnpaintedReason | undefined; /** Why a landed write did not paint, in the floor's own vocabulary so the loop * reads one kind of finding wherever it came from. */ export interface UnpaintedReason { /** Repair instructions for the screen — what to fix, as the floor words it. */ readonly blocking: readonly string[]; /** The DEPLOYMENT could not paint, so nothing the writer saves changes it: no * screen engine is wired here. A screen fault leaves this absent. */ readonly environment?: true; } /** A landed hot-path write, and either the view it painted or why it did not. */ export type PaintAttempt = { readonly painted: true; readonly streamId: string; readonly part: VendoViewPart; } | { readonly painted: false; readonly reason?: UnpaintedReason; }; export interface RenderSeamOptions { /** Write the part on the stable per-app stream id, so successive views * reconcile in place instead of stacking. */ emit: (streamId: string, part: VendoViewPart) => void; /** * The checks floor (§7.1) — the production compile dialect, and the * deterministic fact checks over what it compiled. * * INJECTED rather than imported. The floor's implementation needs a catalog, * tool shapes and a model, none of which a bare `WorkspaceFs` wrap can know. * Composition builds it — `AppsRuntime.floor(ctx)` — which is the only layer * that HAS those things. * * Unwired, this build carries no screen engine: nothing paints, and a * `WorkspaceFs` wrapped outside composition still has to work. */ floor?: AppFloor; /** * Contract §2.2/§3.2 — persist the app's own SOURCE for a commit that landed. * * The same interception point as a view, for the same reason plus one: the * sandbox sync-back path (`materialize.ts`) commits without ever calling * `writeFile` on this façade, so a builder working inside a box reaches the * store HERE and nowhere else. Hooking the write instead would persist content * that never landed and miss the box entirely. * * `changed` is `CommitResult.changed` verbatim — the paths that actually reached * the store. Called once per APP the commit touched, because `commitApp` is * per-app and one commit can carry several; it does its own prefix filtering, so * the whole list rides every call. `workspace` is the real façade underneath this * wrapper, which is what the diff reads the landed bytes back through. * * Composition injects `AppsRuntime.commitSource` (see `packages/vendo/src/server.ts`), * which binds `commitApp` to the app row's ownership, its compare-and-swap * update, and the deployment's files adapter for blob spill. * * UNWIRED, source is not persisted: `machine.snapshotRef` stays the only home an * app's code has, which is exactly today's behaviour — so no host regresses, and * no host is protected either. */ commitSource?: (input: { appId: AppId; changed: readonly string[]; workspace: WorkspaceFs; }) => Promise; /** The turn this seam is painting inside, stamped on every view it emits so a * screen joins back to the exchange that made it. Absent outside a turn. */ turnId?: TurnId; } /** The view a landed hot-path commit produces, or why it did not paint. */ export declare function viewForWrite(path: string, content: string, options: RenderSeamOptions): Promise; /** * Wrap a workspace so a commit that lands a hot-path file emits its view. Every * other operation passes straight through, so the result is still a `WorkspaceFs`. */ export declare function wrapWorkspaceForRender(workspace: WorkspaceFs, options: RenderSeamOptions): WorkspaceFs; //# sourceMappingURL=render-seam.d.ts.map