feat(o4b): TS contract foundation — the four primitives cross to TypeScript#9
Merged
Merged
Conversation
…Script O4b-1 of the positron-lit build-out. Until now @positron/core shipped only the *generated wire data* (StateEnvelope, CommandEnvelope, session frames) and the repo had a Rust-only CI. This lands the missing half: the four positron primitives — ViewState / Renderer / Host / Observer — as hand-authored TS interfaces (npm/core/src/contract.ts), the TS twin of the Rust traits in positron-core/src/lib.rs. They are hand-authored on purpose: ts-rs projects *data* (structs/enums with a wire form); a trait has no serialized form to generate. The Rust trait and the TS interface are the same contract in two languages — the generated wire types are the data those contracts move. Toolchain (first TS build in a Rust-only repo): - root package.json = npm workspaces over npm/* + shared devDeps (typescript/tsx/@types/node) - tsconfig.base.json = strict shared options; per-package tsconfig sets only `include`. noEmit — these packages ship .ts source, they're typechecked not built. - CI gains a `web` job: npm install → `tsc --noEmit` → `node --test` smoke tests. contract.ts has no Rust drift gate, so this job IS its gate. - lockfile ignored (matching Cargo.lock), so `npm install` not `npm ci`. Proof mirrors positron-core's own smoke tests: the same Counter fixture, the same kind/revision/deterministic-render assertions, plus an Observer perceive check — the TS side proven usable the way the Rust side is. Validated: `npm run typecheck` clean, `npm test` 4/4 pass. Task #117 (positron O1..O6 build-out). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo
joelteply
added a commit
that referenced
this pull request
Jul 3, 2026
…Result> + LitHost) (#10) * feat(o4b): @positron/lit — the Lit DOM renderer (Renderer<S, TemplateResult> + LitHost) O4b-2 — the DOM/TS outlier of the positron Renderer/Host contract, the sibling of the wgpu backend on the web surface. Completes O4b (the contract's TypeScript crossing, foundation landed in O4b-1 / PR #9). New package `@positron/lit`: - `renderer.ts` — `LitRenderer<S> = Renderer<S, TemplateResult>`. Not a fresh interface: the render contract lives once in @positron/core; this only pins the DOM output type (compression rule). - `host.ts` — `LitHost` implements core's `Host`: state flows down (render → injected commit sink), events flow up (injected event→command mapper). DOM-free by construction — imports only the `TemplateResult` type, never a DOM value — so it's headlessly testable. - `dom.ts` — `domCommit(container)`, the ONE DOM-touching seam (Lit's `render` into a container). The analogue of the wgpu outlier's `gpu.rs`: quarantined from the pure projection, off the headless test path. Same pure/impure split as both Rust outliers. - `lit.test.ts` — Counter + CounterLitRenderer fixture (mirrors core's contract.test.ts). Asserts the projection headlessly on the TemplateResult's `strings`/`values` — the DOM analogue of wgpu's quad assertions — plus LitHost state-down/event-up. 4/4 pass, no jsdom. Toolchain: adds `npm/lit/` to the workspaces; deps `lit ^3.2.0` + `@positron/core` (type-only — lit imports only interfaces from core, all erased, so no runtime coupling). The existing `web` CI job gates it. Docs: ARCHITECTURE.md marks O4b landed and records the deferred subsume-vs-complement decision — positron's portable contract (ViewState/Renderer/Host/Observer + session frames) and continuum's `sdk/typescript` (its Commands/Events/domain types) COMPLEMENT; they meet at ContinuumHost (O5), neither subsumes the other. README Status + diagram updated. Task #117 (positron O1..O6 build-out). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo * docs(o4b): breadcrumb the Lit-4 narrowing point in lit.test.ts Review non-blocking nit: in Lit 4, `TemplateResult` becomes possibly- compiled and drops `.strings`, so the static-structure assertion is the exact line that will need an `UncompiledTemplateResult` narrowing on that bump. Note it in place so future-you doesn't have to re-derive it. Comment only — no behavior change (8/8 still green, typecheck clean). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O4b-1 — the positron contract crosses to TypeScript
First slice of the
positron-litbuild-out (roadmap O4b). Until now@positron/coreshipped only the generated wire data (StateEnvelope,CommandEnvelope, session frames) and the repo had a Rust-only CI. This lands the missing half.What
npm/core/src/contract.ts— the four positron primitives (ViewState/Renderer/Host/Observer) as hand-authored TS interfaces, the TS twin of the Rust traits inpositron-core/src/lib.rs.snake_case→ TScamelCase(observer_id→observerId); Rust associated types (Renderer::Output,Host::Command/Event) → TS generics.package.jsonnpm workspaces overnpm/*;tsconfig.base.jsonstrict shared options (noEmit— packages ship.tssource); per-package tsconfig sets onlyinclude.webjob:npm install→tsc --noEmit→node --test.contract.tshas no Rust drift gate, so this job is its gate.Cargo.lock) →npm install, notnpm ci; deps are dev-only (typescript/tsx/@types/node).Proof
contract.test.tsmirrors positron-core's own Rust smoke tests: sameCounterfixture, same kind/revision/deterministic-render assertions, plus anObserverperceive check.Validated locally:
npm run typecheckclean,npm test4/4 pass.Why a slice (not all of O4b)
O4b-2 (next) adds
@positron/lit— the actual Lit DOMRenderer(Output = TemplateResult) +LitHost(against theClientMessage/ServerMessagesession frames) + a Counter example with a headless template assertion. This slice is the foundation it builds on: the contract must exist in TS, typecheck, and be CI-gated first.Task #117 (positron O1..O6 build-out).
🤖 Generated with Claude Code