Skip to content

FE-870: Renderer golden coverage and agent-context tools#217

Merged
lunelson merged 25 commits into
nextfrom
ln/fe-870-renderer-golden-context-tools
Jun 16, 2026
Merged

FE-870: Renderer golden coverage and agent-context tools#217
lunelson merged 25 commits into
nextfrom
ln/fe-870-renderer-golden-context-tools

Conversation

@lunelson

@lunelson lunelson commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Stack Context

This stack is a post-demo rehabilitation pass. The previous PRs stabilize runtime/tooling and clarify prompt/runtime topology; this PR starts the deferred renderer/context coverage frontier.

What?

  • Establishes renderer golden coverage for the selected render surfaces.
  • Tightens the agent-context tool/read path around the renderer boundary.
  • Updates the renderer/context ledgers as rows are locked or deferred.

Why?

Renderer output is lossy and LLM/user-facing, so it needs golden locks plus semantic invariants. This PR focuses on that RENDER-stage coverage without making it a ship gate.

lunelson commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@lunelson lunelson changed the title update agent system prompt paths FE-870: Renderer golden coverage and agent-context tools Jun 15, 2026
@lunelson lunelson marked this pull request as ready for review June 15, 2026 16:17
Copilot AI review requested due to automatic review settings June 15, 2026 16:17
@cursor

cursor Bot commented Jun 15, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are lint config and documentation only; import rules may fail CI if existing code violates the new boundaries, but there is no runtime behavior change in this diff.

Overview
This PR is mostly topology enforcement and planning/spec updates, not renderer implementation. The diff does not touch src/renderers/ or golden test files.

.oxlintrc.json adds no-restricted-imports overrides that encode D52-L: only graph/ (plus db/) may reach db/; renderers/ and workspace/ are isolated from adapter, transport, and domain layers; tests are exempt.

memory/PLAN.md and memory/SPEC.md reshape renderer-golden-coverage around D83-L (md-pen + TOON + tree, <workspace> / <specification> / <session>), record completed substrate/scope work and scoped graph-render migration, and introduce the web-driver-streaming (FE-873, topology A) horizon. They also note that layer import boundaries moved from redundant architecture tests to oxlint, fix .pi/agents/ paths (flat *.md vs definitions/), and add forward notes on streaming subscriptions and web-as-driver.

docs/archive/PLAN_HISTORY.md fixes a stale agent definition path in the prompt-composition coverage note.

Reviewed by Cursor Bugbot for commit d4a7050. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR advances the “renderer/context coverage frontier” by moving per-turn agent context seed rendering into session/ (so prompt composition consumes a prepared bundle), adding a cheap graph LSN read to avoid unnecessary graph/gap reads across mode/prompt recompositions, and updating the .pi/agents asset topology.

Changes:

  • Introduces composeAgentContextSeed / renderWorkspaceSeed / renderGraphSeed in src/session/agent-context-seed.ts with new golden-ish unit tests.
  • Adds latestGraphLsn and threads a latestLsn read through graph reader interfaces, plus a WorldReadCache memo in prompt composition to reuse queryGraph/getElicitationGaps when the LSN is unchanged.
  • Refactors CLI arg parsing to node:util parseArgs, and updates .pi/agents markdown layout + build asset copy step accordingly.

Reviewed changes

