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
10 changes: 10 additions & 0 deletions .llm/runs/release-0.0.6-features--orchestration/context-pack.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Context pack — 0.0.6 runtime / public-surface lane

## Reopened slice — #1548 / PR #1559 (2026-08-12)

The lane was reopened for the P1 browser stream-discovery fix on
`fix/1548-vite-browser-stream-discovery`. PLAN-EVAL passed with binding amendments recorded at the
bottom of `slices/plan-1548.md`. The implementation replaces the value-passed/computed browser env
reads with literal Vite-substitutable member expressions, adds a source-internal pure lookup, and
adds five resolver tests. Gate evidence and the contributor path are in `slices/worklog-1548.md`.
The PR remains draft at `status:impl`; separate-session IMPL-EVAL and merge authority remain with the
orchestrator.

Closing summary. The lane is **complete**: both owned issues landed on `main`. Read this first if
resuming or auditing; everything below is traceable to a named artifact.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use harness

# Slice brief — #1548 browser stream resolver cannot see Aspire VITE service references

**Codex · GPT-5.6 Sol · medium** (`normal_implementation`). The plan has **passed PLAN-EVAL with
conditions**; implement it, do not re-decide it.

| Field | Value |
| --- | --- |
| Issue | #1548 (`priority:p1`) |
| PR | **#1559** (already open, draft, at plan phase — commit onto its branch) |
| Worktree | `/home/codex/repos/ns006-1548` |
| Branch | `fix/1548-vite-browser-stream-discovery` |
| Run dir | `.llm/runs/release-0.0.6-features--orchestration/` |

**Read first:** `slices/plan-1548.md` — **including the "Amendments after PLAN-EVAL" section at the
bottom, which is binding** — and `slices/research-1548.md`. If they are not on your branch, read them
with `git show chore/release-0.0.6-runtime-reopen:<path>`.

## SKILL

- `netscript-doctrine` — `packages/plugin-streams-core` is framework code; `mod.ts` is published
surface.
- `deno-fresh` — Fresh/Vite build and `import.meta.env` substitution.
- `netscript-tools`, `netscript-pr`, `netscript-harness`.

## The defect

`packages/plugin-streams-core/src/application/stream-url-resolver.ts` cannot see
`VITE_services__streams__http__0` in a browser bundle, for **two** independent reasons:

1. `import.meta` is passed **as a value** into `readImportMetaEnvironment` (`:60`), reached through a
parameter binding (`:77-78`) — the literal `import.meta.env.VITE_…` never appears in source.
2. Both keys are read by **computed index** (`:64,:68`).

This repo's own Vite plugin substitutes by emitting `define` entries keyed exactly as
`` `import.meta.env.${target}` `` (`packages/fresh/src/application/vite/vite.ts:195,311-335`) — a
textual static-expression mechanism that by construction cannot reach either shape.

## LOCKED decisions

- **D1** — read the two browser keys as **literal static member expressions** inline:
`import.meta.env.VITE_services__streams__http__0` and `import.meta.env.VITE_STREAMS_URL`. No value
passing of `import.meta`, no computed index for these two. Safe because the keys are fully known at
compile time (`STREAMS_RESOURCE_NAME`, `domain/constants.ts:5`).
- **D2** — split the **pure, injectable** lookup from the impure reader. **A1 (binding):** the SDK
(`packages/sdk/src/discovery/browser-env.ts`) is a **structural** precedent only — it carries the
*same* substitutability defect. Borrow its shape; do **not** describe it, in code comments or the
PR, as having already solved this.
- **D3** — **no published-surface growth**: the pure function stays internal, not added to `mod.ts`
(which exports only `buildStreamUrl`, `getStreamsAuth`, `getStreamsUrl`). Tests import by src path.
- **D4** — precedence unchanged: `DURABLE_STREAMS_URL` → `services__streams__http__0` → browser
`VITE_*` (full key before shorthand) → throw. Change **how** the browser branch reads, not what wins.
- **D5** — **no** Vite `transform` hook and **no** scaffold-template change in this slice.
- **D6** — you may narrow the silent `catch` (`:59,69-71`) so a genuine throw is distinguishable from
"absent", but it must not change which value wins. Drop it if it grows.
- **A3** — `plugin-streams-core/deno.json` depends only on `@netscript/telemetry` and `@std/assert`;
there is no dependency on `packages/fresh`, so no cycle is introduced and the
`createNetScriptStreamDB` call site needs no change.

