FE-795: Track live graph observer frontier#166
Conversation
PR SummaryMedium Risk Overview Agent workflow — Prepared slices move from a single Topology READMEs — Data model — Drizzle baseline migration Docs / naming — Product CLI references shift to Reviewed by Cursor Bugbot for commit 28750cd. Bugbot is set up for automated code reviews on this repo. Configure here. |
- 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
f6b8c5b to
94750e1
Compare
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>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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.
| for (const update of updates) { | ||
| invalidateProductUpdate(queryClient, update as ProductUpdate); | ||
| } |
| 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(); | ||
| } | ||
| }); | ||
| }); |
| function broadcastProductUpdate(notification: string): void { | ||
| for (const client of webSocketServer.clients) { | ||
| client.send(notification); | ||
| } |
| 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)), | ||
| ]); | ||
| }, |
| 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]); | ||
| } |
| 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(); | ||
| } | ||
| }); |
| loader: ({ context, params }) => { | ||
| const specId = Number(params.specId); | ||
| return Promise.all([ | ||
| context.queryClient.ensureQueryData(workspaceSnapshotQueryOptions(context.rpcClient)), | ||
| context.queryClient.ensureQueryData(graphOverviewQueryOptions(context.rpcClient, specId)), | ||
| ]); |


No description provided.