Copilot reviewed 28 out of 32 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/web/app.test.tsx Adds a window.scrollTo stub for jsdom-based web tests.
src/session/agent-context-seed.ts New session-owned renderer for the per-turn pushed context blocks (workspace + selected-spec graph).
src/session/agent-context-seed.test.ts Adds/adjusts tests covering workspace seed rendering and context seed composition.
src/graph/workspace-store.ts Threads a cheap LSN read (latestLsn) into spec-scoped graph readers.
src/graph/queries.ts Exposes latestGraphLsn and reuses it in queryGraph clock stamping.
src/dev/tier-2-harness.ts Allows tier-2 harness boots to override agent services; adds a no-model services helper.
src/dev/faux-harness.test.ts Updates harness stubs to satisfy the new latestLsn reader shape.
src/dev/brunch-dev.ts Centralizes BRUNCH_DEV env gating in a dev utility module.
src/app/brunch.ts Refactors CLI parsing to parseArgs; moves isBrunchDevEnabled import to src/dev/.
src/app/brunch.test.ts Updates CLI tests to match the new boolean flag parsing behavior.
src/app/brunch-tui.ts Moves isBrunchDevEnabled import and threads latestLsn into prompt graph reads.
src/app/brunch-tui.test.ts Updates prompt graph read stubs with latestLsn.
src/.pi/extensions/system-prompts/world-reads.ts Adds a memo/cache to reuse graph/gap reads when (specId, lsn) is unchanged.
src/.pi/extensions/system-prompts/world-reads.test.ts Adds tests proving read reuse vs refresh based on LSN/spec changes.
src/.pi/extensions/system-prompts/seed/workspace.ts Deleted (workspace seed rendering relocated to src/session/agent-context-seed.ts).
src/.pi/extensions/system-prompts/seed/workspace.test.ts Deleted (tests relocated to src/session/agent-context-seed.test.ts).
src/.pi/extensions/system-prompts/seed/graph.ts Deleted (graph seed rendering relocated to src/session/agent-context-seed.ts).
src/.pi/extensions/system-prompts/index.ts Switches to WorldReadCache + composeAgentContextSeed for prompt context assembly.
src/.pi/extensions/system-prompts/compose.ts Imports readiness estimate rendering/types from the new session context-seed module.
src/.pi/extensions/runtime/state.ts Removes the definitions prompt-resource family path logic; simplifies resource locations to skills.
src/.pi/extensions/graph/index.ts Extends GraphReaders with latestLsn(specId) for cheap change detection.
src/.pi/extensions/graph/command-adapter.ts Cleans up unused graph-slice type import.
src/.pi/agents/reviewer.md Adds a reviewer agent definition markdown at the new flat path.
src/.pi/agents/README.md Updates topology docs for flat src/.pi/agents/{agent}.md layout.
src/.pi/agents/elicitor.md Adds an elicitor agent definition markdown at the new flat path.
src/.pi/tests/prompting.test.ts Updates prompt context stubs with latestLsn.
src/.pi/tests/graph-tools.test.ts Wires latestGraphLsn into graph readers used by graph tool tests.
src/.pi/tests/extension-registry.test.ts Updates extension registry stubs with latestLsn.
package.json Updates build:pi-assets to copy flat agent markdown files (excluding README).
package-lock.json Adjusts pi-ai bin path entry (likely from lock regeneration).
memory/SPEC.md Updates spec text to reflect the new flat .pi/agents layout.
docs/archive/PLAN_HISTORY.md Updates archived plan boundary text to reflect the new .pi/agents layout.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +31 to +40
const lsn = graphReads.latestLsn(specId);
if (cached && cached.specId === specId && cached.lsn === lsn) {
return cached.reads;
}
const reads: WorldReads = {
graph: graphReads.queryGraph(),
gaps: graphReads.getElicitationGaps(specId),
};
cached = { specId, lsn, reads };
return reads;
Comment on lines +157 to +159
beforeAll(() => {
Object.defineProperty(window, 'scrollTo', { value: vi.fn(), writable: true });
});

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 148 out of 171 changed files in this pull request and generated 3 comments.