## Required tests

1. **Precedence on the pure lookup**, injected bag: full key wins over shorthand; shorthand used when
the full key is absent; neither → `undefined`. Mirrors
`packages/sdk/tests/discovery/env-ordering_test.ts:24,41,56`.
2. **Source-shape guard** — assert the module contains the literal substitutable expressions and that
the browser path does **not** pass `import.meta` across a function boundary or index `env` by a
computed key. This is deliberately a shape assertion: **the defect is the shape**, and without this
guard a refactor back to a helper reintroduces the bug silently with all behavioural tests green.
3. **Resolution through `getStreamsUrl()`** proving the browser branch is reachable and correctly
ordered.

There are currently **no unit tests at all** for this file's URL resolution — the package's nine test
files never reference `getStreamsUrl`. You are adding the first.

**Do not claim any test proves Vite substitution.** It does not; test 2 is an explicit surrogate.
Say so in the PR.

## Gates

```bash
deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root packages/plugin-streams-core --ext ts,tsx
deno run --allow-read --allow-run .llm/tools/run-deno-lint.ts --root packages/plugin-streams-core --ext ts,tsx
deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root packages/plugin-streams-core --ext ts,tsx
deno task --cwd packages/plugin-streams-core test
deno task doc:lint --root packages/plugin-streams-core --pretty
```

**A2 (binding):** `arch:check` at `deno.json:156` **confirmed does not include**
`packages/plugin-streams-core`. So run `deno task quality:gate` **and** an **explicit target scan over
`packages/plugin-streams-core/src`**, and state in the PR that the package-quality verdict rests on
the explicit scan, not the repo gate. Do not report a green repo gate as proof for this package.

Use `deno task --cwd <pkg> test`, never a bare `deno test <path>` (omits `--allow-env`, exits 1 on
`NotCapable`). No `e2e:cli` — this slice does not touch scaffold output.

## Commit trail

PR **#1559 already exists** as a draft at plan phase. Commit onto its branch, push by explicit
refspec, and post a `[PHASE: IMPL]` comment with commit hash and pasted real gate output. Update the
PR body's Definition of Done to match what shipped. `Closes #1548` is already in its Scope. Move the
label from `status:plan-eval` to `status:impl` when you push.

## Reporting contract

Report what changed, the exact test names and what each catches, verbatim gate output, and anything
you could not verify. **Do not flip the PR to ready** — that fires the automatic IMPL-EVAL and is the
orchestrator's trigger to pull. Merge authority is the orchestrator's.
143 changes: 143 additions & 0 deletions .llm/runs/release-0.0.6-features--orchestration/slices/plan-1548.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Plan — #1548 browser stream resolver cannot see Aspire VITE service references

Lane: 0.0.6 runtime reopen. Control PR #1555. Research: `slices/research-1548.md`.
Branch: `fix/1548-vite-browser-stream-discovery`. **Goes to PLAN-EVAL before implementation** via the
`openhands` + `status:plan-eval` label pair (automatic policy, D-4/D-5).

## Contract

`createNetScriptStreamDB({ streamPath, schema })` with **no `baseUrl`** must resolve
`VITE_services__streams__http__0` (or `VITE_STREAMS_URL`) in a Fresh/Vite browser bundle and connect,
instead of throwing "Durable streams URL not found…". The consumer-side
`baseUrl: import.meta.env.VITE_… ?? …` workaround must become unnecessary.

