Skip to content

FE-795: Track live graph observer frontier#166

Open
lunelson wants to merge 46 commits into
nextfrom
ln/fe-795-live-over-web-rpc
Open

FE-795: Track live graph observer frontier#166
lunelson wants to merge 46 commits into
nextfrom
ln/fe-795-live-over-web-rpc

Conversation

@lunelson
Copy link
Copy Markdown
Contributor

@lunelson lunelson commented Jun 2, 2026

No description provided.

Base automatically changed from ln/fe-785-agent-graph-integration to next June 3, 2026 12:30
@lunelson lunelson marked this pull request as ready for review June 3, 2026 12:30
Copilot AI review requested due to automatic review settings June 3, 2026 12:30
@cursor
Copy link
Copy Markdown

cursor Bot commented Jun 3, 2026

PR Summary

Medium Risk
The regenerated Drizzle migration and new spec_id columns affect all graph persistence; skill/workflow changes are doc-only but change how agents select and retire scope work.

Overview
FE-795 / live-graph-observermemory/PLAN.md marks live-graph-observer in-progress, links FE-795 and branch ln/fe-795-live-over-web-rpc, and tightens verification (WebSocket/stdio brunch.updated, session/ runtime projection, D40-L). Adds a committed manual workbench at .fixtures/workbenches/live-graph-observer/README.md (cwd for TUI/web smoke, CDP-first browser loop).

Agent workflow — Prepared slices move from a single memory/CARDS.md queue to memory/cards/<frontier-id>--<slug>.md scope files (Mode: single | chain), with hybrid ln-build selection, stale-downstream invalidation between chain cards, expected touched paths (overlap-as-independence), and per-file cleanup. ln-scope, ln-plan, ln-handoff, ln-consult, ln-sync, and related skills are updated consistently.

Topology READMEsAGENTS.md defines co-located src/**/README.md as canonical layout docs. ln-build, ln-spec, ln-sync, ln-review, and ln-refactor now reconcile or audit them when seams or SPEC IDs change.

Data model — Drizzle baseline migration 0000_deep_maria_hill adds required spec_id FKs on nodes, edges, and reconciliation_need (multi-spec graph discipline).

Docs / naming — Product CLI references shift to brunch-cli; architecture copy uses session exchange (vs elicitation-exchange) where updated; new docs/architecture/pi-wrapper-comparative.md; RPC parity notes align with session.* method names.

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

lunelson and others added 17 commits June 3, 2026 14:31
- Storage: scope cards live in memory/cards/<frontier-id>--<slug>.md
  (or dev--/tooling--/docs-- prefix when not a PLAN frontier)
- File metadata header: Frontier, Status, Mode, Created
- Multi-card scope files are a bias when conditions hold, not a
  sanctioned exception. Hard anti-speculation gate leads the section.
- Overlap-as-independence-test: two proposed files for one frontier
  with overlapping primary write paths must be merged or reshaped.
- Expected touched paths (tentative) section added to full cards
  (required) and light cards (when non-trivial), using pseudo tree
  with + ~ - ? markers. Doubles as a manifest for parallel-agent
  conflict-avoidance.
- Routing updated to name scope file path explicitly when handing
  off to ln-build.

Pairs with subsequent ln-build rewrite (Card 2) and cross-reference
sweep (Card 3). Queue in memory/CARDS.md while the sweep is pending.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8c75-8051-73ee-a611-00c58c546cbe
Co-authored-by: Amp <amp@ampcode.com>
- Hybrid selection policy: explicit path arg wins; single active
  file for current frontier → pick + announce; otherwise list
  active scope files and ask via tool-ask-question. Never scan or
  pick by mtime/alphabetical.
- Stale-downstream invalidation: explicit re-orient checkpoint
  between each card in a chain. Even when ln-scope honored the
  hard anti-speculation gate, implementation can still surprise.
  Mark the rest of the chain stale and route back to ln-scope.
- Per-file deletion under memory/cards/: literal paths only; never
  bulk on the directory or with globs. Honors AGENTS.md
  file-scoped-invocations rule. Partial-done files stay in place.
  Stale files get Status: superseded and survive for ln-sync.
- Preserves: no-op commit suppression when card is already green;
  all 8 serial-execution stop conditions; canonical reconciliation
  discipline; cross-skill check before stopping.
- Expected touched paths from scope card are tentative — divergence
  is allowed with a note; significant divergence triggers
  overlap-as-independence-test recheck against other active files
  for the same frontier.

Pairs with ln-scope rewrite (Card 1, 76a2d9b). Cross-reference
sweep (Card 3) follows.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8c75-8051-73ee-a611-00c58c546cbe
Co-authored-by: Amp <amp@ampcode.com>
Mechanical update propagating the storage seam established by Cards
1+2 (ln-scope and ln-build rewrites). All 18 references to
memory/CARDS.md across the family now point at scope files under
memory/cards/ with consistent terminology.

