Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/observe-records-channel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@solidjs/signals": patch
"solid-js": patch
"@solidjs/web": patch
"@solidjs/diagnostics": patch
---

`OBSERVE.records` — one records channel on both platforms (observe/dev tiers); frame records from both ends; the client `"call"` record; `observeServerFunctionCalls` removed

- **`@solidjs/signals`**: `OBSERVE.records` — `subscribe(type, listener)`, `observed(type)`, `emit(type, event, live)` — the channel every runtime record rides, created once per process and registered on `globalThis` under `Symbol.for("@solidjs/signals/observe/records")` so a second copy of the core (a bundled server build instrumented through `--import`) and wire layers bundled without a framework import reach the same listener sets. Listeners are snapshotted per emit; a throwing listener is reported and the rest run. Types: `Records`, `RecordTypes` (extends `HostRecordTypes`; both declared empty, for the runtimes to augment — one augmenter per interface), `RecordType`, `RecordEvent`, `RecordLive`, `RecordListener`. Folds out of prod. New **`OBSERVE.attribution.currentOrigin()`** (and the `currentOrigin` hook on `AttributionHooks`): the provenance a root write performed now would be stamped with — the interaction whose handler is running, the navigation/effect/action frame open, or inside a recompute the origin of the change that caused it — as the engine's own `ChangeOrigin` object, `undefined` when external or with no engine; for a runtime stamping a record of its own. The installed hooks are also registered on `globalThis` under `Symbol.for("@solidjs/signals/observe/attribution")`, the same reach-without-an-import the channel has.
- **`solid-js`**: the `"boundary"` record moves from `OBSERVE.server.records` to `OBSERVE.records` (augmenting the core's `RecordTypes`). `OBSERVE.server` keeps only the `trace` slot; `ServerRecords` is gone.
- **`@solidjs/web`**: the `"invocation"` and `"frame"` records move to `OBSERVE.records` (augmenting `HostRecordTypes` through `solid-js`). New **`"call"` record** (`CallEvent`, `CallLive`, `CallListener`): one per server-function call made from the browser, at the caller's settle — `{ id, at, durationMs, method: "GET" | "POST", outcome, status?, origin?, deferred? }` with `{ args, response?, result? | error? }` beside it; joins the server's `"invocation"` by `id`, and — through `origin`, the engine's own interaction/navigation object read at dispatch via `currentOrigin()` — the attribution engine's `InteractionEvent` / `NavigationEvent` / `HoldEvent` by identity, so an observer files the call under the click that made it without a time join. The **`"frame"` record now has a client half**: `FrameEvent` is `FrameProducedEvent | FrameAppliedEvent`, discriminated by `side`, same census on both; the client half (`applyFrameResponse`, one per stream in a response) adds `address` (the `as` remap) and `outcome: "truncated"` for a body that ended before `complete`, with `live.response`. Server census fix: `regions` counts `html` chunks addressed to a child frame id (the former count read a chunk type that does not exist), and `shellMs` is set by the stream's own shell only. The emitters and their wrappers fold out of the prod client artifacts behind the observe literal (prod `applyFrameResponse` and the server-function dispatch are the pre-existing functions, no extra frame or promise hop). The server-functions and frames **client** entries gain `observe` and `development` builds and export conditions (`server-functions/dist/client.{observe,dev}.js`, `frames/dist/client.observe.js`); the server-functions client is now built with its flags replaced in every tier (before, `_SOLID_DEV_` there was an unreplaced truthy string).
- **Removed**: `observeServerFunctionCalls` and the `ServerFunctionCall` / `ServerFunctionRequestCall` / `ServerFunctionResponseCall` types, from both server-function entries. Subscribe to `OBSERVE.records` `"call"` (client) or `"invocation"` (server) instead.
- **`@solidjs/diagnostics`** (format v6): `artifact.server` is replaced by `artifact.records: { boundary, invocation, frame, call }` — always present, captured on both platforms including the browser bridge; types `BoundaryRecord`, `InvocationRecord`, `FrameRecord` (`FrameProducedRecord | FrameAppliedRecord`), `CallRecord` (with `origin?: ChangeOrigin`), `ArtifactRecords` replace the `Server*Record` / `ArtifactServer` names. JSONL: one line per record with `type` naming its table; the meta line's `boundaryCount`/`invocationCount`/`frameCount` become `recordCounts: { boundary, invocation, frame, call }`.
19 changes: 12 additions & 7 deletions documentation/plans/server-dev-build-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,9 @@ type/tooling reuse, with unused members no-op.
> `"boundary"` record from solid-js's server entry joined the `"invocation"`
> one — and the objects and the `records`/`trace` members are solid-js's,
> with web augmenting solid-js's `ServerRecords`/`ServerTrace`; see
> `sentry-integration-plan.md` C3.)_ Observe-tier only: web now
> `sentry-integration-plan.md` C3. Since C4's client half, 2026-09-15: the
> channel is the core's `OBSERVE.records`, on both platforms — see C4
> there; `OBSERVE.server` keeps only `trace`.)_ Observe-tier only: web now
> ships `dist/server.observe.js`, `server-functions/dist/server.observe.js`
> and `frames/dist/server.observe.js` under the `observe` condition (the P0
> plumbing, third flavour), and every emit site folds out of prod behind
Expand Down Expand Up @@ -346,19 +348,22 @@ becomes the contract test for server codes.
> **(c) The artifact.** `@solidjs/diagnostics` format v5 adds
> `artifact.server: { boundaries, invocations } | null`, folded from
> `OBSERVE.server.records` when the server runtime installed its surface
> (`null` otherwise — client captures, the browser bridge). The package still
> (`null` otherwise — client captures, the browser bridge). _(v6, with C4's
> client half: `artifact.records.{boundary, invocation, frame, call}`,
> folded from the core's `OBSERVE.records` on both platforms and always
> present.)_ The package still
> depends on `@solidjs/signals` alone: it reads the channel by its contract
> (`subscribe(type, listener)`, structurally) and mirrors the two record
> types (`ServerBoundaryRecord`, `ServerInvocationRecord`); the web server
> (`subscribe(type, listener)`, structurally) and mirrors the record
> types (`BoundaryRecord`, `InvocationRecord`, `FrameRecord`, `CallRecord`); the web server
> suite pins the mirrors to the runtime types at compile time, both ways and
> by key set. JSONL egress adds `boundary`/`invocation` lines. The contract
> by key set. JSONL egress adds one line per record. The contract
> test is `packages/web/test/server/diagnostics-server-scenario.spec.tsx`
> (harness aliased from source in `vite.config.server.mjs` and
> `tsconfig.test.json`): the seeded `HEAD_TAG_INVALID` and `SERVER_WRITE`
> with `ownerPath`, a boundary and the invocation under it joined by id, the
> waterfall as a finding `expectNoDiagnostics` catches, and the tables
> serializable line by line. The package's own suite covers the fold against
> a stand-in channel (bare signals has no server surface).
> serializable line by line. The package's own suite covers the fold with
> records emitted onto the real channel by hand (bare signals has no emitter).

## Decisions (resolved 2026-09-06)

Expand Down
Loading
Loading