Comment on lines +124 to +134
async function collectTopology(
cwd: string,
shouldIgnore: (relativePath: string, isDirectory: boolean) => boolean,
): Promise<WorkspaceTopologyEntry> {
return {
name: '.',
kind: 'directory',
fileCount: await countVisibleFiles(cwd, cwd, shouldIgnore),
children: await collectTopologyChildren(cwd, cwd, shouldIgnore, 0),
};
}
Comment on lines +159 to +163
if (entry.isDirectory()) {
const fileCount = await countVisibleFiles(path, cwd, shouldIgnore);
const children =
depth < 1 ? await collectTopologyChildren(path, cwd, shouldIgnore, depth + 1) : undefined;
topologyEntries.push({
Comment on lines +27 to +43
export function createWorldReadCache(): WorldReadCache {
let cached: { specId: number; lsn: number; reads: WorldReads } | null = null;
return {
read(graphReads, specId) {
const lsn = graphReads.latestLsn(specId);
if (cached && cached.specId === specId && cached.lsn === lsn) {
return cached.reads;
}
const reads: WorldReads = {
graph: graphReads.queryGraph(),
gaps: graphReads.getElicitationGaps(specId),
};
cached = { specId, lsn, reads };
return reads;
},
};
}
@graphite-app graphite-app Bot changed the base branch from ln/fe-869-runtime-topology-cleanup to graphite-base/217 June 16, 2026 16:51
lunelson and others added 16 commits June 16, 2026 16:55
The per-turn pushed context blocks (workspace + graph seeds) are a
session-context-composition concern, not a system-prompt one. Relocate
them and the AgentPrompt*Context types + renderSoftReadinessEstimate from
.pi/extensions/system-prompts into src/session/agent-context-seed.ts, so
the prompt layer consumes a context bundle it no longer owns. The Pi
extension performs the PULL (queryGraph) and delegates RENDER/COMPOSE to
composeAgentContextSeed. Verbatim move; output and tests unchanged.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecb11-98d3-716c-9224-f95c9e6b28ca
Co-authored-by: Amp <amp@ampcode.com>
Per-turn prompt composition re-ran the expensive SQL pair queryGraph +
getElicitationGaps every turn, even when the graph was unchanged (e.g.
cycling operational modes / agent prompts). Add a cheap latestGraphLsn
reader path and a world-read memo that gates those reads behind the
per-spec graph clock: unchanged (spec, lsn) reuses prior reads, a changed
LSN or spec refreshes. Lens-dependent seed rendering still happens fresh
per prompt; only the underlying reads are cached.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecb11-98d3-716c-9224-f95c9e6b28ca
Co-authored-by: Amp <amp@ampcode.com>
Move the command input/result contract types and the structural-validation
subsystem out of command-executor.ts (1439 → 916 lines) into two
semantically-named subtree modules, mirroring the existing graph-mutation-types
split. The root keeps the CommandExecutor class, the seeded elicitation-gap
floor, and the public re-export barrel, so the external API surface is
unchanged. Topology README updated to register both modules.
…le battery

Consolidate the scattered web-as-driver / streaming / subscriptions intentions
into one Horizon frontier (web-driver-streaming) with topology A confirmed:
relay the in-process AgentSession event stream over the existing Brunch WS,
multiplexed with Brunch domain notifications, plus a web command-intake path.
A' rejected (Pi ships no TUI-over-RPC); B documented as the isolation-only
alternative. Records the oracle battery (stream<->transcript differential,
domain-projection multiplexing, mid-stream exchange convergence, reconnect,
fan-out) on the tier-2 faux substrate; render feel stays outer-loop manual.
Relaxation: one driver, many observers (no concurrent multi-driver).

SPEC Verification Design: new middle-loop oracle row; fire the subscription
reconnect/resume blind spot; soften the staging decisions D49-L (polling ->
streaming subscription), D72-L (web read-only -> driver), and D5-L (agent-as-user
split: public-RPC contract probe vs tier-2 mission engine) with forward notes
so they stop reading as permanent locks.

memory/ only; src/** README revisions, Linear issue, and build branch deferred.
Port the layer import boundaries (db only from graph, renderers isolation,
workspace leaf isolation) into .oxlintrc.json via no-restricted-imports,
with graph/db and test files exempted. Delete the architecture/topology
tests that merely restated these static checks, keeping only the content
and seam invariants that lint cannot express.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecbe5-9952-77d9-ae20-374b0f9ad949
Co-authored-by: Amp <amp@ampcode.com>
Update I26-L coverage and the Verification Design architectural-boundary
row to note the no-direct-db-imports-outside-graph boundary (plus
renderers/workspace isolation) is now enforced by oxlint
no-restricted-imports rather than grep tests. Add lint-first guidance and
a completion note to the topology-readmes-and-boundaries frontier.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecbe5-9952-77d9-ae20-374b0f9ad949
Co-authored-by: Amp <amp@ampcode.com>
The claimed post-build:web drizzle/sqliteTable bundle assertion does not
exist. Downgrade I44-L to partially covered: architecture.test.ts guards
leaf purity, the db->graph kinds-only edge, and enum-array ownership, and
oxlint now forbids non-graph modules from importing db/; the transitive
dist-web-Drizzle-free claim is a structural expectation, not test-verified.

Amp-Thread-ID: https://ampcode.com/threads/T-019ecbe5-9952-77d9-ae20-374b0f9ad949
Co-authored-by: Amp <amp@ampcode.com>
Move co-located *.test.ts(x) into per-directory __tests__/ folders so test
topology is consistent and compatible with pi auto-discovery. Tests under
src/.pi/extensions/*/ stay co-located by design; src/.pi/__tests__/ keeps the
cross-extension suites.

Consolidate test helpers under __tests__/support/ and drop re-export shims in
favor of importing from canonical locations:
- graph fixture-reads helper -> src/graph/__tests__/support/fixture-reads.ts
  (removes the renderers/graph re-export shim)
- create-only-mutation -> src/graph/__tests__/support/
- tier-2-test-support -> src/dev/__tests__/support/

Repair relative imports and import.meta.url/HERE-relative filesystem paths
(fixtures, drizzle migrations, source-reading assertions, repo-root reads) for
the deeper test locations. Production projection present-review-set.ts stays in
src/projections/exchanges/.
   Fold dedicated previews.test.ts files into per-renderer co-located __tests__/,
   drop lockPreview/mkdirSync/HERE scaffolding for bare toMatchFileSnapshot, move
   system-prompts tests into __tests__/, repoint dead test:prompts script. Goldens
   regenerated (trailing-newline only).

Signed-off-by: Lu Nelson <ln@hash.ai>
…clustering)

Refine D60-L RENDER stage: agent context adopts one dialect — md-pen markdown
frame, TOON for uniform record sets, stringify-tree for hierarchy, section-tag
wrappers — clustered into workspace/specification/session scopes (D19-L). The
md-pen substrate is shared across renderer audiences; workspace.state print
stays a product-state projection. Lexicon and renderers README reconciled.
Frontier reshaped from 'lock existing renderers' to 'adopt the context-render
house style (md-pen + TOON + stringify-tree) and rewrite the scope-clustered
context renders, workspace + specification first, then migrate the rest'. Add
FE-870 / branch, the new library dependencies, the countTurnEntries audit and
brunch-print fork as acceptance, and supersede the old prepared chain card
(Cards 2-5 locked the old flat shape; re-author via ln-scope).
…+ workspace + specification)

Mode: chain. Card 1 substrate adoption (md-pen + TOON + stringify-tree +
section helper) is buildable now; Cards 2-3 (workspace, specification context
renders) are design-gated — structural scope settled, exact output shape awaits
a collaborative design pass appended before build. Retire the superseded
render-stage-chain card; repoint the frontier execution pointer.
lunelson added 9 commits June 16, 2026 16:55
Signed-off-by: Lu Nelson <ln@hash.ai>
…+ refine D83-L TOON rule

Card 2 design APPROVED: bare Label: sections (Pi no-ATX-heading policy),
Project as md bullets, Specifications as md table (always), Topology as an
annotated file tree (all dirs to depth 2 with recursive counts, .md leaves).
Status flipped to next; substrate API + cwd-inventory extension noted for the
builder. D83-L refined: TOON for large/unbounded uniform sets, md tables for
small bounded rosters (size-aware, not uniformity-alone).
…+ capture graph/session-name decisions

Card 2 (workspace render) verified landed (d37c8a2). Card 3 design approved and flipped to next: Overview bullets / Sessions md-table (size-aware rule) / Gaps TOON (band-then-priority); graph block deferred to the graph-render-migration card. Captures: graph design-it-twice (overview G-D, neighborhood G-C); session auto-naming as a named adjacent capability with a revise-here obligation; countTurnEntries messages-vs-turns audit. Retire HANDOFF.md.
…(boundary, risks, posture, verification, build sequencing)

Names the harness-as-false-proof risk: the specification scope block has no existing caller, so the card wires a read_specification_context tool entry (mirrors read_workspace_context) rather than shipping a golden-only render. Build sequence: countTurnEntries audit first (settles the turns value/label the golden inherits), then inspection + render + golden, then tool registration. Seed re-cluster named as deferred adjacent work.
…factor (latestSessionName exists vs auto-naming)
…erview, G-C neighborhood, retire dead formatGraphSlice)