## Root cause (verified from repo code, not from claims about Vite)

Two independent reasons the value cannot be statically substituted —
`packages/plugin-streams-core/src/application/stream-url-resolver.ts`:

1. `import.meta` is passed **as a value** into `readImportMetaEnvironment` (`:60`), which reaches
`meta.env` through a parameter binding (`:77-78`). The literal expression
`import.meta.env.VITE_services__streams__http__0` never appears in source.
2. Even given a bag, both keys are read by **computed index** (`:64,:68`).

**The decisive corroboration is internal, which is why this does not rest on an assertion about
Vite.** This repo's own Vite plugin injects env by emitting `define` entries keyed exactly as
`` `import.meta.env.${mapping.target}` `` (`packages/fresh/src/application/vite/vite.ts:195,311-335`).
That is textual static-expression substitution by construction — it cannot reach a value-passed
`import.meta` or a computed index. The failure is fully explained by this repo's own machinery.

Aggravating factor: the browser branch is wrapped in a silent
`try { … } catch { return undefined }` (`:59,69-71`), so the diagnostic surfaces as a generic
"not found" rather than anything pointing at env reading.

## Locked decisions

- **D1 — read the two browser keys as literal static member expressions**, inline in the module:
`import.meta.env.VITE_services__streams__http__0` and `import.meta.env.VITE_STREAMS_URL`. No value
passing of `import.meta`, no computed index for these two keys. This is safe because the key
strings are **fully known at compile time** — `STREAMS_RESOURCE_NAME` is a constant
(`packages/plugin-streams-core/src/domain/constants.ts:5`). The generic
`serviceName`/`protocol`/`index` parameterisation is what made the keys computed; for the browser
path it buys nothing and costs substitutability.
- **D2 — split the pure lookup from the `import.meta` access**, mirroring the SDK precedent
`packages/sdk/src/discovery/browser-env.ts:35-54,65`, whose pure
`getBrowserServiceUrlFromEnv(env, …)` is unit-tested at
`packages/sdk/tests/discovery/env-ordering_test.ts:24,41,56`. The pure function takes an injected
env bag; only a thin inline shim touches `import.meta.env.*`.
- **D3 — no published-surface growth.** The pure function stays **internal**: not added to
`packages/plugin-streams-core/mod.ts`, which exports only `buildStreamUrl`, `getStreamsAuth`,
`getStreamsUrl` (`mod.ts:19`). Tests import it by src path, as this repo's tests already do.
- **D4 — resolution precedence is unchanged**: `DURABLE_STREAMS_URL` → `services__streams__http__0`
→ browser `VITE_*` (full key before shorthand) → throw. This slice changes **how** the browser
branch reads, not **what** wins.
- **D5 — no Vite `transform` hook, and no scaffold-template change in this slice.** The transform
option would couple the framework to a bundler's module graph; the `envMappings` route
(`vite.ts:76-83,183-199`) only helps once the read is substitutable, so it is a possible follow-up,
not part of the fix. Adding it here would widen a p1 into CLI-template territory.
- **D6 — the silent `catch` (`:59,69-71`) may be narrowed so a genuine throw is distinguishable from
"absent", but must not change which value wins.** Explicitly bounded so it does not become a
diagnostics refactor.

## The testability trap this plan has to solve

A unit test cannot easily prove "Vite substituted the expression" without running a real Vite build.
So the tests must attack the defect from both sides:

1. **Precedence tests on the pure lookup (D2)** with an injected bag — full key wins over shorthand;
shorthand used when the full key is absent; neither present → `undefined`. Mirrors
`env-ordering_test.ts`.
2. **A source-shape guard** asserting the module contains the **literal** substitutable expressions
and that the browser path does **not** pass `import.meta` across a function boundary or index
`env` by a computed key. This is deliberately a shape assertion: the defect *is* the shape, and
without this guard a future refactor back to a helper reintroduces the bug **silently and with all
behavioural tests still green** — exactly the regression class #1405's reason tests were built to
catch.
3. **A resolution test through `getStreamsUrl()`** proving the browser branch is reachable and
ordered correctly.