Touched files:
- .agents/skills/ln-consult/SKILL.md (3 refs)
- .agents/skills/ln-plan/SKILL.md (3 refs)
- .agents/skills/ln-plan/assets/plan-template.md (1 ref)
- .agents/skills/ln-handoff/SKILL.md (3 refs)
- .agents/skills/ln-handoff/assets/handoff-template.md (1 ref)
- .agents/skills/ln-sync/SKILL.md (5 refs; per-file deletion rule
  added so ln-sync respects AGENTS.md file-scoped-invocations)
- .agents/skills/ln-oracles/SKILL.md (1 ref)
- docs/praxis/ln-skills.md (1 ref)
- docs/praxis/graphite-workflow.md (1 ref; clarified that multiple
  scope files for one frontier do not imply multiple branches)

memory/CARDS.md (the queue file holding this work) is marked done.
Cleanup of that file is the final step; surfacing as user decision
per the card's 'user-call at execution time' wording.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8c75-8051-73ee-a611-00c58c546cbe
Co-authored-by: Amp <amp@ampcode.com>
All three cards (ln-scope rewrite, ln-build rewrite, cross-reference
sweep) landed in 76a2d9b, 98537ea, ee05769. Under the new regime
this skill family established, scope files live under memory/cards/
and stale derivative queues are deleted per-file (ln-sync rule).

This file held the work that defined that rule; honoring it here is
the final tie-off. Rationale preserved in git history + thread
T-019e8c75-8051-73ee-a611-00c58c546cbe.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8c75-8051-73ee-a611-00c58c546cbe
Co-authored-by: Amp <amp@ampcode.com>
… workbench

Mise-en-place Card 1 of live-graph-observer. Renames the npm package and
its single bin entry to 'brunch-cli', bumps version to 0.1.0, and adds a
reusable in-repo workbench cwd under .fixtures/workbenches/live-graph-observer/
so manual TUI/web smoke runs scaffold .brunch/ there rather than at the
repo root. Adds src/package-identity.test.ts as a regression oracle for
package name, version floor, single-bin discipline, and shim
executability.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8cc3-ac62-7596-b46d-dee2e8be729c
Co-authored-by: Amp <amp@ampcode.com>
Card 1 of live-graph-observer graph-rpc-spine. Establishes spec ownership
at storage, command, reader, tool, and runtime layers (D61-L). Every
graph projection and graph mutation now targets exactly one spec.

Storage:
  nodes, edges, reconciliation_need all gain a NOT NULL spec_id FK to
  specs.id. Initial drizzle migration regenerated as 0000_deep_maria_hill;
  graph_clock seed re-added manually.

Domain:
  GraphNode, GraphEdge, ReconciliationNeed carry specId. CommandExecutor
  inputs (CreateNodeInput, CreateReconNeedInput, CommitGraphInput) now
  require specId. commitGraph rejects existing refs whose spec_id differs
  from the command spec (structural_illegal). validateAndResolveBatchEdge
  emits explicit cross-spec diagnostics. createReconciliationNeed
  validates that target edge / node-pair belongs to the command spec.

Readers:
  getGraphOverview(db, specId), getNodeNeighborhood(db, specId, nodeId),
  getOpenReconciliationNeeds(db, specId) are spec-scoped. Supersession
  filtering is also spec-scoped. WorkspaceGraphRuntime.forSpec(specId)
  returns SpecScopedReaders so callers bind once instead of threading
  specId through every read.

Pi extension:
  BrunchGraphDeps now requires {specId, commandExecutor, snapshots}.
  Registrar binds specId from the selected session/spec at construction
  time; commit_graph / read_graph tool schemas never receive specId from
  the LLM. brunch-tui constructs graphDeps via graph.forSpec(workspace
  .spec.id) before passing to the extension shell.

Tests:
  New tracer src/graph/spec-ownership.test.ts proves the seven
  acceptance criteria (ownership isolation, existing ref guard,
  endpoint guard, reader guard, tool guard, schema guard).
  command-executor.test.ts and snapshot.test.ts updated to seed a spec
  in beforeEach and thread specId through all calls. Pi graph-tools and
  review-set-proposal tests likewise updated.

Verified: npm run verify (358 tests, lint, fmt, build all green).

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019e8cc3-ac62-7596-b46d-dee2e8be729c
@lunelson lunelson force-pushed the ln/fe-795-live-over-web-rpc branch from f6b8c5b to 94750e1 Compare June 3, 2026 13:39
lunelson and others added 2 commits June 3, 2026 15:41
Adds a new 'topology READMEs' section to AGENTS.md naming directory-level
README.md files under src/**/ as canonical documentation (alongside
memory/SPEC.md and memory/PLAN.md), defining their shape and drift sources.