Scoping found the graph render surface is three renderers of differing live-ness, not one shared render: formatGraphOverview (read_graph only; stale shared docstring), formatNeighborhood (live), formatGraphSlice + variants (dead, zero non-test callers), renderGraphSeed (separate seed render). Chain: Card 0 retire dead formatGraphSlice (buildable now), Card 1 overview => G-D (design-gated), Card 2 specification graph block, Card 3 neighborhood => G-C (design-gated). Corrected the PLAN shared-render claim.
@lunelson lunelson force-pushed the graphite-base/217 branch from 52dc938 to c4e2b0b Compare June 16, 2026 16:55
@lunelson lunelson force-pushed the ln/fe-870-renderer-golden-context-tools branch from 76a6f6f to d4a7050 Compare June 16, 2026 16:55
@graphite-app graphite-app Bot changed the base branch from graphite-base/217 to next June 16, 2026 16:55
@graphite-app

graphite-app Bot commented Jun 16, 2026

Copy link
Copy Markdown

Merge activity

  • Jun 16, 4:55 PM UTC: Graphite rebased this pull request, because this pull request is set to merge when ready.

@lunelson lunelson merged commit e4a63fd into next Jun 16, 2026
12 checks passed
@lunelson lunelson deleted the ln/fe-870-renderer-golden-context-tools branch June 16, 2026 17:26
lunelson added a commit that referenced this pull request Jun 17, 2026
* update agent system prompt paths