The plan does **not** claim a unit test proves Vite substitution. If PLAN-EVAL judges the source-shape
guard insufficient, the fallback is a built-fixture test, which is materially more expensive and
should be argued for explicitly rather than assumed.

## Slices

- **S1** — D1 + D2 + D3 + D4 with tests 1–3.
- **S2** — D6 only if it stays trivial; otherwise dropped and recorded.

## Gates

Scoped check/lint/fmt over `packages/plugin-streams-core`, `deno task quality:gate` (**verify it
covers this package — it demonstrably omits several, tracked as #1542; if not covered, run an
explicit target scan and say so**), `deno task --cwd packages/plugin-streams-core test`,
`deno task doc:lint`. No `e2e:cli` — this slice does not touch scaffold output.

## Risks

- **R1** — the fix is only provable end-to-end in a real Vite build; the source-shape guard is a
proxy. Stated openly above rather than papered over.
- **R2** — `getStreamsAuth()` is Deno-only (`:138-141`) and returns `{}` in a browser. Out of scope
here, but if the browser path needs auth this fix alone will not deliver a working connection.
**Worth PLAN-EVAL's attention:** it may mean the issue's "connect directly to Streams" acceptance is
not fully satisfiable by URL resolution alone.
- **R3** — the AppHost actually injecting both VITE variables was **not verified** by research.

## Acceptance mapping (#1548)

| Expectation | Satisfied by | Evidence |
| --- | --- | --- |
| Zero-config browser factory resolves Aspire's canonical Vite reference | D1 + D2 + D4 | precedence tests + source-shape guard + resolution test |
| Consumer `baseUrl` workaround becomes unnecessary | D1 | the documented override remains supported, no longer required |

---

## Amendments after PLAN-EVAL (verdict PASS with conditions)

**A1 — the SDK is a *structural* precedent, not a *fix* precedent. Do not over-claim it.**
PLAN-EVAL verified that `packages/sdk/src/discovery/browser-env.ts:65` has the **same
Vite-substitutability defect** — it reads `import.meta.env` via a cast inside try/catch, so it is
*also* not a literal static member expression. What this plan borrows from the SDK is **only** the
separation of a pure, injectable lookup from the impure reader, and the fact that the pure half is
unit-tested. It must not be described anywhere as "the SDK already solved this". Both the research
note and D2 are corrected by this amendment.

Consequence worth recording: **the SDK likely has the same latent browser-discovery bug.** That is
out of scope here and is not being fixed blind, but it should be filed once this fix proves the
shape works.

**A2 — the explicit target scan is a hard gate step, not a conditional.** PLAN-EVAL confirmed
`deno.json:156` (`arch:check`) does **not** include `packages/plugin-streams-core`. So "verify
whether it is covered" is settled: it is **not**. The implementation slice's gate list must contain
an explicit target scan over `packages/plugin-streams-core/src`, and the PR must state that the
package-quality verdict rests on that scan rather than on the repo gate. Same caveat this lane
already carried on #1528 and #1536, now confirmed for this package too.

**A3 — no circular-dependency or size risk.** PLAN-EVAL verified `plugin-streams-core/deno.json`
depends only on `@netscript/telemetry` and `@std/assert` — no dependency on `packages/fresh`, so
fixing this in `plugin-streams-core` introduces no cycle, and the `createNetScriptStreamDB` call site
in `packages/fresh` needs no change. It also verified the planned ~120-150 LOC test file sits well
under the 409-LOC ceiling of the largest existing test in that package.

**Unchanged:** R1 stands as disclosed — no unit test proves Vite's `define` substitution fires in a
real build; the source-shape guard is an explicit surrogate, and PLAN-EVAL accepted it as such rather
than requiring a built fixture.
Loading
Loading