Adds targeted hooks in the skills that touch canonical state:

- ln-sync: new row in document-roles table; new bullet in drift/ontology
  check; topology READMEs added to cross-skill preservation check.
- ln-build: new bullet in the reconciliation question list (topology
  question); new 'Topology READMEs' update rule that triggers when the
  topology question is yes; cross-skill check extended.
- ln-spec: new cross-reference integrity bullet — retired/renumbered IDs
  must be grepped and repaired in topology READMEs during the same pass.
- ln-review: new 'Topology README accuracy' sub-check under topography,
  covering ownership, SPEC IDs, dependency direction, layout sketches,
  and migration notes.
- ln-refactor: commit-ordering rule that topology README updates land in
  the same commit as the topology change they describe; Decisions section
  prompts naming touched READMEs.

Amp-Thread-ID: https://ampcode.com/threads/T-019e8dae-2e8a-72e3-9bb7-18c3a344848d
Co-authored-by: Amp <amp@ampcode.com>
Comment thread drizzle/meta/_journal.json
Copilot AI review requested due to automatic review settings June 3, 2026 14:54
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e47e24e. Configure here.

Comment thread .agents/skills/ln-build/SKILL.md
Copy link
Copy Markdown

Copilot AI left a comment

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 85 out of 87 changed files in this pull request and generated 5 comments.

Comment on lines +38 to +40
for (const update of updates) {
invalidateProductUpdate(queryClient, update as ProductUpdate);
}
Comment thread src/rpc/websocket.ts
Comment on lines 49 to 59
webSocketServer.on('connection', (webSocket) => {
webSocket.on('message', (data) => {
void handleMessage(options.handlers, data).then(({ response, method }) => {
activeRequests += 1;
void handleMessage(options.handlers, data).then((response) => {
webSocket.send(JSON.stringify(response));
if (isProductMutation(method) && !Object.hasOwn(response, 'error')) {
broadcastProductUpdate();
activeRequests -= 1;
if (activeRequests === 0) {
flushDeferredNotifications();
}
});
});
Comment thread src/rpc/websocket.ts
Comment on lines +79 to 82
function broadcastProductUpdate(notification: string): void {
for (const client of webSocketServer.clients) {
client.send(notification);
}
Comment thread src/web/routes/spec.tsx
Comment on lines +1 to +18
import { useSuspenseQuery } from '@tanstack/react-query';
import { createRoute } from '@tanstack/react-router';

import { GraphOverviewPanel } from '../features/graph/GraphOverview.js';
import { graphOverviewQueryOptions } from '../queries/graph.js';
import { workspaceSnapshotQueryOptions } from '../queries/workspace.js';
import { rootRoute, SessionPanel, WorkspaceChrome } from './root.js';

export const specRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/spec/$specId',
loader: ({ context, params }) => {
const specId = Number(params.specId);
return Promise.all([
context.queryClient.ensureQueryData(workspaceSnapshotQueryOptions(context.rpcClient)),
context.queryClient.ensureQueryData(graphOverviewQueryOptions(context.rpcClient, specId)),
]);
},
Comment on lines +79 to +83
const groups = new Map<string, GraphOverview['nodes']>();
for (const node of nodes) {
const label = `${node.plane} / ${node.kind}`;
groups.set(label, [...(groups.get(label) ?? []), node]);
}
@lunelson lunelson marked this pull request as draft June 3, 2026 17:48
@lunelson lunelson marked this pull request as ready for review June 4, 2026 11:22
Copilot AI review requested due to automatic review settings June 4, 2026 11:22
Copy link
Copy Markdown

Copilot AI left a comment

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 94 out of 97 changed files in this pull request and generated 2 comments.

Comment thread src/rpc/websocket.ts
Comment on lines 50 to 58
webSocket.on('message', (data) => {
void handleMessage(options.handlers, data).then(({ response, method }) => {
activeRequests += 1;
void handleMessage(options.handlers, data).then((response) => {
webSocket.send(JSON.stringify(response));
if (isProductMutation(method) && !Object.hasOwn(response, 'error')) {
broadcastProductUpdate();
activeRequests -= 1;
if (activeRequests === 0) {
flushDeferredNotifications();
}
});
Comment thread src/web/routes/spec.tsx
Comment on lines +12 to +17
loader: ({ context, params }) => {
const specId = Number(params.specId);
return Promise.all([
context.queryClient.ensureQueryData(workspaceSnapshotQueryOptions(context.rpcClient)),
context.queryClient.ensureQueryData(graphOverviewQueryOptions(context.rpcClient, specId)),
]);
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