DELETE /api/chats/[id]?mode=preserve-graph|delete-nodes (mode required): - preserve-graph: only extraction bookkeeping dies (coverage rows, legacy checkpoints) — graph ledgers byte-untouched - delete-nodes: the chat's ledger traces die. Node survival = surviving provenance point / mapping line (notes imports carry empty provenance) / surviving event. The creator's aliases + provenance are stripped from a surviving node's create line (owner ruling 2026-09-23: name/statement/createdAt are the shared identity); orphan nodes, their edges, events, mappings, positions, embedding vectors and cluster members die; cluster labels stay (immutable) Gates: 404 unknown, 409 turn_in_flight / jobs_running (with jobIds), 503 extraction_winding_down after a 10s abort-and-poll; the purge is one sync block (ledgers → jobs → chat record last). rewriteLedgers is atomic (tmp + rename). graphRevision (max mtime over graph data files) rides the activity feed + the response as the change stamp. Anti-resurrection: the chat pipeline re-checks chat liveness at each merge — a run that slips past the wind-down aborts with nothing merged or checkpointed; its partial spend dies with the chat.
70 lines
2.7 KiB
TypeScript
70 lines
2.7 KiB
TypeScript
import * as fs from "node:fs";
|
|
import { EMBEDDINGS_FILE, LEDGER_FILES, POSITIONS_FILE } from "../../config.ts";
|
|
import type { GraphSnapshot } from "../core/contracts.ts";
|
|
import type { GraphCostSummary } from "../core/cost-summary.ts";
|
|
import { graphCostSummary } from "../core/cost-summary.ts";
|
|
import { graphSnapshot } from "../core/graph.ts";
|
|
import { stores } from "./stores.ts";
|
|
|
|
/**
|
|
* Server-side graph entry for the home view (GET /api/graph). A PURE READ:
|
|
* the extraction pipeline (the sole graph writer) is triggered by quiz
|
|
* answers in sessions (turn-service), never from here — the home view
|
|
* reflects whatever the pipeline has merged so far.
|
|
*/
|
|
export function graphView(): GraphSnapshot {
|
|
return graphSnapshot(stores);
|
|
}
|
|
|
|
/** The graph view's cost surface (GET /api/graph/costs — the 2026-09 cost
|
|
* pill): fold every usage channel into stage totals + recent runs. A pure
|
|
* read over the chat records (chat-front-door runs), the notes sources
|
|
* (notes-front-door runs), and the naming ledger (graph-global runs);
|
|
* dollars are inferred by the pure core fold (core/cost-summary.ts +
|
|
* prices.ts) — nothing here stores or caches money. */
|
|
export function graphCosts(): GraphCostSummary {
|
|
const chats = stores.chatStore
|
|
.listChats()
|
|
.flatMap((summary) => {
|
|
const record = stores.chatStore.getChat(summary.id);
|
|
return record?.extractions?.length
|
|
? [{ title: record.title ?? summary.id, extractions: record.extractions }]
|
|
: [];
|
|
});
|
|
const sources = stores.graphStore
|
|
.readSources()
|
|
.filter((s) => s.extractions?.length)
|
|
.map((s) => ({ filePath: s.filePath, extractions: s.extractions! }));
|
|
return graphCostSummary({ chats, sources, naming: stores.graphStore.readNamingRuns() });
|
|
}
|
|
|
|
/** The graph's version stamp (session-deletion wave 6): the max mtime
|
|
* across every graph data file — ledgers, positions, embeddings. Moves
|
|
* on ANY graph write (merge append, settle, embed, or a deletion's
|
|
* atomic rewrite), never moves on reads, and needs no bookkeeping of
|
|
* its own: the fs IS the counter. Consumers poll it (the activity feed
|
|
* carries it; the DELETE response returns it) to know clusters/layout
|
|
* must refetch — the "graph changed underneath me" signal. */
|
|
export function graphRevision(): number {
|
|
let revision = 0;
|
|
for (const file of [
|
|
LEDGER_FILES.nodes,
|
|
LEDGER_FILES.edges,
|
|
LEDGER_FILES.events,
|
|
LEDGER_FILES.mappings,
|
|
LEDGER_FILES.sessions,
|
|
LEDGER_FILES.coverage,
|
|
LEDGER_FILES.clusterLabels,
|
|
LEDGER_FILES.namingRuns,
|
|
POSITIONS_FILE,
|
|
EMBEDDINGS_FILE,
|
|
]) {
|
|
try {
|
|
revision = Math.max(revision, fs.statSync(file).mtimeMs);
|
|
} catch {
|
|
/* absent — nothing has ever written it */
|
|
}
|
|
}
|
|
return revision;
|
|
}
|