* chore(cards): re-retire graph-render-migration card resurrected by squash merge

   The FE-870 squash merge (#217, e4a63fd) reintroduced the exhausted
   renderer-golden-coverage--graph-render-migration.md scope card in its
stale
   pre-build form (Cards 0-3 shown blocked/not-done), though Cards 0-3
shipped
   and PLAN records the scope card as retired. Re-delete it so HEAD
matches
   bkp/ln/fe-870-renderer-golden-context-tools and PLAN's "scope card
retired"
   state. No other canonical-doc drift from the restack.
lunelson added a commit that referenced this pull request Jun 17, 2026
* update agent system prompt paths

* chore(cards): re-retire graph-render-migration card resurrected by squash merge

   The FE-870 squash merge (#217, e4a63fd) reintroduced the exhausted
   renderer-golden-coverage--graph-render-migration.md scope card in its
stale
   pre-build form (Cards 0-3 shown blocked/not-done), though Cards 0-3
shipped
   and PLAN records the scope card as retired. Re-delete it so HEAD
matches
   bkp/ln/fe-870-renderer-golden-context-tools and PLAN's "scope card
retired"
   state. No other canonical-doc drift from the restack.

* FE-873: observer relay seam for live AgentSession event streaming (topology A)

   SessionEventRelay forwards the in-process AgentSession event stream over the
   existing TUI sidecar /rpc WebSocket as brunch.sessionEvent frames, multiplexed
   with brunch.updated. Ephemeral/process-local; no second canonical store (D19-L,
   D84-L). Battery claims 1-4 production-wired; claims 5-7 are follow-on slices.

Signed-off-by: Lu Nelson <ln@hash.ai>

* FE-873: reconcile web-driver plan after restack

---------

Signed-off-by: Lu Nelson <ln@hash.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants