@inerrata-corporation/errata 2.0.22 → 2.0.23-dev.4689

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/pass-worker.mjs CHANGED
@@ -959,10 +959,10 @@ function mergeDefs(...defs) {
959
959
  function cloneDef(schema) {
960
960
  return mergeDefs(schema._zod.def);
961
961
  }
962
- function getElementAtPath(obj, path) {
963
- if (!path)
962
+ function getElementAtPath(obj, path2) {
963
+ if (!path2)
964
964
  return obj;
965
- return path.reduce((acc, key) => acc?.[key], obj);
965
+ return path2.reduce((acc, key) => acc?.[key], obj);
966
966
  }
967
967
  function promiseAllObject(promisesObj) {
968
968
  const keys = Object.keys(promisesObj);
@@ -1274,11 +1274,11 @@ function aborted(x, startIndex = 0) {
1274
1274
  }
1275
1275
  return false;
1276
1276
  }
1277
- function prefixIssues(path, issues) {
1277
+ function prefixIssues(path2, issues) {
1278
1278
  return issues.map((iss) => {
1279
1279
  var _a2;
1280
1280
  (_a2 = iss).path ?? (_a2.path = []);
1281
- iss.path.unshift(path);
1281
+ iss.path.unshift(path2);
1282
1282
  return iss;
1283
1283
  });
1284
1284
  }
@@ -1520,7 +1520,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
1520
1520
  }
1521
1521
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
1522
1522
  const result = { errors: [] };
1523
- const processError = (error49, path = []) => {
1523
+ const processError = (error49, path2 = []) => {
1524
1524
  var _a2, _b;
1525
1525
  for (const issue2 of error49.issues) {
1526
1526
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -1530,7 +1530,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1530
1530
  } else if (issue2.code === "invalid_element") {
1531
1531
  processError({ issues: issue2.issues }, issue2.path);
1532
1532
  } else {
1533
- const fullpath = [...path, ...issue2.path];
1533
+ const fullpath = [...path2, ...issue2.path];
1534
1534
  if (fullpath.length === 0) {
1535
1535
  result.errors.push(mapper(issue2));
1536
1536
  continue;
@@ -1562,8 +1562,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1562
1562
  }
1563
1563
  function toDotPath(_path) {
1564
1564
  const segs = [];
1565
- const path = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1566
- for (const seg of path) {
1565
+ const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1566
+ for (const seg of path2) {
1567
1567
  if (typeof seg === "number")
1568
1568
  segs.push(`[${seg}]`);
1569
1569
  else if (typeof seg === "symbol")
@@ -14257,13 +14257,13 @@ function resolveRef(ref, ctx) {
14257
14257
  if (!ref.startsWith("#")) {
14258
14258
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14259
14259
  }
14260
- const path = ref.slice(1).split("/").filter(Boolean);
14261
- if (path.length === 0) {
14260
+ const path2 = ref.slice(1).split("/").filter(Boolean);
14261
+ if (path2.length === 0) {
14262
14262
  return ctx.rootSchema;
14263
14263
  }
14264
14264
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14265
- if (path[0] === defsKey) {
14266
- const key = path[1];
14265
+ if (path2[0] === defsKey) {
14266
+ const key = path2[1];
14267
14267
  if (!key || !ctx.defs[key]) {
14268
14268
  throw new Error(`Reference not found: ${ref}`);
14269
14269
  }
@@ -15535,8 +15535,8 @@ function npmPurl(name2, version3) {
15535
15535
  function component(name2, version3) {
15536
15536
  return { purl: npmPurl(name2, version3), name: name2, version: version3, ecosystem: "npm" };
15537
15537
  }
15538
- function isNpmImporterPath(path) {
15539
- return path === "" || !path.includes("node_modules/");
15538
+ function isNpmImporterPath(path2) {
15539
+ return path2 === "" || !path2.includes("node_modules/");
15540
15540
  }
15541
15541
  function parsePackageLockJson(jsonText) {
15542
15542
  let doc;
@@ -15549,22 +15549,22 @@ function parsePackageLockJson(jsonText) {
15549
15549
  const components = [];
15550
15550
  const hoisted = /* @__PURE__ */ new Map();
15551
15551
  const byPath = /* @__PURE__ */ new Map();
15552
- for (const [path, meta3] of Object.entries(packages)) {
15553
- if (path === "" || meta3.link === true) continue;
15554
- const ix = path.lastIndexOf("node_modules/");
15552
+ for (const [path2, meta3] of Object.entries(packages)) {
15553
+ if (path2 === "" || meta3.link === true) continue;
15554
+ const ix = path2.lastIndexOf("node_modules/");
15555
15555
  if (ix === -1) continue;
15556
- const name2 = path.slice(ix + "node_modules/".length);
15556
+ const name2 = path2.slice(ix + "node_modules/".length);
15557
15557
  const version3 = typeof meta3.version === "string" ? meta3.version : "";
15558
15558
  if (!name2 || !version3) continue;
15559
15559
  components.push(component(name2, version3));
15560
- byPath.set(path, { name: name2, version: version3 });
15561
- const depth = path.split("node_modules/").length;
15560
+ byPath.set(path2, { name: name2, version: version3 });
15561
+ const depth = path2.split("node_modules/").length;
15562
15562
  const prev = hoisted.get(name2);
15563
15563
  if (!prev || depth < prev.depth) hoisted.set(name2, { version: version3, depth });
15564
15564
  }
15565
15565
  const dependencies = [];
15566
- for (const [path, meta3] of Object.entries(packages)) {
15567
- const self = byPath.get(path);
15566
+ for (const [path2, meta3] of Object.entries(packages)) {
15567
+ const self = byPath.get(path2);
15568
15568
  if (!self) continue;
15569
15569
  const deps = meta3.dependencies;
15570
15570
  if (!deps || typeof deps !== "object") continue;
@@ -15577,8 +15577,8 @@ function parsePackageLockJson(jsonText) {
15577
15577
  dependencies.push({ ref: npmPurl(self.name, self.version), dependsOn });
15578
15578
  }
15579
15579
  const directRaw = [];
15580
- for (const [path, meta3] of Object.entries(packages)) {
15581
- if (!isNpmImporterPath(path)) continue;
15580
+ for (const [path2, meta3] of Object.entries(packages)) {
15581
+ if (!isNpmImporterPath(path2)) continue;
15582
15582
  for (const section of [meta3.dependencies, meta3.devDependencies, meta3.optionalDependencies]) {
15583
15583
  if (!section || typeof section !== "object") continue;
15584
15584
  for (const name2 of Object.keys(section)) {
@@ -15825,31 +15825,31 @@ function basename(p) {
15825
15825
  const ix = p.lastIndexOf("/");
15826
15826
  return ix === -1 ? p : p.slice(ix + 1);
15827
15827
  }
15828
- function parseCsproj(path, text) {
15828
+ function parseCsproj(path2, text) {
15829
15829
  const deps = [];
15830
15830
  for (const m of text.matchAll(/<PackageReference\s+Include="([^"]+)"(?:\s+Version="([^"]+)")?/g)) {
15831
- deps.push({ ecosystem: "nuget", name: m[1] ?? "", version: m[2] ?? null, kind: "package", manifest: path });
15831
+ deps.push({ ecosystem: "nuget", name: m[1] ?? "", version: m[2] ?? null, kind: "package", manifest: path2 });
15832
15832
  }
15833
15833
  for (const m of text.matchAll(/<Project\s+Sdk="([^"/]+)(?:\/([^"]+))?"/g)) {
15834
15834
  const sdk = m[1] ?? "";
15835
15835
  if (sdk.toLowerCase() !== "microsoft.net.sdk") {
15836
- deps.push({ ecosystem: "nuget", name: sdk, version: m[2] ?? null, kind: "sdk", manifest: path });
15836
+ deps.push({ ecosystem: "nuget", name: sdk, version: m[2] ?? null, kind: "sdk", manifest: path2 });
15837
15837
  }
15838
15838
  }
15839
15839
  for (const m of text.matchAll(/<TargetFramework>([^<]+)<\/TargetFramework>/g)) {
15840
15840
  const mm = /^net(\d+\.\d+)/.exec((m[1] ?? "").trim());
15841
- if (mm) deps.push({ ecosystem: "dotnet", name: "dotnet", version: mm[1] ?? null, kind: "runtime", manifest: path });
15841
+ if (mm) deps.push({ ecosystem: "dotnet", name: "dotnet", version: mm[1] ?? null, kind: "runtime", manifest: path2 });
15842
15842
  }
15843
15843
  return deps;
15844
15844
  }
15845
- function parseGodot(path, text) {
15845
+ function parseGodot(path2, text) {
15846
15846
  const m = /config\/features=PackedStringArray\(([^)]*)\)/.exec(text);
15847
15847
  if (!m) return [];
15848
15848
  const feats = (m[1] ?? "").split(",").map((f) => f.trim().replace(/^"|"$/g, "")).filter((f) => f.length > 0);
15849
15849
  const version3 = feats.find((f) => /^\d+\.\d+/.test(f)) ?? null;
15850
- return [{ ecosystem: "godot", name: "godot", version: version3, kind: "engine", manifest: path }];
15850
+ return [{ ecosystem: "godot", name: "godot", version: version3, kind: "engine", manifest: path2 }];
15851
15851
  }
15852
- function parsePackageJson(path, text) {
15852
+ function parsePackageJson(path2, text) {
15853
15853
  let obj;
15854
15854
  try {
15855
15855
  obj = JSON.parse(text);
@@ -15863,7 +15863,7 @@ function parsePackageJson(path, text) {
15863
15863
  if (!section || typeof section !== "object") continue;
15864
15864
  for (const [name2, ver] of Object.entries(section)) {
15865
15865
  const version3 = ver ? String(ver) : null;
15866
- deps.push({ ecosystem: "npm", name: name2, version: version3, kind: "package", manifest: path });
15866
+ deps.push({ ecosystem: "npm", name: name2, version: version3, kind: "package", manifest: path2 });
15867
15867
  }
15868
15868
  }
15869
15869
  return deps;
@@ -15871,7 +15871,7 @@ function parsePackageJson(path, text) {
15871
15871
  function isPep508DirectRef(spec) {
15872
15872
  return /^[A-Za-z0-9][A-Za-z0-9._-]*(?:\[[^\]]*\])?\s*@\s*\S/.test(spec.trim());
15873
15873
  }
15874
- function parseRequirements(path, text) {
15874
+ function parseRequirements(path2, text) {
15875
15875
  const deps = [];
15876
15876
  for (const raw of text.split(/\r?\n/)) {
15877
15877
  const line = (raw.split("#", 1)[0] ?? "").trim();
@@ -15883,14 +15883,14 @@ function parseRequirements(path, text) {
15883
15883
  name: m[1] ?? "",
15884
15884
  version: m[2] ? m[3] ?? null : null,
15885
15885
  kind: "package",
15886
- manifest: path,
15886
+ manifest: path2,
15887
15887
  ...isPep508DirectRef(line) ? { directRef: true } : {}
15888
15888
  });
15889
15889
  }
15890
15890
  }
15891
15891
  return deps;
15892
15892
  }
15893
- function parsePyproject(path, text) {
15893
+ function parsePyproject(path2, text) {
15894
15894
  const deps = [];
15895
15895
  const m = /^\s*dependencies\s*=\s*\[([\s\S]*?)\]/m.exec(text);
15896
15896
  if (!m) return deps;
@@ -15903,14 +15903,14 @@ function parsePyproject(path, text) {
15903
15903
  name: mm[1] ?? "",
15904
15904
  version: null,
15905
15905
  kind: "package",
15906
- manifest: path,
15906
+ manifest: path2,
15907
15907
  ...isPep508DirectRef(spec) ? { directRef: true } : {}
15908
15908
  });
15909
15909
  }
15910
15910
  }
15911
15911
  return deps;
15912
15912
  }
15913
- function parseDocker(path, text) {
15913
+ function parseDocker(path2, text) {
15914
15914
  const deps = [];
15915
15915
  for (const m of text.matchAll(/^\s*(?:image:\s*|FROM\s+(?:--platform=\S+\s+)?)["']?([^\s"']+)/gm)) {
15916
15916
  const ref = m[1] ?? "";
@@ -15920,32 +15920,32 @@ function parseDocker(path, text) {
15920
15920
  const colon = undigested.indexOf(":");
15921
15921
  const name2 = colon === -1 ? undigested : undigested.slice(0, colon);
15922
15922
  const tag = colon === -1 ? "" : undigested.slice(colon + 1);
15923
- deps.push({ ecosystem: "docker", name: name2, version: tag || null, kind: "image", manifest: path });
15923
+ deps.push({ ecosystem: "docker", name: name2, version: tag || null, kind: "image", manifest: path2 });
15924
15924
  }
15925
15925
  return deps;
15926
15926
  }
15927
- function parseGoMod(path, text) {
15927
+ function parseGoMod(path2, text) {
15928
15928
  const deps = [];
15929
15929
  for (const m of text.matchAll(/^\s*(?:require\s+)?([a-z0-9.\-]+\.[a-z]+\/[^\s]+)\s+(v[^\s]+)/gm)) {
15930
15930
  const end = (m.index ?? 0) + m[0].length;
15931
15931
  if (text.slice(end, end + 20).includes("// indirect")) continue;
15932
- deps.push({ ecosystem: "golang", name: m[1] ?? "", version: m[2] ?? null, kind: "package", manifest: path });
15932
+ deps.push({ ecosystem: "golang", name: m[1] ?? "", version: m[2] ?? null, kind: "package", manifest: path2 });
15933
15933
  }
15934
15934
  return deps;
15935
15935
  }
15936
- function parseCargo(path, text) {
15936
+ function parseCargo(path2, text) {
15937
15937
  const deps = [];
15938
15938
  const sec = /^\[dependencies\]([\s\S]*?)(?=^\[|(?![\s\S]))/m.exec(text);
15939
15939
  if (!sec) return deps;
15940
15940
  for (const m of (sec[1] ?? "").matchAll(/^\s*([A-Za-z0-9_-]+)\s*=\s*(?:"([^"]+)"|\{[^}]*version\s*=\s*"([^"]+)")/gm)) {
15941
- deps.push({ ecosystem: "cargo", name: m[1] ?? "", version: m[2] ?? m[3] ?? null, kind: "package", manifest: path });
15941
+ deps.push({ ecosystem: "cargo", name: m[1] ?? "", version: m[2] ?? m[3] ?? null, kind: "package", manifest: path2 });
15942
15942
  }
15943
15943
  return deps;
15944
15944
  }
15945
15945
  function mavenName(groupId, artifactId) {
15946
15946
  return `${groupId.trim()}:${artifactId.trim()}`;
15947
15947
  }
15948
- function parsePom(path, text) {
15948
+ function parsePom(path2, text) {
15949
15949
  const deps = [];
15950
15950
  const coord = (block) => {
15951
15951
  const g = /<groupId>([^<]+)<\/groupId>/.exec(block)?.[1];
@@ -15955,15 +15955,15 @@ function parsePom(path, text) {
15955
15955
  };
15956
15956
  for (const m of text.matchAll(/<dependency>([\s\S]*?)<\/dependency>/g)) {
15957
15957
  const c = coord(m[1] ?? "");
15958
- if (c) deps.push({ ecosystem: "maven", name: mavenName(c.g, c.a), version: c.v, kind: "package", manifest: path });
15958
+ if (c) deps.push({ ecosystem: "maven", name: mavenName(c.g, c.a), version: c.v, kind: "package", manifest: path2 });
15959
15959
  }
15960
15960
  for (const m of text.matchAll(/<parent>([\s\S]*?)<\/parent>/g)) {
15961
15961
  const c = coord(m[1] ?? "");
15962
- if (c) deps.push({ ecosystem: "maven", name: mavenName(c.g, c.a), version: c.v, kind: "sdk", manifest: path });
15962
+ if (c) deps.push({ ecosystem: "maven", name: mavenName(c.g, c.a), version: c.v, kind: "sdk", manifest: path2 });
15963
15963
  }
15964
15964
  return deps;
15965
15965
  }
15966
- function parseGradle(path, text) {
15966
+ function parseGradle(path2, text) {
15967
15967
  const deps = [];
15968
15968
  const re = new RegExp(`\\b(?:${GRADLE_CONFIGS})\\s*(?:\\(\\s*)?["']([^"']+)["']`, "g");
15969
15969
  for (const m of text.matchAll(re)) {
@@ -15975,12 +15975,12 @@ function parseGradle(path, text) {
15975
15975
  name: mavenName(group, artifact),
15976
15976
  version: version3?.trim() || null,
15977
15977
  kind: "package",
15978
- manifest: path
15978
+ manifest: path2
15979
15979
  });
15980
15980
  }
15981
15981
  return deps;
15982
15982
  }
15983
- function parseVersionCatalog(path, text) {
15983
+ function parseVersionCatalog(path2, text) {
15984
15984
  const section = /^\s*\[libraries\]([\s\S]*?)(?=^\s*\[|(?![\s\S]))/m.exec(text);
15985
15985
  if (!section) return [];
15986
15986
  const deps = [];
@@ -15991,34 +15991,34 @@ function parseVersionCatalog(path, text) {
15991
15991
  if (module2) {
15992
15992
  const [group2, artifact2] = module2.split(":");
15993
15993
  if (group2 && artifact2) {
15994
- deps.push({ ecosystem: "maven", name: mavenName(group2, artifact2), version: version3, kind: "package", manifest: path });
15994
+ deps.push({ ecosystem: "maven", name: mavenName(group2, artifact2), version: version3, kind: "package", manifest: path2 });
15995
15995
  }
15996
15996
  continue;
15997
15997
  }
15998
15998
  const group = /\bgroup\s*=\s*["']([^"']+)["']/.exec(line)?.[1];
15999
15999
  const artifact = /\bname\s*=\s*["']([^"']+)["']/.exec(line)?.[1];
16000
16000
  if (group && artifact) {
16001
- deps.push({ ecosystem: "maven", name: mavenName(group, artifact), version: version3, kind: "package", manifest: path });
16001
+ deps.push({ ecosystem: "maven", name: mavenName(group, artifact), version: version3, kind: "package", manifest: path2 });
16002
16002
  }
16003
16003
  }
16004
16004
  return deps;
16005
16005
  }
16006
- function parseGemfile(path, text) {
16006
+ function parseGemfile(path2, text) {
16007
16007
  const deps = [];
16008
16008
  for (const raw of text.split(/\r?\n/)) {
16009
16009
  const line = (raw.split("#", 1)[0] ?? "").trim();
16010
16010
  const m = /^gem\s+["']([^"']+)["']\s*(?:,\s*["']([^"']+)["'])?/.exec(line);
16011
16011
  if (!m?.[1]) continue;
16012
- deps.push({ ecosystem: "gem", name: m[1], version: m[2] ?? null, kind: "package", manifest: path });
16012
+ deps.push({ ecosystem: "gem", name: m[1], version: m[2] ?? null, kind: "package", manifest: path2 });
16013
16013
  }
16014
16014
  return deps;
16015
16015
  }
16016
- function parseGemspec(path, text) {
16016
+ function parseGemspec(path2, text) {
16017
16017
  const deps = [];
16018
16018
  for (const m of text.matchAll(
16019
16019
  /\.add_(?:runtime_|development_)?dependency\s*\(?\s*["']([^"']+)["']\s*(?:,\s*["']([^"']+)["'])?/g
16020
16020
  )) {
16021
- if (m[1]) deps.push({ ecosystem: "gem", name: m[1], version: m[2] ?? null, kind: "package", manifest: path });
16021
+ if (m[1]) deps.push({ ecosystem: "gem", name: m[1], version: m[2] ?? null, kind: "package", manifest: path2 });
16022
16022
  }
16023
16023
  return deps;
16024
16024
  }
@@ -16039,8 +16039,8 @@ function pomSelf(text) {
16039
16039
  if (artifact) self.push({ ecosystem: "maven", kind: "name", value: mavenName(group, artifact) });
16040
16040
  return self;
16041
16041
  }
16042
- function parseManifestSelf(path, text) {
16043
- const file2 = basename(path);
16042
+ function parseManifestSelf(path2, text) {
16043
+ const file2 = basename(path2);
16044
16044
  if (file2 === "package.json") {
16045
16045
  let obj;
16046
16046
  try {
@@ -16082,23 +16082,23 @@ function parseManifestSelf(path, text) {
16082
16082
  }
16083
16083
  return [];
16084
16084
  }
16085
- function parseManifest(path, text) {
16086
- const name2 = basename(path);
16087
- if (name2.endsWith(".csproj") || name2.endsWith(".fsproj")) return parseCsproj(path, text);
16088
- if (name2 === "project.godot") return parseGodot(path, text);
16089
- if (name2 === "package.json") return parsePackageJson(path, text);
16090
- if (name2.startsWith("requirements") && name2.endsWith(".txt")) return parseRequirements(path, text);
16091
- if (name2 === "pyproject.toml") return parsePyproject(path, text);
16085
+ function parseManifest(path2, text) {
16086
+ const name2 = basename(path2);
16087
+ if (name2.endsWith(".csproj") || name2.endsWith(".fsproj")) return parseCsproj(path2, text);
16088
+ if (name2 === "project.godot") return parseGodot(path2, text);
16089
+ if (name2 === "package.json") return parsePackageJson(path2, text);
16090
+ if (name2.startsWith("requirements") && name2.endsWith(".txt")) return parseRequirements(path2, text);
16091
+ if (name2 === "pyproject.toml") return parsePyproject(path2, text);
16092
16092
  if (name2.startsWith("docker-compose") || name2.startsWith("compose") || name2.startsWith("Dockerfile")) {
16093
- return parseDocker(path, text);
16094
- }
16095
- if (name2 === "go.mod") return parseGoMod(path, text);
16096
- if (name2 === "libs.versions.toml") return parseVersionCatalog(path, text);
16097
- if (name2 === "Cargo.toml") return parseCargo(path, text);
16098
- if (name2 === "pom.xml") return parsePom(path, text);
16099
- if (name2 === "build.gradle" || name2 === "build.gradle.kts") return parseGradle(path, text);
16100
- if (name2 === "Gemfile") return parseGemfile(path, text);
16101
- if (name2.endsWith(".gemspec")) return parseGemspec(path, text);
16093
+ return parseDocker(path2, text);
16094
+ }
16095
+ if (name2 === "go.mod") return parseGoMod(path2, text);
16096
+ if (name2 === "libs.versions.toml") return parseVersionCatalog(path2, text);
16097
+ if (name2 === "Cargo.toml") return parseCargo(path2, text);
16098
+ if (name2 === "pom.xml") return parsePom(path2, text);
16099
+ if (name2 === "build.gradle" || name2 === "build.gradle.kts") return parseGradle(path2, text);
16100
+ if (name2 === "Gemfile") return parseGemfile(path2, text);
16101
+ if (name2.endsWith(".gemspec")) return parseGemspec(path2, text);
16102
16102
  return [];
16103
16103
  }
16104
16104
  function buildSpine(sha2, manifestPaths2, readText) {
@@ -16172,7 +16172,7 @@ var init_history_read = __esm({
16172
16172
  "../../packages/shared/src/history-read.ts"() {
16173
16173
  "use strict";
16174
16174
  init_history_dependencies();
16175
- CLOUD_ATTR_DUPLICATE_KEYS = ["attrsJson", "embedding"];
16175
+ CLOUD_ATTR_DUPLICATE_KEYS = ["attrsJson", "embedding", "structEmbedding", "structEmbeddedAt"];
16176
16176
  }
16177
16177
  });
16178
16178
 
@@ -16184,7 +16184,7 @@ var init_history_temporal = __esm({
16184
16184
  });
16185
16185
 
16186
16186
  // ../../packages/shared/src/history-revision.ts
16187
- var Sha, HistoryRevisionRequestSchema;
16187
+ var Sha, HistoryRevisionRequestSchema, HistoryCarryRequestSchema, HISTORY_REVIEW_BUDGET, HISTORY_REVIEW_POLICY;
16188
16188
  var init_history_revision = __esm({
16189
16189
  "../../packages/shared/src/history-revision.ts"() {
16190
16190
  "use strict";
@@ -16204,6 +16204,17 @@ var init_history_revision = __esm({
16204
16204
  dependencyContext: HistoryDependencyContextSchema.optional()
16205
16205
  })).max(50)
16206
16206
  });
16207
+ HistoryCarryRequestSchema = external_exports.strictObject({
16208
+ fromCommit: Sha,
16209
+ atCommit: Sha,
16210
+ parents: external_exports.array(external_exports.strictObject({ commit: Sha, parents: external_exports.array(Sha).max(32) })).max(8192),
16211
+ /** Every symbol in a file the range changed, both sides; `null` = too many to name, treat all as changed. */
16212
+ changedSymbols: external_exports.array(external_exports.string().regex(/^sym_[a-f0-9]{8,64}$/)).max(5e3).nullable(),
16213
+ /** Manifests the range changed; `null` = a lockfile (or too many manifests) changed, treat all as changed. */
16214
+ changedManifests: external_exports.array(external_exports.string().regex(/^hmanifest_[a-f0-9]{32}$/)).max(512).nullable()
16215
+ });
16216
+ HISTORY_REVIEW_BUDGET = 48e3;
16217
+ HISTORY_REVIEW_POLICY = `reviewer-view-${HISTORY_REVIEW_BUDGET}`;
16207
16218
  }
16208
16219
  });
16209
16220
 
@@ -16387,13 +16398,13 @@ function loadNodeSqlite() {
16387
16398
  process.emitWarning = original;
16388
16399
  }
16389
16400
  }
16390
- function openDatabase(path, opts) {
16391
- const db = opts ? new DatabaseSync(path, opts) : new DatabaseSync(path);
16401
+ function openDatabase(path2, opts) {
16402
+ const db = opts ? new DatabaseSync(path2, opts) : new DatabaseSync(path2);
16392
16403
  try {
16393
16404
  db.exec("PRAGMA foreign_keys = ON");
16394
16405
  } catch {
16395
16406
  }
16396
- if (path !== ":memory:" && !opts?.readOnly) {
16407
+ if (path2 !== ":memory:" && !opts?.readOnly) {
16397
16408
  try {
16398
16409
  db.exec("PRAGMA journal_mode = WAL");
16399
16410
  db.exec("PRAGMA synchronous = NORMAL");
@@ -16402,20 +16413,20 @@ function openDatabase(path, opts) {
16402
16413
  } catch {
16403
16414
  }
16404
16415
  }
16405
- const wrapStmt = (stmt) => ({
16416
+ const wrapStmt = (stmt2) => ({
16406
16417
  run: (...params) => {
16407
- const r = stmt.run(...coerceParams(params));
16418
+ const r = stmt2.run(...coerceParams(params));
16408
16419
  return {
16409
16420
  changes: Number(r.changes),
16410
16421
  lastInsertRowid: Number(r.lastInsertRowid)
16411
16422
  };
16412
16423
  },
16413
16424
  get: (...params) => {
16414
- const r = stmt.get(...coerceParams(params));
16425
+ const r = stmt2.get(...coerceParams(params));
16415
16426
  return r;
16416
16427
  },
16417
16428
  all: (...params) => {
16418
- const r = stmt.all(...coerceParams(params));
16429
+ const r = stmt2.all(...coerceParams(params));
16419
16430
  return r;
16420
16431
  }
16421
16432
  });
@@ -16476,6 +16487,548 @@ var init_sqlite_adapter = __esm({
16476
16487
  }
16477
16488
  });
16478
16489
 
16490
+ // ../../packages/local-shared/src/tag-grammar.ts
16491
+ function tagGrammarCopy() {
16492
+ const copy = [];
16493
+ for (const ref of ["its-handle", "its-id", "h", "id"]) {
16494
+ for (const build of Object.values(TAG_EXAMPLES)) copy.push(build(ref));
16495
+ }
16496
+ for (const v of TAG_VERBS) {
16497
+ copy.push(v.hint);
16498
+ if (v.taughtBy) copy.push(v.taughtBy);
16499
+ for (const q of v.qualifiers ?? []) copy.push(q.note);
16500
+ for (const l of v.lowering) {
16501
+ if (l.note) copy.push(l.note);
16502
+ if (l.knownViolation) copy.push(l.knownViolation.finding);
16503
+ }
16504
+ }
16505
+ for (const f of TAG_FENCES) copy.push(f.hint);
16506
+ return copy;
16507
+ }
16508
+ function normalizeTemplateBody(body2) {
16509
+ return body2.replace(/…|\.{3}/g, " ").replace(/\s+/g, " ").trim().replace(/^[\s,;:—–-]+|[\s,;:.—–-]+$/g, "").toLowerCase();
16510
+ }
16511
+ function deriveTagTemplates(copy) {
16512
+ const bodies = /* @__PURE__ */ new Set();
16513
+ const handles = new Set([...TAG_PLACEHOLDER_HANDLES].map((h) => h.toLowerCase()));
16514
+ for (const text of copy) {
16515
+ for (const m of text.matchAll(BRACKET_TOKEN)) {
16516
+ const token = m[1].trim().toLowerCase();
16517
+ if (!/^[!?]/.test(token) && !REAL_HANDLE_SHAPE.test(token)) handles.add(token);
16518
+ }
16519
+ }
16520
+ for (const text of copy) {
16521
+ for (const m of text.matchAll(TEMPLATE_VERB_GROUP)) {
16522
+ const body2 = normalizeTemplateBody(m[2]);
16523
+ bodies.add(body2);
16524
+ const unthreaded = normalizeTemplateBody(body2.replace(/^#[a-z][\w-]*/i, ""));
16525
+ bodies.add(unthreaded);
16526
+ const rest = normalizeTemplateBody(unthreaded.replace(BRACKET_TOKEN, (t, h) => handles.has(h.trim().toLowerCase()) ? " " : t).replace(/,/g, " "));
16527
+ bodies.add(rest);
16528
+ }
16529
+ }
16530
+ bodies.delete("");
16531
+ return { bodies, handles };
16532
+ }
16533
+ var TAG_CANONICAL_ID_PREFIXES, TAG_HANDLE_SOURCE, TAG_THREAD_SOURCE, TAG_PLACEHOLDER_HANDLES, TAG_EXAMPLES, P, S, RC, CITE_LOWERING, INSTANCE_LOWERING, TRIAGE_TO_RC, TAG_VERBS, TAG_FENCES, TAG_VERB_BY_NAME, TAG_PAREN_VERBS, TAG_GRAMMAR_OPENERS, TAG_QUOTED_PAREN_SOURCE, TAG_QUOTED_RE, TAG_QUOTED_PAREN_RE, TEMPLATE_VERB_GROUP, BRACKET_TOKEN, REAL_HANDLE_SHAPE, TAG_TEMPLATES, VERB_WORDS_SOURCE, JOINED_VERB, LEADING_VERB, ANY_VERB_WORD, QUOTED_TAG_OPENER;
16534
+ var init_tag_grammar = __esm({
16535
+ "../../packages/local-shared/src/tag-grammar.ts"() {
16536
+ "use strict";
16537
+ TAG_CANONICAL_ID_PREFIXES = ["pat", "sol", "drc", "dcause", "dfix", "dprob", "dvuln", "prob", "claim", "err"];
16538
+ TAG_HANDLE_SOURCE = String.raw`\[([a-z0-9][\w-]{0,80})\]|((?:${TAG_CANONICAL_ID_PREFIXES.join("|")})_[0-9a-f]{6,})`;
16539
+ TAG_THREAD_SOURCE = String.raw`#([a-z][\w-]{0,63})`;
16540
+ TAG_PLACEHOLDER_HANDLES = /* @__PURE__ */ new Set([
16541
+ "handle",
16542
+ "its-handle",
16543
+ "another",
16544
+ "a-third",
16545
+ "h",
16546
+ "h1",
16547
+ "h2",
16548
+ "id",
16549
+ "its-id",
16550
+ "a",
16551
+ "b",
16552
+ "\u2026",
16553
+ "..."
16554
+ ]);
16555
+ TAG_EXAMPLES = {
16556
+ prior: (ref) => `([${ref}])`,
16557
+ problem: () => `[!one line on what's wrong]`,
16558
+ vulnerability: () => `[!vuln: who can do what; observed basis @ path:line]`,
16559
+ suspectedVulnerability: () => `[?vuln: consequence; missing check]`,
16560
+ vulnerabilityThread: () => `[!#v vuln: finding here]`,
16561
+ fix: (ref) => `(fix:[${ref}])`,
16562
+ // CONSTRAINT — the native capture path for a DIFFUSE problem (a constraint/tension/
16563
+ // conflict that shaped a decision). Free text, attaches to the decision sentence the
16564
+ // agent is already writing. Full rationale in the constraint note below + prior-tags.ts.
16565
+ constraint: () => `(constraint: the limitation that forced it)`,
16566
+ // TRIAGE — routes the problem/symptom in scope to its cause. `(cause:[handle])`
16567
+ // links to a cited RootCause/Solution node; `(cause: free text)` mints a RootCause
16568
+ // from the text. Harvested in prior-tags.ts → engine.ts (see the triage note below).
16569
+ triage: (ref) => `(cause:[${ref}])`,
16570
+ // Unlike a bare cause citation, this handle names the Problem being explained.
16571
+ triageExplain: (ref) => `(cause:[${ref}] the mechanism)`,
16572
+ // The MINT form — free-text cause that mints a RootCause. Prime-time surfacing
16573
+ // (recallForFile) pastes this next to an open Problem that has no cause yet, so the
16574
+ // diagnostic moment is cued when the agent is looking at the problem. Kept here so
16575
+ // the grammar can't drift from parseInlineTags' `(cause: …)` acceptance.
16576
+ triageMint: () => `(cause: why it happens)`,
16577
+ // THREAD forms — the witness-declared symptom↔cause/fix binding. A `#id` on the
16578
+ // flag names the diagnosis thread; the same `#id` on a later verb binds to it
16579
+ // explicitly (across sentences AND turns), replacing proximity guessing. Adjacent
16580
+ // tags never need one — the id is for diagnoses that unfold over distance.
16581
+ problemThread: () => `[!#slug one line on what's wrong]`,
16582
+ causeThread: () => `(cause:#slug the mechanism)`,
16583
+ fixThread: (thread = "slug") => `(fix:#${thread} what you changed)`,
16584
+ // ATTEMPT arc — what's being tried and what didn't work. A failed attempt is a
16585
+ // witnessed NEGATIVE result: it saves the next agent the same dead end.
16586
+ tried: () => `(tried: the approach you're attempting)`,
16587
+ failed: () => `(failed: what didn't work and the dead end it rules out)`,
16588
+ // `(failed:[h] …)` on a shown SOLUTION — the refute-by-failure form the context render teaches.
16589
+ failedCite: (ref) => `(failed:[${ref}] what came back)`,
16590
+ // LINK verbs (AC epic) — bind the problem in scope to CANONICAL priors and
16591
+ // abstractions. Multi-target by design: single links are weak; ~3 links to 3
16592
+ // DIFFERENT relevant priors is the target shape (see linkBullet).
16593
+ instance: (ref) => `(instance:[${ref}],[another],[a-third])`,
16594
+ pattern: () => `(pattern: name the general shape)`,
16595
+ // DOMAIN — the abstract area a problem is about; the concept layer an
16596
+ // anchor-less problem clusters on. Mints/resolves a Domain by name.
16597
+ domain: () => `(domain: The Area)`,
16598
+ // PACKAGE/COMPONENT — agent-named public anchors (OM-agent-anchors): the
16599
+ // package a problem is ABOUT (even when not a dependency) and the
16600
+ // framework/product-level unit it concerns. Public spine anchors → the
16601
+ // knowledge can cross to the collective.
16602
+ package: () => `(package: the-package-name)`,
16603
+ component: () => `(component: The Component)`,
16604
+ aids: (ref) => `(aids:[${ref}])`,
16605
+ // SOLUTION-STRUCTURE (SS-structure) — taught in the link bullet; Solution→Solution.
16606
+ buildsOn: (ref) => `(builds-on:[${ref}])`,
16607
+ supersedes: (ref) => `(supersedes:[${ref}])`,
16608
+ alternative: (ref) => `(alternative:[${ref}])`,
16609
+ // VERDICT (VS-verdict-tags) — a judgment on a SHOWN prior, distinct from leaning on it.
16610
+ // `confirm` rides the corroborate channel (it held); `refute` the contradict channel
16611
+ // (it's wrong / didn't hold) and REQUIRES a reason. This is the inline producer the
16612
+ // evidence channels lacked — refute sat dead (contradictionPressure 0) until now, while
16613
+ // lean-on corroboration lived, because only corroboration had an inline path. Grammar
16614
+ // single-sourced with parseInlineTags' CONFIRM_PREFIX/REFUTE_PREFIX.
16615
+ confirm: (ref) => `(confirm:[${ref}])`,
16616
+ refute: (ref) => `(refute:[${ref}] one line why)`,
16617
+ // RETRACT — "not a real problem": the errata-resolved block with a disposition
16618
+ // (parseDesignResolutions, turn.ts). No inline form exists; the block is the grammar.
16619
+ retract: (id) => ["```errata-resolved", `id: ${id}`, "disposition: false_positive", "reason: why it was never a real problem", "```"].join("\n")
16620
+ };
16621
+ P = "Problem";
16622
+ S = "Solution";
16623
+ RC = "RootCause";
16624
+ CITE_LOWERING = [
16625
+ { target: RC, writes: [{ from: P, edge: "CAUSED_BY", to: RC }] },
16626
+ { target: S, writes: [{ from: P, edge: "SOLVED_BY", to: S }] },
16627
+ { target: "Pattern", writes: [{ from: P, edge: "INSTANCE_OF", to: "Pattern" }, { from: "Pattern", edge: "ANCHORED_AT", to: "File" }], note: "cite-anchor promotion after 2 sessions", decision: "d", knownViolation: { edge: "ANCHORED_AT", finding: "motif cite-anchor promotion writes a refused ANCHORED_AT" } },
16628
+ { target: "Package", writes: [{ from: P, edge: "DEPENDS_ON", to: "Package" }] },
16629
+ { target: "Language", writes: [{ from: P, edge: "OCCURS_IN", to: "Language" }] },
16630
+ { target: "Tool", writes: [{ from: P, edge: "CONCERNS", to: "Tool" }] },
16631
+ { target: "Component", writes: [{ from: P, edge: "CONCERNS", to: "Component" }] },
16632
+ { target: P, writes: [{ from: P, edge: "RELATES_TO", to: P }, { from: P, edge: "ANCHORED_AT", to: "File" }], note: "corroboration witness + cite-anchor promotion" },
16633
+ { target: "AntiPattern", writes: [{ from: P, edge: "RELATES_TO", to: "AntiPattern" }, { from: "AntiPattern", edge: "ANCHORED_AT", to: "File" }], decision: "e", knownViolation: { edge: "ANCHORED_AT", finding: "motif cite-anchor promotion writes a refused ANCHORED_AT" } },
16634
+ { target: "Technique", writes: [{ from: P, edge: "RELATES_TO", to: "Technique" }, { from: "Technique", edge: "ANCHORED_AT", to: "File" }], decision: "e", knownViolation: { edge: "ANCHORED_AT", finding: "motif cite-anchor promotion writes a refused ANCHORED_AT" } },
16635
+ { target: "Weakness", writes: [{ from: P, edge: "RELATES_TO", to: "Weakness" }], decision: "e" },
16636
+ { target: "Domain", writes: [{ from: P, edge: "RELATES_TO", to: "Domain" }], decision: "e" },
16637
+ { target: "Claim", writes: [{ from: P, edge: "RELATES_TO", to: "Claim" }, { from: "Claim", edge: "ANCHORED_AT", to: "File" }] }
16638
+ ];
16639
+ INSTANCE_LOWERING = [
16640
+ { target: "Pattern", writes: [{ from: P, edge: "INSTANCE_OF", to: "Pattern" }] },
16641
+ { target: P, writes: [{ from: P, edge: "RELATES_TO", to: P }] },
16642
+ { target: S, writes: [{ from: P, edge: "SOLVED_BY", to: S }], note: "an instance cite on a Solution claims the problem is solved by it", decision: "a" },
16643
+ { target: RC, writes: [{ from: P, edge: "CAUSED_BY", to: RC }] },
16644
+ { target: "AntiPattern", writes: [{ from: P, edge: "RELATES_TO", to: "AntiPattern" }], decision: "e" },
16645
+ { target: "Technique", writes: [{ from: P, edge: "RELATES_TO", to: "Technique" }], decision: "e" },
16646
+ { target: "Weakness", writes: [{ from: P, edge: "RELATES_TO", to: "Weakness" }], decision: "e" },
16647
+ { target: "Domain", writes: [{ from: P, edge: "RELATES_TO", to: "Domain" }], decision: "e" },
16648
+ { target: "Package", writes: [{ from: P, edge: "DEPENDS_ON", to: "Package" }] },
16649
+ { target: "Component", writes: [{ from: P, edge: "CONCERNS", to: "Component" }] }
16650
+ ];
16651
+ TRIAGE_TO_RC = [
16652
+ { from: P, edge: "TRIAGED_BY", to: "Triage" },
16653
+ { from: "Triage", edge: "INDICATES", to: RC },
16654
+ { from: P, edge: "CAUSED_BY", to: RC }
16655
+ ];
16656
+ TAG_VERBS = [
16657
+ {
16658
+ verb: "cite",
16659
+ form: "citation",
16660
+ opener: "(",
16661
+ kinds: ["prior"],
16662
+ args: "handles",
16663
+ thread: false,
16664
+ handleRequired: true,
16665
+ lowering: CITE_LOWERING,
16666
+ examples: ["prior"],
16667
+ hint: "cite a shown prior you leaned on: ([its-handle]) \u2014 handles only, no prose inside the parens",
16668
+ taught: "taught"
16669
+ },
16670
+ {
16671
+ verb: "!",
16672
+ form: "flag",
16673
+ opener: "[!",
16674
+ kinds: ["problem", "triage", "vulnerability", "fix", "prior"],
16675
+ args: "flag-body",
16676
+ thread: true,
16677
+ minText: 8,
16678
+ qualifiers: [
16679
+ { name: "vuln", taught: true, note: "[!vuln: \u2026] \u2192 Vulnerability (asserted)" },
16680
+ { name: "fixed", taught: false, note: "[!fixed: X] \u2192 read as a self-found fix" },
16681
+ { name: "resolved", taught: false, note: "[!resolved: X] \u2192 read as a self-found fix" }
16682
+ ],
16683
+ lowering: [
16684
+ { target: P, writes: [], note: "mints a Problem; `@ path[:line]` anchors it (ANCHORED_AT to code)" },
16685
+ { target: RC, writes: [...TRIAGE_TO_RC, { from: RC, edge: "CAUSED_BY", to: RC }], note: "`<-` segments: first \u2192 triage route, later \u2192 RootCause chain" },
16686
+ { target: "Vulnerability", writes: [], note: "[!vuln: \u2026]; `<-` causes stay on the finding (vulnerabilityCauses)" }
16687
+ ],
16688
+ examples: ["problem", "problemThread", "vulnerability", "vulnerabilityThread"],
16689
+ hint: "flag a problem on one line: [!what's wrong @ path:42]; fold causes with <- ; a fix goes in (fix: \u2026), not [!fixed: \u2026]",
16690
+ taught: "taught"
16691
+ },
16692
+ {
16693
+ verb: "?",
16694
+ form: "flag",
16695
+ opener: "[?",
16696
+ kinds: ["todo", "vulnerability"],
16697
+ args: "flag-body",
16698
+ thread: true,
16699
+ minText: 8,
16700
+ qualifiers: [{ name: "vuln", taught: true, note: "[?vuln: \u2026] \u2192 Vulnerability (suspected)" }],
16701
+ lowering: [{ target: P, writes: [], note: "mints a todo Problem; a fix can close it today", decision: "g" }],
16702
+ examples: ["suspectedVulnerability"],
16703
+ hint: "[?\u2026] marks an open question / todo; [?vuln: consequence; missing check] a suspected vulnerability",
16704
+ taught: "untaught",
16705
+ taughtBy: "only the [?vuln:] form is taught; the bare [?todo] form is not",
16706
+ decisions: ["g"]
16707
+ },
16708
+ {
16709
+ verb: "fix",
16710
+ form: "verb",
16711
+ opener: "(fix:",
16712
+ kinds: ["fix"],
16713
+ args: "handles-text",
16714
+ thread: true,
16715
+ minText: 12,
16716
+ lowering: [
16717
+ { target: P, writes: [{ from: P, edge: "SOLVED_BY", to: S }], note: "closes the Problem; a note \u226512 chars mints the Solution" },
16718
+ { target: "Vulnerability", writes: [{ from: "Vulnerability", edge: "SOLVED_BY", to: S }] },
16719
+ { target: RC, writes: [], note: "dropped: 'fix tag went nowhere' (not a Problem); no tag writes FIXED_BY", decision: "f" }
16720
+ ],
16721
+ examples: ["fix", "fixThread"],
16722
+ hint: "one fix per tag: (fix:[its-handle]) or (fix:#thread what you changed) \u2014 put the cause in its own (cause: \u2026)",
16723
+ taught: "taught",
16724
+ decisions: ["f"]
16725
+ },
16726
+ {
16727
+ verb: "cause",
16728
+ form: "verb",
16729
+ opener: "(cause:",
16730
+ kinds: ["triage"],
16731
+ args: "handles-text",
16732
+ thread: true,
16733
+ minText: 8,
16734
+ lowering: [
16735
+ { target: RC, writes: TRIAGE_TO_RC },
16736
+ { target: P, writes: [{ from: P, edge: "TRIAGED_BY", to: "Triage" }, { from: "Triage", edge: "INDICATES", to: RC }, { from: P, edge: "CAUSED_BY", to: RC }], note: "(cause:[problem] mechanism) \u2014 the cited Problem is the symptom; the mechanism mints the RootCause" },
16737
+ { target: S, writes: [{ from: P, edge: "TRIAGED_BY", to: "Triage" }, { from: "Triage", edge: "INDICATES", to: S }], decision: "b", knownViolation: { edge: "INDICATES", finding: "(cause:[solution]) writes a refused INDICATES \u2192 Solution" } }
16738
+ ],
16739
+ examples: ["triage", "triageExplain", "triageMint", "causeThread"],
16740
+ hint: "(cause: the mechanism you'd change) or (cause:[root-cause-handle]); bind a distant symptom with (cause:#thread \u2026)",
16741
+ taught: "taught",
16742
+ decisions: ["b"]
16743
+ },
16744
+ {
16745
+ verb: "constraint",
16746
+ form: "verb",
16747
+ opener: "(constraint:",
16748
+ kinds: ["constraint"],
16749
+ args: "text",
16750
+ thread: false,
16751
+ minText: 8,
16752
+ textRequired: true,
16753
+ lowering: [{ target: P, writes: [], note: "mints a constraint-kind Problem" }],
16754
+ examples: ["constraint"],
16755
+ hint: "(constraint: the limitation that forced the decision)",
16756
+ taught: "taught"
16757
+ },
16758
+ {
16759
+ verb: "tried",
16760
+ form: "verb",
16761
+ opener: "(tried:",
16762
+ kinds: ["attempt"],
16763
+ args: "text",
16764
+ thread: true,
16765
+ minText: 8,
16766
+ textRequired: true,
16767
+ lowering: [{ target: P, writes: [], note: "journals an attempt on the bound problem" }],
16768
+ examples: ["tried"],
16769
+ hint: "(tried: the approach) \u2014 bind with (tried:#thread \u2026)",
16770
+ taught: "taught"
16771
+ },
16772
+ {
16773
+ verb: "failed",
16774
+ form: "verb",
16775
+ opener: "(failed:",
16776
+ kinds: ["failure"],
16777
+ args: "handles-text",
16778
+ thread: true,
16779
+ minText: 8,
16780
+ textRequired: true,
16781
+ lowering: [
16782
+ { target: P, writes: [], note: "journals a failed attempt on the bound problem" },
16783
+ { target: S, writes: [], note: "(failed:[h]) refutes the cited prior (contradictionPressure); skips the label gate today", decision: "j" }
16784
+ ],
16785
+ examples: ["failed", "failedCite"],
16786
+ hint: "(failed: what didn't work); (failed:[solution] what came back) refutes a shown fix",
16787
+ taught: "taught",
16788
+ decisions: ["j"]
16789
+ },
16790
+ {
16791
+ verb: "instance",
16792
+ form: "verb",
16793
+ opener: "(instance:",
16794
+ kinds: ["instance"],
16795
+ args: "handles",
16796
+ thread: false,
16797
+ handleRequired: true,
16798
+ lowering: INSTANCE_LOWERING,
16799
+ examples: ["instance"],
16800
+ hint: "(instance:[h1],[h2],[h3]) \u2014 ~3 DIFFERENT shown priors this problem instantiates; handles only",
16801
+ taught: "taught",
16802
+ decisions: ["a", "e"]
16803
+ },
16804
+ {
16805
+ verb: "pattern",
16806
+ form: "verb",
16807
+ opener: "(pattern:",
16808
+ kinds: ["pattern"],
16809
+ args: "handle-or-text",
16810
+ thread: false,
16811
+ minText: 3,
16812
+ lowering: [{ target: "Pattern", writes: [{ from: P, edge: "INSTANCE_OF", to: "Pattern" }], note: "a handle must be a Pattern; free text resolves-or-mints one" }],
16813
+ examples: ["pattern"],
16814
+ hint: "(pattern: name the general shape) or (pattern:[shown-pattern])",
16815
+ taught: "taught"
16816
+ },
16817
+ {
16818
+ verb: "domain",
16819
+ form: "verb",
16820
+ opener: "(domain:",
16821
+ kinds: ["domain"],
16822
+ args: "text",
16823
+ thread: false,
16824
+ minText: 2,
16825
+ textRequired: true,
16826
+ lowering: [{ target: "Domain", writes: [{ from: P, edge: "PERTAIN_TO", to: "Domain" }], note: '(domain:#t X) mints a Domain named "#t X" today', decision: "k" }],
16827
+ examples: ["domain"],
16828
+ hint: "(domain: The Area) \u2014 Title Case, no thread",
16829
+ taught: "taught",
16830
+ decisions: ["k"]
16831
+ },
16832
+ {
16833
+ verb: "package",
16834
+ form: "verb",
16835
+ opener: "(package:",
16836
+ kinds: ["package"],
16837
+ args: "text",
16838
+ thread: false,
16839
+ minText: 2,
16840
+ textRequired: true,
16841
+ lowering: [{ target: "Package", writes: [{ from: P, edge: "DEPENDS_ON", to: "Package" }], note: "means 'concerns', written as DEPENDS_ON", decision: "c" }],
16842
+ examples: ["package"],
16843
+ hint: "(package: the-package-name) \u2014 the public package it's about",
16844
+ taught: "taught",
16845
+ decisions: ["c"]
16846
+ },
16847
+ {
16848
+ verb: "component",
16849
+ form: "verb",
16850
+ opener: "(component:",
16851
+ kinds: ["component"],
16852
+ args: "text",
16853
+ thread: false,
16854
+ minText: 2,
16855
+ textRequired: true,
16856
+ lowering: [{ target: "Component", writes: [{ from: P, edge: "CONCERNS", to: "Component" }] }],
16857
+ examples: ["component"],
16858
+ hint: "(component: The Component) \u2014 the framework/product unit",
16859
+ taught: "taught"
16860
+ },
16861
+ {
16862
+ verb: "aids",
16863
+ form: "verb",
16864
+ opener: "(aids:",
16865
+ kinds: ["transfer"],
16866
+ args: "handles",
16867
+ thread: true,
16868
+ handleRequired: true,
16869
+ lowering: [{ target: P, writes: [{ from: S, edge: "MAY_RESOLVE", to: P }], note: "source = the Solution in scope; non-Problem targets are skipped" }],
16870
+ examples: ["aids"],
16871
+ hint: "(aids:[problem-handle],\u2026) \u2014 other shown problems your fix might also resolve",
16872
+ taught: "taught"
16873
+ },
16874
+ {
16875
+ verb: "builds-on",
16876
+ form: "verb",
16877
+ opener: "(builds-on:",
16878
+ kinds: ["builds-on"],
16879
+ args: "handles",
16880
+ thread: true,
16881
+ handleRequired: true,
16882
+ lowering: [{ target: S, writes: [{ from: S, edge: "BUILDS_ON", to: S }] }],
16883
+ examples: ["buildsOn"],
16884
+ hint: "(builds-on:[shown-solution]) \u2014 your fix layers on it",
16885
+ taught: "taught",
16886
+ taughtBy: "linkBullet instruction text"
16887
+ },
16888
+ {
16889
+ verb: "supersedes",
16890
+ form: "verb",
16891
+ opener: "(supersedes:",
16892
+ kinds: ["supersedes"],
16893
+ args: "handles",
16894
+ thread: true,
16895
+ handleRequired: true,
16896
+ lowering: [{ target: S, writes: [{ from: S, edge: "SUPERSEDES", to: S }] }],
16897
+ examples: ["supersedes"],
16898
+ hint: "(supersedes:[shown-solution]) \u2014 your fix replaces it",
16899
+ taught: "taught",
16900
+ taughtBy: "linkBullet instruction text"
16901
+ },
16902
+ {
16903
+ verb: "alternative",
16904
+ form: "verb",
16905
+ opener: "(alternative:",
16906
+ kinds: ["alternative"],
16907
+ args: "handles",
16908
+ thread: true,
16909
+ handleRequired: true,
16910
+ lowering: [{ target: S, writes: [{ from: S, edge: "ALTERNATIVE_TO", to: S }] }],
16911
+ examples: ["alternative"],
16912
+ hint: "(alternative:[shown-solution]) \u2014 a different valid approach",
16913
+ taught: "taught",
16914
+ taughtBy: "linkBullet instruction text"
16915
+ },
16916
+ {
16917
+ verb: "confirm",
16918
+ form: "verb",
16919
+ opener: "(confirm:",
16920
+ kinds: ["confirm"],
16921
+ args: "handles",
16922
+ thread: false,
16923
+ handleRequired: true,
16924
+ lowering: [{ target: S, writes: [], note: "corroboration witness (corroborationCount), no edge" }],
16925
+ examples: ["confirm"],
16926
+ hint: "(confirm:[shown-prior]) \u2014 it held",
16927
+ taught: "taught",
16928
+ taughtBy: "verdictBullet + context render",
16929
+ decisions: ["j"]
16930
+ },
16931
+ {
16932
+ verb: "refute",
16933
+ form: "verb",
16934
+ opener: "(refute:",
16935
+ kinds: ["refute"],
16936
+ args: "handles-text",
16937
+ thread: false,
16938
+ minText: 4,
16939
+ handleRequired: true,
16940
+ textRequired: true,
16941
+ lowering: [{ target: S, writes: [], note: "contradiction witness (contradictionPressure), no edge; reason stays local" }],
16942
+ examples: ["refute"],
16943
+ hint: "(refute:[shown-prior] one line why) \u2014 the reason is required",
16944
+ taught: "taught",
16945
+ taughtBy: "verdictBullet + context render",
16946
+ decisions: ["j"]
16947
+ }
16948
+ ];
16949
+ TAG_FENCES = [
16950
+ {
16951
+ fence: "errata-problem",
16952
+ fields: ["problem", "cause", "fix", "anchor", "kind"],
16953
+ required: [["problem"]],
16954
+ taught: "untaught",
16955
+ parser: "apps/daemon/src/turn.ts parseDesignFlags",
16956
+ decisions: ["h"],
16957
+ hint: "use an inline [!\u2026] flag instead (errata-problem cause ids never meet inline ids)"
16958
+ },
16959
+ {
16960
+ fence: "errata-resolved",
16961
+ fields: ["id", "problem", "fix", "disposition", "reason"],
16962
+ required: [["id", "problem"]],
16963
+ taught: "taught",
16964
+ taughtBy: "retract form only (TAG_EXAMPLE.retract); the fix form is untaught",
16965
+ parser: "apps/daemon/src/turn.ts parseDesignResolutions",
16966
+ hint: "```errata-resolved with id: and disposition: false_positive | invalid, reason: \u2026"
16967
+ },
16968
+ {
16969
+ fence: "errata-triage",
16970
+ fields: ["presenting", "cause", "test", "fix", "drift", "route"],
16971
+ required: [["presenting", "route"], ["cause", "test"]],
16972
+ taught: "taught",
16973
+ taughtBy: "MCP errata_triage tool copy",
16974
+ parser: "packages/local-graph/src/triage.ts parseTriageFences",
16975
+ hint: "```errata-triage with presenting: and cause: (or route: + test: to answer one)"
16976
+ },
16977
+ {
16978
+ fence: "errata-abstraction",
16979
+ fields: ["candidate", "principle", "covers"],
16980
+ required: [["candidate"], ["principle"], ["covers"]],
16981
+ taught: "taught",
16982
+ taughtBy: "MCP errata_pending_abstractions tool copy",
16983
+ parser: "packages/local-graph/src/abstraction.ts parseAbstractionFences",
16984
+ hint: "```errata-abstraction with candidate:, principle:, covers: (all required)"
16985
+ },
16986
+ {
16987
+ fence: "errata-intent",
16988
+ fields: ["intent"],
16989
+ required: [["intent"]],
16990
+ taught: "taught",
16991
+ parser: "packages/local-graph/src/intent.ts parseIntentFences",
16992
+ hint: "```errata-intent with intent: what you're about to do"
16993
+ },
16994
+ {
16995
+ fence: "errata-share",
16996
+ fields: ["priors"],
16997
+ required: [["priors"]],
16998
+ taught: "taught",
16999
+ taughtBy: "subagent hand-off copy",
17000
+ parser: "packages/local-graph/src/intent.ts parseShareFence",
17001
+ hint: "```errata-share with priors: all | [h1], [h2]"
17002
+ }
17003
+ ];
17004
+ TAG_VERB_BY_NAME = new Map(
17005
+ TAG_VERBS.filter((v) => v.form === "verb").map((v) => [v.verb, v])
17006
+ );
17007
+ TAG_PAREN_VERBS = [...TAG_VERB_BY_NAME.keys()].sort((a, b) => b.length - a.length);
17008
+ TAG_GRAMMAR_OPENERS = [
17009
+ ...new Set(TAG_VERBS.filter((v) => v.form !== "citation").map((v) => v.opener))
17010
+ ];
17011
+ TAG_QUOTED_PAREN_SOURCE = String.raw`\(\s*(?:${TAG_PAREN_VERBS.map((v) => v.replace(/-/g, "\\-")).join("|")})\s*:|\(\[`;
17012
+ TAG_QUOTED_RE = new RegExp(String.raw`\[[!?]|` + TAG_QUOTED_PAREN_SOURCE, "i");
17013
+ TAG_QUOTED_PAREN_RE = new RegExp(TAG_QUOTED_PAREN_SOURCE, "i");
17014
+ TEMPLATE_VERB_GROUP = new RegExp(
17015
+ String.raw`\(\s*(${TAG_PAREN_VERBS.map((v) => v.replace(/-/g, "\\-")).join("|")})\s*:((?:[^()\n]|\([^()\n]*\))*)\)`,
17016
+ "gi"
17017
+ );
17018
+ BRACKET_TOKEN = /\[([^\]\n]{1,80})\]/g;
17019
+ REAL_HANDLE_SHAPE = new RegExp(
17020
+ String.raw`^(?:[a-z0-9]+(?:-[a-z0-9]+)*-(?=[0-9a-f]{0,3}\d)[0-9a-f]{4}|(?:${TAG_CANONICAL_ID_PREFIXES.join("|")})_[0-9a-f]{6,})$`,
17021
+ "i"
17022
+ );
17023
+ TAG_TEMPLATES = deriveTagTemplates(tagGrammarCopy());
17024
+ VERB_WORDS_SOURCE = TAG_PAREN_VERBS.map((v) => v.replace(/-/g, "\\-")).join("|");
17025
+ JOINED_VERB = new RegExp(String.raw`[,;]\s*(?=(?:${VERB_WORDS_SOURCE})\s*:)`, "i");
17026
+ LEADING_VERB = new RegExp(String.raw`^\s*(${VERB_WORDS_SOURCE})\s*:`, "i");
17027
+ ANY_VERB_WORD = new RegExp(String.raw`\b(?:${VERB_WORDS_SOURCE})\s*:`, "gi");
17028
+ QUOTED_TAG_OPENER = new RegExp(String.raw`\(\s*(?:(${VERB_WORDS_SOURCE})\s*:|(?=\[))`, "gi");
17029
+ }
17030
+ });
17031
+
16479
17032
  // ../../packages/local-shared/src/index.ts
16480
17033
  var init_src2 = __esm({
16481
17034
  "../../packages/local-shared/src/index.ts"() {
@@ -16489,6 +17042,7 @@ var init_src2 = __esm({
16489
17042
  init_review();
16490
17043
  init_anchorable();
16491
17044
  init_sqlite_adapter();
17045
+ init_tag_grammar();
16492
17046
  }
16493
17047
  });
16494
17048
 
@@ -16874,11 +17428,12 @@ function purgeWorkspaceCodeGraph(store2, workspaceId) {
16874
17428
  const edgesBefore = store2.edgeCount();
16875
17429
  store2.transaction(() => {
16876
17430
  for (const label of INDEXER_OWNED_LABELS) {
16877
- const nodes = store2.findAllVersionsByLabel(label);
17431
+ const nodes = store2.selectNodes({
17432
+ labels: [label],
17433
+ includeClosed: true,
17434
+ where: [{ attr: "workspaceId", eq: workspaceId }]
17435
+ });
16878
17436
  for (const n of nodes) {
16879
- if (n.attrs.workspaceId !== workspaceId) {
16880
- continue;
16881
- }
16882
17437
  store2.deleteNode(n.id);
16883
17438
  nodesDeleted++;
16884
17439
  }
@@ -16895,10 +17450,20 @@ function isReExportBarrel(relPath) {
16895
17450
  function graphExportMap(store2, workspaceId, relPath) {
16896
17451
  const out2 = /* @__PURE__ */ new Map();
16897
17452
  const fileId = fileNodeId(workspaceId, relPath);
16898
- if (!store2.getNode(fileId)) return out2;
16899
- for (const e of store2.outEdges(fileId, ["DEFINES"])) {
16900
- const n = store2.getNode(e.to);
16901
- if (!n || !EXPORTABLE_LABELS.has(n.label)) continue;
17453
+ if (store2.nodeLabels([fileId]).size === 0) return out2;
17454
+ const defines = store2.outEdges(fileId, ["DEFINES"]);
17455
+ const rows = /* @__PURE__ */ new Map();
17456
+ for (let i2 = 0; i2 < defines.length; i2 += 500) {
17457
+ for (const r of store2.selectNodes({
17458
+ labels: [...EXPORTABLE_LABELS],
17459
+ attrs: ["workspaceId", "name"],
17460
+ where: [{ idIn: defines.slice(i2, i2 + 500).map((e) => e.to) }],
17461
+ includeClosed: true
17462
+ })) rows.set(r.id, r);
17463
+ }
17464
+ for (const e of defines) {
17465
+ const n = rows.get(e.to);
17466
+ if (!n) continue;
16902
17467
  if (n.attrs["workspaceId"] !== workspaceId) continue;
16903
17468
  const name2 = n.attrs["name"] ?? n.description;
16904
17469
  if (!name2 || name2.startsWith("<") || name2.includes(":")) continue;
@@ -17065,14 +17630,37 @@ async function incrementalReindex(store2, rootPath, workspaceId, changedAbsPaths
17065
17630
  signatureAfter: a.signature
17066
17631
  });
17067
17632
  }
17633
+ const repointable = /* @__PURE__ */ new Map();
17068
17634
  store2.transaction(() => {
17069
17635
  for (const nid of changedIds) store2.freezeNode(nid, t);
17070
17636
  for (const nid of removedIds) {
17637
+ repointable.set(nid, store2.inEdges(nid, ["CALLS", "ACCESSES", "ANCHORED_AT"]));
17071
17638
  for (const e of store2.outEdges(nid)) store2.closeEdge(e.id, t);
17072
17639
  store2.closeNode(nid, t);
17073
17640
  }
17074
17641
  });
17075
- const r = await runIndexer(store2, {
17642
+ const seenNodes = /* @__PURE__ */ new Set();
17643
+ const seenEdges = /* @__PURE__ */ new Set();
17644
+ const writeStore = store2.mergeNodeIfChanged && store2.mergeEdgeIfChanged ? new Proxy(store2, {
17645
+ get(target, prop) {
17646
+ if (prop === "mergeNode") {
17647
+ return (n) => {
17648
+ seenNodes.add(n.id);
17649
+ if (n.label === "File" || n.label === "Folder") target.mergeNode(n);
17650
+ else target.mergeNodeIfChanged(n);
17651
+ };
17652
+ }
17653
+ if (prop === "mergeEdge") {
17654
+ return (e) => {
17655
+ seenEdges.add(edgeId(e.from, e.type, e.to));
17656
+ target.mergeEdgeIfChanged(e);
17657
+ };
17658
+ }
17659
+ const v = Reflect.get(target, prop, target);
17660
+ return typeof v === "function" ? v.bind(target) : v;
17661
+ }
17662
+ }) : store2;
17663
+ const r = await runIndexer(writeStore, {
17076
17664
  workspaceId,
17077
17665
  rootPath,
17078
17666
  providers,
@@ -17090,14 +17678,14 @@ async function incrementalReindex(store2, rootPath, workspaceId, changedAbsPaths
17090
17678
  if (typeof rel !== "string" || !changedRelPaths.has(rel)) continue;
17091
17679
  if (versionedAndFile.has(n.label)) {
17092
17680
  ownedLive.push(n.id);
17093
- } else if (n.label === "Comment" && n.lastUpdatedAt < t) {
17681
+ } else if (n.label === "Comment" && n.lastUpdatedAt < t && !seenNodes.has(n.id)) {
17094
17682
  store2.closeNode(n.id, t);
17095
17683
  }
17096
17684
  }
17097
17685
  for (const id of ownedLive) {
17098
17686
  for (const e of store2.outEdges(id)) {
17099
17687
  if (e.type === "SUPERSEDED_BY") continue;
17100
- if (e.lastSeenAt < t) {
17688
+ if (e.lastSeenAt < t && !seenEdges.has(edgeId(e.from, e.type, e.to))) {
17101
17689
  store2.closeEdge(e.id, t);
17102
17690
  delta.edgesRemoved++;
17103
17691
  } else if (e.createdAt >= t) {
@@ -17156,8 +17744,8 @@ async function incrementalReindex(store2, rootPath, workspaceId, changedAbsPaths
17156
17744
  version: b.version + 1
17157
17745
  });
17158
17746
  store2.mergeEdge(continuesEdge(m, t));
17159
- for (const e of store2.inEdges(m.fromNid, ["CALLS", "ACCESSES", "ANCHORED_AT"])) {
17160
- if (e.validTo != null) continue;
17747
+ for (const e of repointable.get(m.fromNid) ?? []) {
17748
+ if (e.from === m.fromNid || !store2.liveNodeIds([e.from]).has(e.from)) continue;
17161
17749
  const newId = edgeId(e.from, e.type, m.toNid);
17162
17750
  if (!store2.getEdge(newId)) {
17163
17751
  store2.mergeEdge({ ...e, id: newId, to: m.toNid, lastSeenAt: t });
@@ -17214,6 +17802,7 @@ async function runIndexer(store2, opts) {
17214
17802
  const maxBytes = opts.maxFileBytes ?? 1024 * 1024;
17215
17803
  const scope = opts.changedRelPaths;
17216
17804
  const inScope = (relPath) => scope === void 0 || scope.has(relPath) || isReExportBarrel(relPath);
17805
+ const emits = (relPath) => scope === void 0 || scope.has(relPath);
17217
17806
  let perfLast = started;
17218
17807
  const perfFile = process.env["ERRATA_PERF"];
17219
17808
  const perf = (label) => {
@@ -17265,7 +17854,7 @@ async function runIndexer(store2, opts) {
17265
17854
  upsertFolder(store2, rootId, ".", opts.workspaceId, rootRel);
17266
17855
  report.nodesEmitted++;
17267
17856
  for (const f of files) {
17268
- if (!inScope(f.relPath)) continue;
17857
+ if (!emits(f.relPath)) continue;
17269
17858
  const segments = f.relPath.split(/[\\/]/).slice(0, -1);
17270
17859
  let parentId = rootId;
17271
17860
  let acc = "";
@@ -17348,7 +17937,13 @@ async function runIndexer(store2, opts) {
17348
17937
  }
17349
17938
  }
17350
17939
  perf(`parse (${report.filesParsed} parsed, ${report.filesSkipped} skipped)`);
17351
- const exportsByFile = /* @__PURE__ */ new Map();
17940
+ const pendingExports = /* @__PURE__ */ new Set();
17941
+ const exportsByFile = new class extends Map {
17942
+ get(relPath) {
17943
+ if (pendingExports.delete(relPath)) super.set(relPath, graphExportMap(store2, opts.workspaceId, relPath));
17944
+ return super.get(relPath);
17945
+ }
17946
+ }();
17352
17947
  const importsByFile = /* @__PURE__ */ new Map();
17353
17948
  for (const [relPath, symbols] of symbolsByFile) {
17354
17949
  const localExports = /* @__PURE__ */ new Map();
@@ -17372,7 +17967,8 @@ async function runIndexer(store2, opts) {
17372
17967
  if (scope !== void 0) {
17373
17968
  for (const f of files) {
17374
17969
  if (inScope(f.relPath) || exportsByFile.has(f.relPath)) continue;
17375
- exportsByFile.set(f.relPath, graphExportMap(store2, opts.workspaceId, f.relPath));
17970
+ exportsByFile.set(f.relPath, /* @__PURE__ */ new Map());
17971
+ pendingExports.add(f.relPath);
17376
17972
  }
17377
17973
  }
17378
17974
  const workspacePackages = /* @__PURE__ */ new Map();
@@ -17513,6 +18109,7 @@ async function runIndexer(store2, opts) {
17513
18109
  const providerByRel = new Map(files.map((x) => [x.relPath, x.provider]));
17514
18110
  let emittedFiles = 0;
17515
18111
  for (const [relPath, symbols] of symbolsByFile) {
18112
+ if (!emits(relPath)) continue;
17516
18113
  if (emittedFiles > 0 && emittedFiles % 50 === 0) {
17517
18114
  await new Promise((r) => setImmediate(r));
17518
18115
  }
@@ -17714,9 +18311,10 @@ async function runIndexer(store2, opts) {
17714
18311
  if (ei > 0) await new Promise((r) => setImmediate(r));
17715
18312
  const slice = pendingEdges.slice(ei, ei + EDGE_BATCH);
17716
18313
  store2.transaction(() => {
18314
+ const present = store2.nodeLabels([...new Set(slice.flatMap((e) => [e.from, e.to]))]);
17717
18315
  for (const e of slice) {
17718
18316
  if (e.from === e.to) continue;
17719
- if (!store2.getNode(e.from) || !store2.getNode(e.to)) continue;
18317
+ if (!present.has(e.from) || !present.has(e.to)) continue;
17720
18318
  upsertEdge(
17721
18319
  store2,
17722
18320
  e.from,
@@ -17732,6 +18330,7 @@ async function runIndexer(store2, opts) {
17732
18330
  }
17733
18331
  perf("flush cross-file edges");
17734
18332
  for (const relPath of symbolsByFile.keys()) {
18333
+ if (!emits(relPath)) continue;
17735
18334
  const fid = fileNodeId(opts.workspaceId, relPath);
17736
18335
  if (store2.outEdges(fid, ["DEFINES", "CONTAINS"]).length === 0) {
17737
18336
  stampIndexOutcome(store2, fid, { symbolCount: 0 });
@@ -18328,14 +18927,14 @@ function unmarshalNode(tree, address = TRANSFER_BUFFER) {
18328
18927
  address += SIZE_OF_INT;
18329
18928
  const row = C.getValue(address, "i32");
18330
18929
  address += SIZE_OF_INT;
18331
- const column = C.getValue(address, "i32");
18930
+ const column2 = C.getValue(address, "i32");
18332
18931
  address += SIZE_OF_INT;
18333
18932
  const other = C.getValue(address, "i32");
18334
18933
  const result = new Node(INTERNAL, {
18335
18934
  id,
18336
18935
  tree,
18337
18936
  startIndex: index,
18338
- startPosition: { row, column },
18937
+ startPosition: { row, column: column2 },
18339
18938
  other
18340
18939
  });
18341
18940
  return result;
@@ -18425,11 +19024,11 @@ async function Module2(moduleArg = {}) {
18425
19024
  }, "quit_");
18426
19025
  var _scriptName = import.meta.url;
18427
19026
  var scriptDirectory = "";
18428
- function locateFile(path) {
19027
+ function locateFile(path2) {
18429
19028
  if (Module["locateFile"]) {
18430
- return Module["locateFile"](path, scriptDirectory);
19029
+ return Module["locateFile"](path2, scriptDirectory);
18431
19030
  }
18432
- return scriptDirectory + path;
19031
+ return scriptDirectory + path2;
18433
19032
  }
18434
19033
  __name(locateFile, "locateFile");
18435
19034
  var readAsync, readBinary;
@@ -19581,11 +20180,11 @@ async function Module2(moduleArg = {}) {
19581
20180
  }
19582
20181
  }
19583
20182
  __name(_tree_sitter_log_callback, "_tree_sitter_log_callback");
19584
- function _tree_sitter_parse_callback(inputBufferAddress, index, row, column, lengthAddress) {
20183
+ function _tree_sitter_parse_callback(inputBufferAddress, index, row, column2, lengthAddress) {
19585
20184
  const INPUT_BUFFER_SIZE = 10 * 1024;
19586
20185
  const string4 = Module.currentParseCallback(index, {
19587
20186
  row,
19588
- column
20187
+ column: column2
19589
20188
  });
19590
20189
  if (typeof string4 === "string") {
19591
20190
  setValue(lengthAddress, string4.length, "i32");
@@ -23249,10 +23848,10 @@ function collectDocstrings(root, records, out2) {
23249
23848
  }
23250
23849
  }
23251
23850
  }
23252
- function docstringIn(stmt) {
23253
- if (!stmt) return null;
23254
- if (stmt.type !== "expression_statement") return null;
23255
- const expr = stmt.namedChild(0);
23851
+ function docstringIn(stmt2) {
23852
+ if (!stmt2) return null;
23853
+ if (stmt2.type !== "expression_statement") return null;
23854
+ const expr = stmt2.namedChild(0);
23256
23855
  if (!expr) return null;
23257
23856
  if (expr.type !== "string") return null;
23258
23857
  const text = expr.text;
@@ -23523,9 +24122,9 @@ function extractNode3(node, containerQname, containerIsClass, source) {
23523
24122
  ];
23524
24123
  }
23525
24124
  case "preproc_include": {
23526
- const path = node.childForFieldName("path")?.text;
23527
- if (!path) return [];
23528
- const src = path.replace(/^[<"]|[>"]$/g, "");
24125
+ const path2 = node.childForFieldName("path")?.text;
24126
+ if (!path2) return [];
24127
+ const src = path2.replace(/^[<"]|[>"]$/g, "");
23529
24128
  return [
23530
24129
  {
23531
24130
  kind: "import",
@@ -23913,9 +24512,9 @@ function importRecords(node) {
23913
24512
  if (n.type === "import_spec") specs.push(n);
23914
24513
  });
23915
24514
  for (const spec of specs) {
23916
- const path = spec.childForFieldName("path")?.text;
23917
- if (!path) continue;
23918
- const src = path.replace(/^["`]|["`]$/g, "");
24515
+ const path2 = spec.childForFieldName("path")?.text;
24516
+ if (!path2) continue;
24517
+ const src = path2.replace(/^["`]|["`]$/g, "");
23919
24518
  out2.push({
23920
24519
  kind: "import",
23921
24520
  name: src,
@@ -24998,16 +25597,16 @@ function baseTypeName(node) {
24998
25597
  }
24999
25598
  function usingPath(node) {
25000
25599
  const alias = node.childForFieldName("name");
25001
- let path = null;
25600
+ let path2 = null;
25002
25601
  for (let i2 = 0; i2 < node.namedChildCount; i2++) {
25003
25602
  const c = node.namedChild(i2);
25004
25603
  if (!c) continue;
25005
25604
  if (alias && c.startIndex === alias.startIndex && c.endIndex === alias.endIndex) continue;
25006
25605
  if (c.type === "qualified_name" || c.type === "identifier" || c.type === "generic_name") {
25007
- path = c;
25606
+ path2 = c;
25008
25607
  }
25009
25608
  }
25010
- return path?.text ?? null;
25609
+ return path2?.text ?? null;
25011
25610
  }
25012
25611
  function calleeName4(fn) {
25013
25612
  if (!fn) return null;
@@ -25274,6 +25873,110 @@ import { parentPort, workerData } from "node:worker_threads";
25274
25873
  init_src2();
25275
25874
  init_src();
25276
25875
 
25876
+ // ../../packages/local-graph/src/wm-calibration.ts
25877
+ var WM_CALIBRATION_LABELS = [
25878
+ "Problem",
25879
+ "Solution",
25880
+ "RootCause",
25881
+ "Pattern",
25882
+ "Technique",
25883
+ "AntiPattern"
25884
+ ];
25885
+ var WM_CALIBRATION_SCHEMA = 2;
25886
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
25887
+ var WM_CALIBRATION_KEYS = [
25888
+ "shownCount",
25889
+ "evictedCount",
25890
+ "reinforceShownCount",
25891
+ "reinforceRecentCount",
25892
+ "reinforceEvictedCount",
25893
+ "reinforceUnshownCount",
25894
+ "reinforceUnshownQueryOnlyCount"
25895
+ ];
25896
+ var WM_COUNTED_PREDICATE = WM_CALIBRATION_KEYS.map((k) => `json_type(attrs_json, '$.${k}') IS NOT NULL`).join(" OR ");
25897
+ var wmCounterSql = (k) => `CASE WHEN json_type(attrs_json, '$.${k}') IN ('integer', 'real') THEN json_extract(attrs_json, '$.${k}') END`;
25898
+ function wmCalibrationCells(store2) {
25899
+ const cells = {
25900
+ calibrationSchema: WM_CALIBRATION_SCHEMA,
25901
+ shownNodes: 0,
25902
+ shownImpressions: 0,
25903
+ evictedNodes: 0,
25904
+ evictedImpressions: 0,
25905
+ reinforceShown: 0,
25906
+ reinforceRecent: 0,
25907
+ reinforceEvicted: 0,
25908
+ reinforceUnshown: 0,
25909
+ reinforceUnshownQueryOnly: 0,
25910
+ reinforcedNodes: 0,
25911
+ reinforcedShownNodes: 0
25912
+ };
25913
+ const newest = /* @__PURE__ */ new Map();
25914
+ const rows = store2.wmCalibrationRows?.(WM_CALIBRATION_LABELS) ?? (function* () {
25915
+ for (const label of WM_CALIBRATION_LABELS) {
25916
+ yield* store2.selectNodes({ labels: [label], attrs: WM_CALIBRATION_KEYS, includeClosed: true });
25917
+ }
25918
+ })();
25919
+ for (const n of rows) {
25920
+ const live = n.validTo === null;
25921
+ const prev = newest.get(n.logicalId);
25922
+ if (prev && (prev.live || !live && prev.version >= n.version)) continue;
25923
+ newest.set(n.logicalId, { version: n.version, live, attrs: n.attrs });
25924
+ }
25925
+ for (const { attrs } of newest.values()) {
25926
+ const shown = num(attrs["shownCount"]);
25927
+ const evicted = num(attrs["evictedCount"]);
25928
+ if (shown > 0) {
25929
+ cells.shownNodes++;
25930
+ cells.shownImpressions += shown;
25931
+ }
25932
+ if (evicted > 0) {
25933
+ cells.evictedNodes++;
25934
+ cells.evictedImpressions += evicted;
25935
+ }
25936
+ const rs = num(attrs["reinforceShownCount"]);
25937
+ const rr = num(attrs["reinforceRecentCount"]);
25938
+ const re = num(attrs["reinforceEvictedCount"]);
25939
+ const ru = num(attrs["reinforceUnshownCount"]);
25940
+ cells.reinforceShown += rs;
25941
+ cells.reinforceRecent += rr;
25942
+ cells.reinforceEvicted += re;
25943
+ cells.reinforceUnshown += ru;
25944
+ cells.reinforceUnshownQueryOnly += num(attrs["reinforceUnshownQueryOnlyCount"]);
25945
+ if (rs + rr + re + ru > 0) cells.reinforcedNodes++;
25946
+ if (rs > 0) cells.reinforcedShownNodes++;
25947
+ }
25948
+ return cells;
25949
+ }
25950
+
25951
+ // ../../packages/local-graph/src/exposure-attrs.ts
25952
+ var EXPOSURE_ATTRS = [
25953
+ "shownCount",
25954
+ "evictedCount",
25955
+ "firstShownAt",
25956
+ "firstEvictedAt",
25957
+ "firstShownAtSeq",
25958
+ "lastShownAtSeq",
25959
+ "lastEvictedAtSeq",
25960
+ "shownSinceTouch",
25961
+ "shownSinceTouchAt",
25962
+ "exposureLog",
25963
+ "exposureLogStart",
25964
+ "exposureLogSince",
25965
+ "exposureFirst",
25966
+ "exposureTrimmed"
25967
+ ];
25968
+ var EXPOSURE_SCOPE = "exposure";
25969
+ var EXPOSURE_KEYS = new Set(EXPOSURE_ATTRS);
25970
+ var isExposureAttr = (key) => EXPOSURE_KEYS.has(key);
25971
+ function pickExposure(attrs) {
25972
+ const out2 = {};
25973
+ for (const k of EXPOSURE_ATTRS) if (attrs[k] !== void 0) out2[k] = attrs[k];
25974
+ return out2;
25975
+ }
25976
+ function exposureDocSql(key) {
25977
+ return `coalesce((SELECT x.attrs_json FROM node_exposure x WHERE x.id = nodes.id AND json_type(x.attrs_json, '$.${key}') IS NOT NULL), attrs_json)`;
25978
+ }
25979
+
25277
25980
  // ../../packages/local-graph/src/history-cache-floor.ts
25278
25981
  var HISTORY_CACHE_FLOOR_KEY = "history-cache-withdrawal-floor-3";
25279
25982
  function installHistoryCacheFloor(db) {
@@ -25314,7 +26017,7 @@ function installHistoryCacheFloor(db) {
25314
26017
  OR EXISTS(SELECT 1 FROM history_cache_withdrawals w WHERE w.id = nodes.id))
25315
26018
  AND (embedding_blob IS NOT NULL OR embedding_json <> '[]' OR is_landmark <> 0
25316
26019
  OR description <> ${description} OR attrs_json <> ${attrs});`;
25317
- const internal = `key IN ('orgId','teamId','groupId','projectId','aliasTexts','aliasCanonicalIds')
26020
+ const internal = `key IN ('orgId','teamId','groupId','projectId','aliasTexts','aliasCanonicalIds','residueAudienceVerified')
25318
26021
  OR key GLOB 'mergedFrom*' OR key GLOB '*WitnessKeys' OR key GLOB '*Sessions'
25319
26022
  OR key GLOB 'authoringSession*' OR key GLOB 'contributor*' OR key GLOB 'witnessKeys*'`;
25320
26023
  const stripMetadata = (scope) => `UPDATE nodes SET attrs_json=(
@@ -25450,7 +26153,9 @@ function installEditPlaceholderRetirement(db) {
25450
26153
 
25451
26154
  // ../../packages/local-graph/src/cloud-attr-compaction.ts
25452
26155
  init_src2();
25453
- var CLOUD_ATTR_COMPACTION_KEY = "cloud-attr-compaction-1";
26156
+ var CLOUD_ATTR_COMPACTION_KEY = "cloud-attr-compaction-2";
26157
+ var V1_KEY = "cloud-attr-compaction-1";
26158
+ var STRUCT_LABELS = "('Problem', 'Solution', 'RootCause')";
25454
26159
  var DUPES = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `'${k}'`).join(",");
25455
26160
  function compacted(row) {
25456
26161
  const packed = `json_extract(${row}.attrs_json, '$.attrsJson')`;
@@ -25469,14 +26174,17 @@ function dirty(row) {
25469
26174
  return `json_extract(${row}.attrs_json, '$.source') = 'cloud' AND (${has})`;
25470
26175
  }
25471
26176
  function installCloudAttrCompaction(db) {
25472
- if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(CLOUD_ATTR_COMPACTION_KEY)) return;
26177
+ const marked = (key) => Boolean(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(key));
26178
+ if (marked(CLOUD_ATTR_COMPACTION_KEY)) return;
26179
+ const scope = marked(V1_KEY) ? ` AND label IN ${STRUCT_LABELS}` : "";
25473
26180
  db.transaction(() => {
25474
26181
  for (const operation of ["INSERT", "UPDATE"]) {
25475
- db.exec(`CREATE TRIGGER IF NOT EXISTS cloud_attr_compact_${operation.toLowerCase()}
26182
+ db.exec(`DROP TRIGGER IF EXISTS cloud_attr_compact_${operation.toLowerCase()}`);
26183
+ db.exec(`CREATE TRIGGER cloud_attr_compact_${operation.toLowerCase()}
25476
26184
  AFTER ${operation} ON nodes WHEN ${dirty("NEW")}
25477
26185
  BEGIN UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE id = NEW.id; END;`);
25478
26186
  }
25479
- db.exec(`UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE ${dirty("nodes")}`);
26187
+ db.exec(`UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE ${dirty("nodes")}${scope}`);
25480
26188
  db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(CLOUD_ATTR_COMPACTION_KEY, "installed");
25481
26189
  });
25482
26190
  }
@@ -25515,6 +26223,313 @@ function installHistoryAttrSlim(db) {
25515
26223
  db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(HISTORY_ATTR_SLIM_KEY, "done");
25516
26224
  }
25517
26225
 
26226
+ // ../../packages/local-graph/src/text-index.ts
26227
+ var TEXT_INDEX_KEY = "text-index-trigram-2";
26228
+ var TEXT_INDEX_MIN_TERM = 3;
26229
+ function installTextIndex(db) {
26230
+ if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)) return;
26231
+ try {
26232
+ db.exec(`CREATE VIRTUAL TABLE temp.fts5_probe USING fts5(x, tokenize='trigram'); DROP TABLE temp.fts5_probe`);
26233
+ } catch {
26234
+ db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "unavailable");
26235
+ return;
26236
+ }
26237
+ db.transaction(() => {
26238
+ db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS nodes_text
26239
+ USING fts5(description, content='nodes', content_rowid='rowid', tokenize='trigram')`);
26240
+ db.exec(`DROP TRIGGER IF EXISTS nodes_text_update_out; DROP TRIGGER IF EXISTS nodes_text_update_in;
26241
+ DROP TRIGGER IF EXISTS nodes_text_update`);
26242
+ db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_insert AFTER INSERT ON nodes WHEN NEW.valid_to IS NULL
26243
+ BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
26244
+ db.exec(`CREATE TRIGGER nodes_text_update AFTER UPDATE OF description, valid_to ON nodes
26245
+ WHEN OLD.description IS NOT NEW.description OR OLD.valid_to IS NOT NEW.valid_to
26246
+ BEGIN
26247
+ INSERT INTO nodes_text(nodes_text, rowid, description)
26248
+ SELECT 'delete', OLD.rowid, OLD.description WHERE OLD.valid_to IS NULL;
26249
+ INSERT INTO nodes_text(rowid, description)
26250
+ SELECT NEW.rowid, NEW.description WHERE NEW.valid_to IS NULL;
26251
+ END;`);
26252
+ db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_delete AFTER DELETE ON nodes WHEN OLD.valid_to IS NULL
26253
+ BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
26254
+ db.exec(`INSERT INTO nodes_text(nodes_text) VALUES ('delete-all')`);
26255
+ db.exec(`INSERT INTO nodes_text(rowid, description) SELECT rowid, description FROM nodes WHERE valid_to IS NULL`);
26256
+ db.prepare("INSERT OR REPLACE INTO store_meta(key,value) VALUES (?,?)").run("text-index-trigram-1", "installed");
26257
+ db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "installed");
26258
+ });
26259
+ }
26260
+ function textIndexReady(db) {
26261
+ return db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)?.["value"] === "installed";
26262
+ }
26263
+
26264
+ // ../../packages/local-graph/src/change-feed.ts
26265
+ var CHANGE_FEED_KEY = "change-feed";
26266
+ var ANY_CHANGE = "*";
26267
+ var nodeScope = (label) => `node:${label}`;
26268
+ var CHANGE_LOG_KEEP = 25e4;
26269
+ var PRUNED_TO_KEY = "change-log-pruned-to";
26270
+ function installChangeFeed(db) {
26271
+ if (changeFeedInstalled(db)) return;
26272
+ db.transaction(() => {
26273
+ db.exec("CREATE TABLE IF NOT EXISTS change_seq (scope TEXT PRIMARY KEY, seq INTEGER NOT NULL) WITHOUT ROWID");
26274
+ db.exec(`CREATE TABLE IF NOT EXISTS change_log (change_seq INTEGER PRIMARY KEY, kind TEXT NOT NULL, id TEXT NOT NULL,
26275
+ label TEXT, from_id TEXT, to_id TEXT)`);
26276
+ for (const name2 of ["nodes", "edges"].flatMap((t) => ["insert", "update", "delete"].map((op) => `change_feed_${t}_${op}`))) {
26277
+ db.exec(`DROP TRIGGER IF EXISTS ${name2}`);
26278
+ }
26279
+ const changed = (table) => columns(db, table).map((c) => `OLD."${c}" IS NOT NEW."${c}"`).join(" OR ");
26280
+ const strip = (row) => `json_remove(${row}.attrs_json, ${EXPOSURE_ATTRS.map((a) => `'$.${a}'`).join(", ")})`;
26281
+ const exposureOnly = `(${columns(db, "nodes").filter((c) => c !== "attrs_json").map((c) => `OLD."${c}" IS NEW."${c}"`).join(" AND ")}
26282
+ AND CASE WHEN json_valid(OLD.attrs_json) AND json_valid(NEW.attrs_json) THEN ${strip("OLD")} IS ${strip("NEW")} ELSE 0 END)`;
26283
+ const bump = (...scopes) => `INSERT INTO change_seq(scope, seq) VALUES ${scopes.map((s) => `(${s}, 1)`).join(", ")}
26284
+ ON CONFLICT(scope) DO UPDATE SET seq = seq + 1;`;
26285
+ const seq = `(SELECT seq FROM change_seq WHERE scope = '*')`;
26286
+ const logNode = (row) => `INSERT INTO change_log(change_seq, kind, id, label) VALUES (${seq}, 'node', ${row}.id, ${row}.label);`;
26287
+ const logEdge = (row) => `INSERT INTO change_log(change_seq, kind, id, label, from_id, to_id) VALUES (${seq}, 'edge', ${row}.id, ${row}.type, ${row}.from_id, ${row}.to_id);`;
26288
+ const node = (row) => `'node:' || ${row}.label`;
26289
+ const edge = (row) => `'edge:' || ${row}.type`;
26290
+ db.exec(`CREATE TRIGGER change_feed_nodes_insert AFTER INSERT ON nodes BEGIN ${bump(`'*'`, node("NEW"))} ${logNode("NEW")} END;`);
26291
+ db.exec(`CREATE TRIGGER change_feed_nodes_update AFTER UPDATE ON nodes WHEN ${changed("nodes")} BEGIN
26292
+ ${bump(`'*'`)}
26293
+ INSERT INTO change_seq(scope, seq) SELECT CASE WHEN ${exposureOnly} THEN '${EXPOSURE_SCOPE}' ELSE ${node("NEW")} END, 1 WHERE 1
26294
+ ON CONFLICT(scope) DO UPDATE SET seq = seq + 1;
26295
+ INSERT INTO change_seq(scope, seq) SELECT ${node("OLD")}, 1 WHERE OLD.label IS NOT NEW.label
26296
+ ON CONFLICT(scope) DO UPDATE SET seq = seq + 1;
26297
+ ${logNode("NEW")}
26298
+ END;`);
26299
+ db.exec(`CREATE TRIGGER change_feed_nodes_delete AFTER DELETE ON nodes BEGIN ${bump(`'*'`, node("OLD"))} ${logNode("OLD")} END;`);
26300
+ db.exec(`CREATE TRIGGER change_feed_edges_insert AFTER INSERT ON edges BEGIN ${bump(`'*'`, edge("NEW"))} ${logEdge("NEW")} END;`);
26301
+ db.exec(`CREATE TRIGGER change_feed_edges_update AFTER UPDATE ON edges WHEN ${changed("edges")} BEGIN
26302
+ ${bump(`'*'`, edge("NEW"))}
26303
+ INSERT INTO change_seq(scope, seq) SELECT ${edge("OLD")}, 1 WHERE OLD.type IS NOT NEW.type
26304
+ ON CONFLICT(scope) DO UPDATE SET seq = seq + 1;
26305
+ ${logEdge("NEW")}
26306
+ END;`);
26307
+ db.exec(`CREATE TRIGGER change_feed_edges_delete AFTER DELETE ON edges BEGIN ${bump(`'*'`, edge("OLD"))} ${logEdge("OLD")} END;`);
26308
+ db.prepare("INSERT OR REPLACE INTO store_meta(key, value) VALUES (?, ?)").run(PRUNED_TO_KEY, String(readChangeSeq(db)));
26309
+ db.prepare("INSERT OR REPLACE INTO store_meta(key, value) VALUES (?, ?)").run(CHANGE_FEED_KEY, columnSignature(db));
26310
+ });
26311
+ }
26312
+ function readChangeSeq(db, scopes = [ANY_CHANGE]) {
26313
+ if (!scopes.length) return 0;
26314
+ const row = db.prepare(`SELECT coalesce(sum(seq), 0) AS n FROM change_seq WHERE scope IN (${scopes.map(() => "?").join(",")})`).get(...scopes);
26315
+ return Number(row?.n ?? 0);
26316
+ }
26317
+ function changeLogCovers(db, sinceSeq) {
26318
+ const prunedTo = Number(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(PRUNED_TO_KEY)?.["value"] ?? NaN);
26319
+ return Number.isFinite(prunedTo) && sinceSeq >= prunedTo;
26320
+ }
26321
+ function readChangedNodeIds(db, sinceSeq, labels) {
26322
+ if (!changeLogCovers(db, sinceSeq)) return null;
26323
+ if (!labels.length) return [];
26324
+ const rows = db.prepare(`SELECT DISTINCT id FROM change_log WHERE change_seq > ? AND kind = 'node' AND label IN (${labels.map(() => "?").join(",")})`).all(sinceSeq, ...labels);
26325
+ return rows.map((r) => r.id);
26326
+ }
26327
+ function readChangedAmong(db, sinceSeq, ids) {
26328
+ if (!changeLogCovers(db, sinceSeq)) return null;
26329
+ const out2 = [];
26330
+ for (let i2 = 0; i2 < ids.length; i2 += 500) {
26331
+ const chunk = ids.slice(i2, i2 + 500);
26332
+ const rows = db.prepare(`SELECT DISTINCT id FROM change_log WHERE change_seq > ? AND kind = 'node' AND id IN (${chunk.map(() => "?").join(",")})`).all(sinceSeq, ...chunk);
26333
+ for (const r of rows) out2.push(r.id);
26334
+ }
26335
+ return out2;
26336
+ }
26337
+ function readLineageChangedFiles(db, sinceSeq) {
26338
+ if (!changeLogCovers(db, sinceSeq)) return null;
26339
+ const rows = db.prepare(LINEAGE_CHANGED_FILES_SQL).all({ s: sinceSeq });
26340
+ return rows.map((r) => r.id);
26341
+ }
26342
+ var LINEAGE_CHANGED_FILES_SQL = `
26343
+ SELECT id FROM change_log WHERE change_seq > :s AND kind = 'node' AND label = 'File'
26344
+ UNION SELECT from_id FROM change_log WHERE change_seq > :s AND kind = 'edge' AND label IN ('DEFINES','CONTAINS')
26345
+ UNION SELECT e.from_id FROM (SELECT DISTINCT id FROM change_log WHERE change_seq > :s AND kind = 'node') c
26346
+ CROSS JOIN edges e ON e.to_id = c.id AND e.type IN ('DEFINES','CONTAINS')
26347
+ `;
26348
+ function pruneChangeLog(db) {
26349
+ const max = Number(db.prepare("SELECT coalesce(max(change_seq), 0) AS n FROM change_log").get()?.["n"] ?? 0);
26350
+ const cut = max - CHANGE_LOG_KEEP;
26351
+ if (cut <= 0) return 0;
26352
+ let removed = 0;
26353
+ db.transaction(() => {
26354
+ removed = Number(db.prepare("DELETE FROM change_log WHERE change_seq <= ?").run(cut).changes);
26355
+ const prev = Number(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(PRUNED_TO_KEY)?.["value"] ?? 0);
26356
+ db.prepare("INSERT OR REPLACE INTO store_meta(key, value) VALUES (?, ?)").run(PRUNED_TO_KEY, String(Math.max(prev, cut)));
26357
+ });
26358
+ return removed;
26359
+ }
26360
+ function changeFeedInstalled(db) {
26361
+ return db.prepare("SELECT value FROM store_meta WHERE key = ?").get(CHANGE_FEED_KEY)?.["value"] === columnSignature(db);
26362
+ }
26363
+ function columns(db, table) {
26364
+ return db.prepare(`SELECT name FROM pragma_table_info('${table}') ORDER BY cid`).all().map((r) => r.name);
26365
+ }
26366
+ function columnSignature(db) {
26367
+ return `5|${columns(db, "nodes").join(",")}|${columns(db, "edges").join(",")}|${EXPOSURE_ATTRS.join(",")}`;
26368
+ }
26369
+
26370
+ // ../../packages/local-graph/src/lineage-integrity.ts
26371
+ var statements = /* @__PURE__ */ new WeakMap();
26372
+ function stmt(db, sql) {
26373
+ let byDb = statements.get(db);
26374
+ if (!byDb) statements.set(db, byDb = /* @__PURE__ */ new Map());
26375
+ let s = byDb.get(sql);
26376
+ if (!s) byDb.set(sql, s = db.prepare(sql));
26377
+ return s;
26378
+ }
26379
+ var HISTORY_EDGE_TYPES = [
26380
+ "SUPERSEDED_BY",
26381
+ "CONTINUES",
26382
+ "FORKED_FROM",
26383
+ "REGRESSION_OF",
26384
+ "SPLIT_INTO",
26385
+ "REVEALED_BY"
26386
+ ];
26387
+ var LINEAGE_INTEGRITY_KEY = "lineage-integrity-v1";
26388
+ var HISTORY_SQL = HISTORY_EDGE_TYPES.map((t) => `'${t}'`).join(",");
26389
+ var NOT_HISTORY = `type NOT IN (${HISTORY_SQL})`;
26390
+ var NOT_HISTORICAL_ROW = `json_type(attrs_json, '$.historical') IS NOT 'true'`;
26391
+ var RETAINS_EDGES = (n) => `(${n}.label = 'Problem'
26392
+ AND json_type(${n}.attrs_json, '$.resolvedAt') IS NOT NULL
26393
+ AND COALESCE(json_extract(${n}.attrs_json, '$.resolvedAs'), '') NOT IN ('duplicate', 'false_positive'))`;
26394
+ var PRESENT = (n) => `(${n}.valid_to IS NULL OR ${RETAINS_EDGES(n)})`;
26395
+ var STRANDED_EDGE_PREDICATE = `e.valid_to IS NULL AND e.${NOT_HISTORY}
26396
+ AND (NOT EXISTS (SELECT 1 FROM nodes f WHERE f.id = e.from_id AND ${PRESENT("f")})
26397
+ OR NOT EXISTS (SELECT 1 FROM nodes t WHERE t.id = e.to_id AND ${PRESENT("t")}))`;
26398
+ function countStrandedEdges(db) {
26399
+ const rows = db.prepare(`SELECT e.type AS type, count(*) AS n FROM edges e WHERE ${STRANDED_EDGE_PREDICATE} GROUP BY e.type ORDER BY n DESC`).all();
26400
+ const byType = {};
26401
+ let total = 0;
26402
+ for (const r of rows) {
26403
+ byType[r.type] = Number(r.n);
26404
+ total += Number(r.n);
26405
+ }
26406
+ return { total, byType };
26407
+ }
26408
+ function countLiveHeadConflicts(db) {
26409
+ const row = db.prepare(
26410
+ `SELECT count(*) AS n FROM (
26411
+ SELECT COALESCE(logical_id, id) AS lid FROM nodes
26412
+ WHERE valid_to IS NULL AND ${NOT_HISTORICAL_ROW}
26413
+ GROUP BY lid HAVING count(*) > 1)`
26414
+ ).get();
26415
+ return Number(row?.n ?? 0);
26416
+ }
26417
+ function closeIncidentEdges(db, id, t) {
26418
+ let closed = 0;
26419
+ for (const side of ["from_id", "to_id"]) {
26420
+ const r = stmt(db, `UPDATE edges SET valid_to = MAX(valid_from, ?) WHERE ${side} = ? AND valid_to IS NULL AND ${NOT_HISTORY}`).run(t, id);
26421
+ closed += Number(r.changes);
26422
+ }
26423
+ return closed;
26424
+ }
26425
+ function reopenCascadeClosedEdges(db, id, closedAt) {
26426
+ let reopened = 0;
26427
+ for (const [side, other] of [["from_id", "to_id"], ["to_id", "from_id"]]) {
26428
+ const r = stmt(
26429
+ db,
26430
+ `UPDATE edges SET valid_to = NULL
26431
+ WHERE ${side} = ? AND valid_to = ? AND ${NOT_HISTORY}
26432
+ AND EXISTS (SELECT 1 FROM nodes o WHERE o.id = edges.${other} AND o.valid_to IS NULL)`
26433
+ ).run(id, closedAt);
26434
+ reopened += Number(r.changes);
26435
+ }
26436
+ return reopened;
26437
+ }
26438
+ function collapseLiveHeads(db, logicalIds, t) {
26439
+ const headsOf = db.prepare(
26440
+ `SELECT id, version, valid_from FROM (
26441
+ SELECT id, version, valid_from, attrs_json FROM nodes WHERE logical_id = ?1 AND valid_to IS NULL
26442
+ UNION
26443
+ SELECT id, version, valid_from, attrs_json FROM nodes WHERE id = ?1 AND logical_id IS NULL AND valid_to IS NULL
26444
+ ) WHERE ${NOT_HISTORICAL_ROW}`
26445
+ );
26446
+ const continuesInto = db.prepare(
26447
+ `SELECT to_id FROM edges WHERE from_id = ? AND type = 'CONTINUES' AND valid_to IS NULL`
26448
+ );
26449
+ const rekeyHead = db.prepare(`UPDATE nodes SET logical_id = ?1 WHERE id = ?1`);
26450
+ const rekeyCopies = db.prepare(
26451
+ `UPDATE nodes SET logical_id = ?1 WHERE logical_id = ?2 AND substr(id, 1, length(?1) + 2) = ?1 || '@v'`
26452
+ );
26453
+ const lineageMembers = db.prepare(
26454
+ `SELECT id FROM nodes WHERE logical_id = ?1 UNION SELECT id FROM nodes WHERE id = ?1`
26455
+ );
26456
+ const closeContinues = db.prepare(
26457
+ `UPDATE edges SET valid_to = MAX(valid_from, ?) WHERE from_id = ? AND to_id = ? AND type = 'CONTINUES' AND valid_to IS NULL`
26458
+ );
26459
+ let split = 0;
26460
+ const queue = [...new Set(logicalIds)];
26461
+ for (let i2 = 0; i2 < queue.length; i2++) {
26462
+ const lid = queue[i2];
26463
+ const heads = headsOf.all(lid);
26464
+ if (heads.length < 2) continue;
26465
+ const members = new Set(lineageMembers.all(lid).map((r) => r.id));
26466
+ const splitOff = (h) => {
26467
+ for (const { to_id } of continuesInto.all(h.id)) {
26468
+ if (members.has(to_id)) closeContinues.run(t, h.id, to_id);
26469
+ }
26470
+ rekeyHead.run(h.id);
26471
+ rekeyCopies.run(h.id, lid);
26472
+ queue.push(h.id);
26473
+ split++;
26474
+ };
26475
+ const kept = new Set(heads.map((h) => h.id));
26476
+ for (const h of heads) {
26477
+ if (h.id === lid) continue;
26478
+ const refuted = continuesInto.all(h.id).some(
26479
+ (e) => e.to_id !== h.id && kept.has(e.to_id)
26480
+ );
26481
+ if (refuted && kept.size > 1) {
26482
+ splitOff(h);
26483
+ kept.delete(h.id);
26484
+ }
26485
+ }
26486
+ let remaining = heads.filter((h) => kept.has(h.id));
26487
+ if (remaining.length < 2) continue;
26488
+ remaining = [...remaining].sort(
26489
+ (a, b) => Number(b.id === lid) - Number(a.id === lid) || Number(b.version) - Number(a.version) || Number(b.valid_from) - Number(a.valid_from) || (a.id < b.id ? -1 : 1)
26490
+ );
26491
+ for (const h of remaining.slice(1)) splitOff(h);
26492
+ }
26493
+ return split;
26494
+ }
26495
+ function repairLineageIntegrity(db, now) {
26496
+ const historicalRowsClosed = Number(
26497
+ db.prepare(
26498
+ `UPDATE nodes SET valid_to = MAX(valid_from, COALESCE(
26499
+ (SELECT s.valid_from FROM edges s WHERE s.id = 'edge_superseded_' || nodes.id), ?))
26500
+ WHERE valid_to IS NULL AND json_type(attrs_json, '$.historical') = 'true'`
26501
+ ).run(now).changes
26502
+ );
26503
+ const conflicted = db.prepare(
26504
+ `SELECT COALESCE(logical_id, id) AS lid FROM nodes
26505
+ WHERE valid_to IS NULL AND ${NOT_HISTORICAL_ROW}
26506
+ GROUP BY lid HAVING count(*) > 1`
26507
+ ).all().map((r) => r.lid);
26508
+ const headsSplit = collapseLiveHeads(db, conflicted, now);
26509
+ const strandedEdgesClosed = Number(
26510
+ db.prepare(
26511
+ `UPDATE edges SET valid_to = MAX(valid_from, COALESCE(
26512
+ (SELECT min(v) FROM (
26513
+ SELECT f.valid_to AS v FROM nodes f WHERE f.id = edges.from_id AND NOT ${PRESENT("f")}
26514
+ UNION ALL
26515
+ SELECT t.valid_to FROM nodes t WHERE t.id = edges.to_id AND NOT ${PRESENT("t")})), ?))
26516
+ WHERE id IN (SELECT e.id FROM edges e WHERE ${STRANDED_EDGE_PREDICATE})`
26517
+ ).run(now).changes
26518
+ );
26519
+ return { historicalRowsClosed, headsSplit, strandedEdgesClosed };
26520
+ }
26521
+ function installLineageIntegrityRepair(db, now = Date.now()) {
26522
+ if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(LINEAGE_INTEGRITY_KEY)) return null;
26523
+ return db.transaction(() => {
26524
+ const report = repairLineageIntegrity(db, now);
26525
+ db.prepare("INSERT OR REPLACE INTO store_meta (key, value) VALUES (?, ?)").run(
26526
+ LINEAGE_INTEGRITY_KEY,
26527
+ JSON.stringify({ at: now, ...report })
26528
+ );
26529
+ return report;
26530
+ });
26531
+ }
26532
+
25518
26533
  // ../../packages/math/src/pagerank.ts
25519
26534
  function pagerank(input) {
25520
26535
  const damping = input.damping ?? 0.85;
@@ -25961,6 +26976,177 @@ function pagerankLocal(input) {
25961
26976
  return { scores, iterations: iter, converged };
25962
26977
  }
25963
26978
 
26979
+ // ../../packages/local-graph/src/node-select.ts
26980
+ var SELECT_INDEXES = [
26981
+ "nodes_live_local_community",
26982
+ "nodes_live_fold_candidate",
26983
+ "nodes_live_resolved",
26984
+ "nodes_live_fix_candidate",
26985
+ "nodes_live_anchor_hint"
26986
+ ];
26987
+ var EMBEDDING_DIM_SQL = "(CASE WHEN length(embedding_blob) >= 4 THEN length(embedding_blob) / 4 ELSE COALESCE(json_array_length(embedding_json), 0) END)";
26988
+ var KEY = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
26989
+ var COLUMNS = /* @__PURE__ */ new Set([
26990
+ "created_at",
26991
+ "last_updated_at",
26992
+ "page_rank",
26993
+ "created_at_seq",
26994
+ "last_reinforced_at_seq",
26995
+ "cumulative_hits",
26996
+ "extraction_confidence"
26997
+ ]);
26998
+ function path(key) {
26999
+ if (!KEY.test(key)) throw new Error(`selectNodes: bad attr key ${key}`);
27000
+ return `'$.${key}'`;
27001
+ }
27002
+ function selectIndex(i2) {
27003
+ if (!SELECT_INDEXES.includes(i2)) throw new Error(`selectNodes: bad index ${i2}`);
27004
+ return i2;
27005
+ }
27006
+ function column(c) {
27007
+ if (!COLUMNS.has(c)) throw new Error(`selectNodes: bad column ${c}`);
27008
+ return c;
27009
+ }
27010
+ function compileNodeWhere(q) {
27011
+ if (q.labels.length === 0) throw new Error("selectNodes: no labels");
27012
+ const params = [...q.labels];
27013
+ const byId = (q.where ?? []).some((w) => "idIn" in w || "idPrefix" in w && w.idPrefix.length > 0);
27014
+ const unindexed = byId ? "+" : "";
27015
+ const conds = [`${unindexed}label IN (${q.labels.map(() => "?").join(", ")})`];
27016
+ if (!q.includeClosed) conds.push(`${unindexed}valid_to IS NULL`);
27017
+ for (const w of q.where ?? []) {
27018
+ if ("embedding" in w) {
27019
+ conds.push(`${EMBEDDING_DIM_SQL} ${w.embedding === "present" ? ">" : "="} 0`);
27020
+ } else if ("idPrefix" in w) {
27021
+ conds.push("substr(id, 1, ?) = ?");
27022
+ params.push(w.idPrefix.length, w.idPrefix);
27023
+ if (w.idPrefix.length > 0) {
27024
+ const last = w.idPrefix.charCodeAt(w.idPrefix.length - 1);
27025
+ conds.push("id >= ? AND id < ?");
27026
+ params.push(w.idPrefix, w.idPrefix.slice(0, -1) + String.fromCharCode(last + 1));
27027
+ }
27028
+ } else if ("idIn" in w) {
27029
+ if (w.idIn.length === 0) conds.push("0");
27030
+ else {
27031
+ conds.push(`id IN (${w.idIn.map(() => "?").join(", ")})`);
27032
+ params.push(...w.idIn);
27033
+ }
27034
+ } else if ("descriptionIn" in w) {
27035
+ if (w.descriptionIn.length === 0) conds.push("0");
27036
+ else {
27037
+ conds.push(`description IN (${w.descriptionIn.map(() => "?").join(", ")})`);
27038
+ params.push(...w.descriptionIn);
27039
+ }
27040
+ } else if ("column" in w) {
27041
+ const c = column(w.column);
27042
+ for (const [op, sym] of [["gte", ">="], ["gt", ">"], ["lte", "<="], ["lt", "<"]]) {
27043
+ const v = w[op];
27044
+ if (v !== void 0) {
27045
+ conds.push(`${c} ${sym} ?`);
27046
+ params.push(v);
27047
+ }
27048
+ }
27049
+ } else {
27050
+ const p = path(w.attr);
27051
+ if ("absent" in w) conds.push(`json_type(attrs_json, ${p}) IS NULL`);
27052
+ else if ("present" in w) conds.push(`json_type(attrs_json, ${p}) IS NOT NULL`);
27053
+ else if ("nullish" in w) conds.push(`json_extract(attrs_json, ${p}) IS NULL`);
27054
+ else if ("notNullish" in w) conds.push(`json_extract(attrs_json, ${p}) IS NOT NULL`);
27055
+ else if ("eq" in w || "ne" in w) {
27056
+ const v = "eq" in w ? w.eq : w.ne;
27057
+ const neg = "ne" in w;
27058
+ if (typeof v === "boolean") {
27059
+ conds.push(`json_type(attrs_json, ${p}) ${neg ? "IS NOT" : "="} ?`);
27060
+ params.push(v ? "true" : "false");
27061
+ } else {
27062
+ conds.push(neg ? `json_extract(attrs_json, ${p}) IS NOT ?` : `json_extract(attrs_json, ${p}) = ?`);
27063
+ params.push(v);
27064
+ }
27065
+ }
27066
+ }
27067
+ }
27068
+ return { where: conds.join(" AND "), params };
27069
+ }
27070
+ function attrValueSql(p, doc = "attrs_json") {
27071
+ return `CASE json_type(${doc}, ${p}) WHEN 'integer' THEN CAST(json_extract(${doc}, ${p}) AS REAL) ELSE json_extract(${doc}, ${p}) END`;
27072
+ }
27073
+ function attrDocSql(key) {
27074
+ return isExposureAttr(key) ? exposureDocSql(key) : "attrs_json";
27075
+ }
27076
+ function nodeSelectFrom(q) {
27077
+ if (q.indexedBy) return `nodes INDEXED BY ${selectIndex(q.indexedBy)}`;
27078
+ const where = q.where ?? [];
27079
+ if (!q.includeClosed && where.some((w) => "descriptionIn" in w && w.descriptionIn.length > 0) && !where.some((w) => "idIn" in w)) {
27080
+ return "nodes INDEXED BY nodes_live_description";
27081
+ }
27082
+ return "nodes";
27083
+ }
27084
+ function compileNodeSelect(q) {
27085
+ const { where, params } = compileNodeWhere(q);
27086
+ const attrs = q.attrs ?? [];
27087
+ const attrCols = attrs.map((k, i2) => `, ${attrValueSql(path(k), attrDocSql(k))} AS a${i2}, json_type(${attrDocSql(k)}, ${path(k)}) AS t${i2}`).join("");
27088
+ let order;
27089
+ if (q.orderBy && "column" in q.orderBy) {
27090
+ order = `${column(q.orderBy.column)} ${q.orderBy.desc ? "DESC" : "ASC"}, rowid`;
27091
+ } else if (q.orderBy) {
27092
+ const p = path(q.orderBy.attr);
27093
+ order = `json_extract(attrs_json, ${p}) IS NULL, json_extract(attrs_json, ${p}) ${q.orderBy.desc ? "DESC" : "ASC"}, rowid`;
27094
+ } else if (q.labels.length > 1) {
27095
+ order = `CASE label ${q.labels.map((_, i2) => `WHEN ? THEN ${i2}`).join(" ")} END, rowid`;
27096
+ } else {
27097
+ order = "rowid";
27098
+ }
27099
+ const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
27100
+ const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.limit))}` : "";
27101
+ const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM ${nodeSelectFrom(q)} WHERE ${where} ORDER BY ${order}${limit}`;
27102
+ return { sql, params: [...params, ...orderParams] };
27103
+ }
27104
+ function decodeAttr(value, type) {
27105
+ switch (type) {
27106
+ case null:
27107
+ case void 0:
27108
+ return void 0;
27109
+ case "true":
27110
+ return true;
27111
+ case "false":
27112
+ return false;
27113
+ case "null":
27114
+ return null;
27115
+ case "object":
27116
+ case "array":
27117
+ return typeof value === "string" ? JSON.parse(value) : value;
27118
+ default:
27119
+ return value;
27120
+ }
27121
+ }
27122
+ function decodeSelectedRow(r, attrs, decodeVector) {
27123
+ const out2 = {};
27124
+ attrs.forEach((k, i2) => {
27125
+ const v = decodeAttr(r[`a${i2}`], r[`t${i2}`]);
27126
+ if (v !== void 0) out2[k] = v;
27127
+ });
27128
+ return {
27129
+ id: r["id"],
27130
+ label: r["label"],
27131
+ description: r["description"] ?? "",
27132
+ createdAt: r["created_at"],
27133
+ lastUpdatedAt: r["last_updated_at"],
27134
+ pageRank: r["page_rank"],
27135
+ cumulativeHits: r["cumulative_hits"],
27136
+ extractionConfidence: r["extraction_confidence"],
27137
+ extractionSource: r["extraction_source"],
27138
+ community: r["community"] ?? null,
27139
+ ...r["created_at_seq"] != null ? { createdAtSeq: r["created_at_seq"] } : {},
27140
+ ...r["last_reinforced_at_seq"] != null ? { lastReinforcedAtSeq: r["last_reinforced_at_seq"] } : {},
27141
+ validTo: r["valid_to"] ?? null,
27142
+ logicalId: r["logical_id"] ?? r["id"],
27143
+ version: Number(r["version"] ?? 1),
27144
+ embeddingDim: Number(r["embedding_dim"] ?? 0),
27145
+ ...decodeVector ? { embedding: decodeVector(r["embedding_blob"], r["embedding_json"] ?? "[]") } : {},
27146
+ attrs: out2
27147
+ };
27148
+ }
27149
+
25964
27150
  // ../../packages/local-graph/src/store.ts
25965
27151
  var PAGE_RANK_SCALE_KEY = "pageRankScale.p95.v1";
25966
27152
  var TEXT_SEARCH_COLUMNS = `id, label, description, page_rank,
@@ -26015,6 +27201,7 @@ function localEdgeViolation(fromLabel, type, toLabel) {
26015
27201
  }
26016
27202
  var SCHEMA_VERSION = 6;
26017
27203
  var SESSION_REPAIR_KEY = "session-evidence-v1";
27204
+ var EXPOSURE_SIDE_KEY = "exposure-side-rows-1";
26018
27205
  var SESSION_EVIDENCE_PREDICATE = SESSION_EVIDENCE_FIELDS.map((field) => `instr(attrs_json, '${JSON.stringify(field)}') > 0`).join(" OR ");
26019
27206
  var SCHEMA_SQL = `
26020
27207
  CREATE TABLE IF NOT EXISTS schema_version (
@@ -26078,8 +27265,13 @@ CREATE TABLE IF NOT EXISTS nodes (
26078
27265
  );
26079
27266
 
26080
27267
  CREATE INDEX IF NOT EXISTS nodes_label ON nodes(label);
26081
- CREATE INDEX IF NOT EXISTS nodes_memory_tier ON nodes(memory_tier);
26082
- CREATE INDEX IF NOT EXISTS nodes_page_rank ON nodes(page_rank DESC);
27268
+ -- Dropped: no query plans through them (every prepared statement across the
27269
+ -- local-graph, indexer, context-writer, generalizer and daemon suites was
27270
+ -- planned with and without them, 2026-10-21), and each write that touches
27271
+ -- memory_tier / page_rank (every node upsert, every rescore) paid to maintain
27272
+ -- them. nodes_live_page_rank serves the live page-rank orderings.
27273
+ DROP INDEX IF EXISTS nodes_memory_tier;
27274
+ DROP INDEX IF EXISTS nodes_page_rank;
26083
27275
 
26084
27276
  CREATE TABLE IF NOT EXISTS edges (
26085
27277
  id TEXT PRIMARY KEY,
@@ -26101,7 +27293,10 @@ CREATE TABLE IF NOT EXISTS edges (
26101
27293
  FOREIGN KEY (to_id) REFERENCES nodes(id) ON DELETE CASCADE
26102
27294
  );
26103
27295
 
26104
- CREATE INDEX IF NOT EXISTS edges_from ON edges(from_id, type);
27296
+ -- Dropped: a prefix of edges_triple (from_id, type, to_id), which every
27297
+ -- from-side lookup and foreign-key check already plans through; it cost 47 MB
27298
+ -- and an index write on every edge write.
27299
+ DROP INDEX IF EXISTS edges_from;
26105
27300
  CREATE INDEX IF NOT EXISTS edges_to ON edges(to_id, type);
26106
27301
  CREATE INDEX IF NOT EXISTS edges_type ON edges(type);
26107
27302
  CREATE UNIQUE INDEX IF NOT EXISTS edges_triple ON edges(from_id, type, to_id);
@@ -26109,8 +27304,41 @@ CREATE UNIQUE INDEX IF NOT EXISTS edges_triple ON edges(from_id, type, to_id);
26109
27304
  var TEMPORAL_INDEX_SQL = `
26110
27305
  CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
26111
27306
  CREATE INDEX IF NOT EXISTS nodes_live_count ON nodes(valid_to);
26112
- CREATE INDEX IF NOT EXISTS nodes_live_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL;
27307
+ -- Problems by recency (the only label read newest-first). Over every live row,
27308
+ -- each write that stamps last_updated_at moved a code symbol's entry from a
27309
+ -- scattered leaf: ~19 KB per position-only symbol rewrite on a 1.1 GB store.
27310
+ -- label stays the leading column so label = 'Problem' plans without a sort.
27311
+ DROP INDEX IF EXISTS nodes_live_recent;
27312
+ CREATE INDEX IF NOT EXISTS nodes_live_problem_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL AND label = 'Problem';
27313
+ -- "Anything created since the watermark?" guards (the fold, regression and
27314
+ -- canonical-bind sweeps run one per session boundary). Without it the planner
27315
+ -- walks nodes_live and reads every live row of the label to test created_at:
27316
+ -- 56 MB per guard on a 1.1 GB store, to learn there was nothing to do. valid_to
27317
+ -- is a key column so the planner prefers this over nodes_live (one more term).
27318
+ CREATE INDEX IF NOT EXISTS nodes_live_created ON nodes(label, valid_to, created_at) WHERE valid_to IS NULL;
27319
+ -- Community members (the skills pull reads them twice per session boundary):
27320
+ -- ~15% of semantic nodes carry a localCommunity, and without this every live
27321
+ -- semantic row was read to find them (168 MB \u2192 18 MB per read).
27322
+ CREATE INDEX IF NOT EXISTS nodes_live_local_community ON nodes(label, valid_to, json_extract(attrs_json, '$.localCommunity')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.localCommunity') IS NOT NULL;
27323
+ -- Problems parked for the fold judge (read every settle boundary): ~1 in 5 open
27324
+ -- Problems; without it every live Problem was read to find them (56 MB).
27325
+ CREATE INDEX IF NOT EXISTS nodes_live_fold_candidate ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_type(attrs_json, '$.foldCandidate') IS NOT NULL;
27326
+ -- Render impressions, one row per node id (exposure-attrs.ts): a render bumps
27327
+ -- ~40 of these, which in the node row rewrote each whole row and its indexes.
27328
+ CREATE TABLE IF NOT EXISTS node_exposure (
27329
+ id TEXT PRIMARY KEY,
27330
+ attrs_json TEXT NOT NULL DEFAULT '{}'
27331
+ ) WITHOUT ROWID;
27332
+ -- The semantic-maintenance sweeps' own filters (closed, asked, hinted): each read
27333
+ -- every Problem row (~30 MB on a 1.1 GB store) for the few hundred that match,
27334
+ -- several times a run, and a run follows most writes (2026-10-20).
27335
+ CREATE INDEX IF NOT EXISTS nodes_live_resolved ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.resolvedAt') IS NOT NULL;
27336
+ CREATE INDEX IF NOT EXISTS nodes_live_fix_candidate ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_type(attrs_json, '$.fixCandidateAt') IS NOT NULL;
27337
+ CREATE INDEX IF NOT EXISTS nodes_live_anchor_hint ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.anchorHint') IS NOT NULL;
26113
27338
  CREATE INDEX IF NOT EXISTS nodes_session_evidence ON nodes(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
27339
+ -- Rows carrying a calibration counter, any version: the logical nodes wm
27340
+ -- calibration can count (~3k), found without reading every citable row.
27341
+ CREATE INDEX IF NOT EXISTS nodes_wm_counted ON nodes(logical_id, version, valid_to, label, ${WM_CALIBRATION_KEYS.map(wmCounterSql).join(", ")}) WHERE ${WM_COUNTED_PREDICATE};
26114
27342
  CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
26115
27343
  -- Covering + partial index for labelFingerprint over the instance labels: the
26116
27344
  -- live-push probe runs it per workspace on a timer, and each hit used to read
@@ -26124,31 +27352,70 @@ CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_up
26124
27352
  CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
26125
27353
  CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
26126
27354
  CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
27355
+ -- Newest live edges first, so a "recent N matching edges" read stops early instead
27356
+ -- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
27357
+ -- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
27358
+ CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
27359
+ -- Live prior-tag edges by recency: the liveness corroboration check reads the
27360
+ -- newest 100 of ~300, and walking all live edges newest-first to find them read
27361
+ -- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
27362
+ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
26127
27363
  -- Expression index on the per-node relPath (stored in attrs_json) so the
26128
27364
  -- incremental reindex can fetch just the changed files' symbols instead of
26129
27365
  -- scanning every versioned node. Partial: only live rows are ever queried.
26130
27366
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
27367
+ -- Symbols by qname and doc comments by the symbol they attach to: the drain's
27368
+ -- symbol lexicon resolves the names in the text it ships one at a time, instead
27369
+ -- of reading every Function/Method/Class/Interface/Const and Comment row on each
27370
+ -- live push (~300 MB of a 1.1 GB store per push, 2026-10-20).
27371
+ CREATE INDEX IF NOT EXISTS nodes_live_qname ON nodes(json_extract(attrs_json, '$.qname')) WHERE valid_to IS NULL;
27372
+ CREATE INDEX IF NOT EXISTS nodes_live_attached_to ON nodes(json_extract(attrs_json, '$.attachedTo')) WHERE valid_to IS NULL AND label = 'Comment';
27373
+ -- The attrs the cloud drain gates every instance row on, so it reads them from
27374
+ -- the index alone: pulled cloud rows are most of these labels (7,105 of 7,708
27375
+ -- Solutions on the live store) at ~10 KB of attrs each, and five full scans for
27376
+ -- two attrs read ~220 MB per push to find the few local rows that can ship.
27377
+ -- created_at leads so the index order is findNodeFieldsByLabel's.
27378
+ CREATE INDEX IF NOT EXISTS nodes_live_instance_gate ON nodes(label, created_at, json_extract(attrs_json, '$.source'), json_extract(attrs_json, '$.privateFinding'), json_extract(attrs_json, '$.resolvedAs'), id) WHERE valid_to IS NULL AND label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause');
27379
+ -- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
27380
+ -- live-only index above cannot serve it, so it scanned the whole table (~275 MB
27381
+ -- of a 1.1 GB store per reindex, 2026-10-20).
27382
+ CREATE INDEX IF NOT EXISTS nodes_closed_relpath ON nodes(json_extract(attrs_json, '$.relPath'), last_updated_at) WHERE valid_to IS NOT NULL;
26131
27383
  -- Live rows by name, for looking up the few symbols a statement mentions
26132
27384
  -- instead of hydrating every code symbol per minted problem.
26133
27385
  CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
27386
+ -- The six single-attr lookups below are partial on the attr being present: each
27387
+ -- is read only by equality (or IN), which implies it. Keyed on NULL for the ~95%
27388
+ -- of rows that lack the attr, every write to such a row's attrs rewrote its NULL
27389
+ -- entry: ~25 KB per position-only symbol rewrite on a 1.1 GB store (2026-10-21).
27390
+ DROP INDEX IF EXISTS nodes_anchor_hint_path;
27391
+ DROP INDEX IF EXISTS nodes_command_signature;
27392
+ DROP INDEX IF EXISTS nodes_diag_command;
27393
+ DROP INDEX IF EXISTS nodes_lsp_rel_path;
27394
+ DROP INDEX IF EXISTS nodes_cloud_node_id;
27395
+ DROP INDEX IF EXISTS nodes_enrichment_pending;
26134
27396
  -- Problems by the file their anchor hint names: the harvest upgrades hints for
26135
27397
  -- every edited file of every turn, and a scan parses every Problem's attrs.
26136
- CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
27398
+ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path_v2 ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.anchorHint.path') IS NOT NULL;
26137
27399
  -- Problems by the command / checker / file that opened them. The generalizer
26138
27400
  -- looked these up per shell or tool EVENT by hydrating every Problem: ~12s of
26139
27401
  -- every minute of daemon main-thread time on a 3.4k-Problem store (2026-10-05).
26140
- CREATE INDEX IF NOT EXISTS nodes_command_signature ON nodes(json_extract(attrs_json, '$.commandSignature')) WHERE valid_to IS NULL;
26141
- CREATE INDEX IF NOT EXISTS nodes_diag_command ON nodes(json_extract(attrs_json, '$.diagCommand')) WHERE valid_to IS NULL;
26142
- CREATE INDEX IF NOT EXISTS nodes_lsp_rel_path ON nodes(json_extract(attrs_json, '$.lspRelPath')) WHERE valid_to IS NULL;
27402
+ CREATE INDEX IF NOT EXISTS nodes_command_signature_v2 ON nodes(json_extract(attrs_json, '$.commandSignature')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.commandSignature') IS NOT NULL;
27403
+ CREATE INDEX IF NOT EXISTS nodes_diag_command_v2 ON nodes(json_extract(attrs_json, '$.diagCommand')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.diagCommand') IS NOT NULL;
27404
+ CREATE INDEX IF NOT EXISTS nodes_lsp_rel_path_v2 ON nodes(json_extract(attrs_json, '$.lspRelPath')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.lspRelPath') IS NOT NULL;
26143
27405
  -- Local nodes by the cloud twin their upload receipt recorded. Every burst /
26144
27406
  -- search fusion folds the Network copy of the caller's own knowledge back onto
26145
27407
  -- the local node; unindexed, the reverse lookup was a ~300ms attrs scan per call.
26146
- CREATE INDEX IF NOT EXISTS nodes_cloud_node_id ON nodes(json_extract(attrs_json, '$.cloudNodeId')) WHERE valid_to IS NULL;
27408
+ CREATE INDEX IF NOT EXISTS nodes_cloud_node_id_v2 ON nodes(json_extract(attrs_json, '$.cloudNodeId')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.cloudNodeId') IS NOT NULL;
26147
27409
  -- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
26148
27410
  -- tool response (the enrichment piggyback), so it must not parse every
26149
- -- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
27411
+ -- Solution's and Problem's attrs per call. Any version: the Problem pull reads
26150
27412
  -- closed versions too.
26151
- CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_json, '$.enrichmentPending'));
27413
+ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending_v2 ON nodes(json_extract(attrs_json, '$.enrichmentPending')) WHERE json_extract(attrs_json, '$.enrichmentPending') IS NOT NULL;
27414
+ -- Revisit flags, any label, any version: listNeedsRevisit's as-of read runs on
27415
+ -- every context render and otherwise json-checks every row (10.3 s on a 324k-row
27416
+ -- store, to return zero flags). The predicate must stay textually identical to
27417
+ -- nodesAsOfWhereTrue's or the planner will not use it.
27418
+ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_type(attrs_json, '$.revisit') = 'true';
26152
27419
  `;
26153
27420
  function encodeEmbedding(emb) {
26154
27421
  if (!emb || emb.length === 0) return null;
@@ -26209,12 +27476,39 @@ function rowToEdge(r) {
26209
27476
  }
26210
27477
  var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
26211
27478
  var NODE_LABELS_CHUNK = 256;
27479
+ var NODE_UPSERT_COLUMNS = [
27480
+ "label",
27481
+ "description",
27482
+ "extraction_confidence",
27483
+ "embedding_json",
27484
+ "embedding_blob",
27485
+ "cumulative_surprise",
27486
+ "peak_surprise",
27487
+ "cumulative_hits",
27488
+ "last_updated_at",
27489
+ "memory_tier",
27490
+ "page_rank",
27491
+ "is_landmark",
27492
+ "community",
27493
+ "stability",
27494
+ "last_reinforced_at_seq",
27495
+ "attrs_json"
27496
+ ];
27497
+ var EDGE_UPSERT_COLUMNS = ["confidence", "last_seen_at", "nav_successes", "nav_failures", "valid_to", "attrs_json"];
27498
+ function sameSqlValue(a, b) {
27499
+ if (a === b || a == null && b == null) return true;
27500
+ if (a instanceof Uint8Array && b instanceof Uint8Array) return Buffer.compare(a, b) === 0;
27501
+ return false;
27502
+ }
27503
+ var PRIOR_TAG_MARKER = '"priorTag":true';
26212
27504
  var SqliteGraphStore = class {
26213
27505
  db;
26214
27506
  // Typed edge lookups build their SQL from the number of types asked for, and
26215
27507
  // used to prepare it on every call: ~600ms of a 2.5s drain build on a live
26216
27508
  // 225k-node store was statement compilation alone. Keyed by the SQL text.
26217
27509
  typedEdgeStmts = /* @__PURE__ */ new Map();
27510
+ /** Narrow merge updates, keyed by table and the columns they set. */
27511
+ changedColumnStmts = /* @__PURE__ */ new Map();
26218
27512
  stmts;
26219
27513
  /** Unified graph-mutation counter (see GraphStore.mutationCount). Bumped on
26220
27514
  * every node/edge upsert — code-index and capture alike — so the consolidation
@@ -26233,6 +27527,8 @@ var SqliteGraphStore = class {
26233
27527
  initialPageRankScale;
26234
27528
  constructor(opts) {
26235
27529
  this.db = openDatabase(opts.path);
27530
+ this.db.exec("PRAGMA cache_size = -32768");
27531
+ this.db.exec("PRAGMA mmap_size = 2147483648");
26236
27532
  this.db.exec(SCHEMA_SQL);
26237
27533
  const versionRow = this.db.prepare("SELECT version FROM schema_version LIMIT 1").get();
26238
27534
  if (!versionRow) {
@@ -26249,12 +27545,15 @@ var SqliteGraphStore = class {
26249
27545
  installEditPlaceholderRetirement(this.db);
26250
27546
  installCloudAttrCompaction(this.db);
26251
27547
  installHistoryAttrSlim(this.db);
27548
+ installTextIndex(this.db);
26252
27549
  if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
26253
27550
  this.db.transaction(() => {
26254
27551
  this.repairSessionAliases();
26255
27552
  this.db.prepare("INSERT OR REPLACE INTO store_meta (key, value) VALUES (?, 'done')").run(SESSION_REPAIR_KEY);
26256
27553
  });
26257
27554
  }
27555
+ installLineageIntegrityRepair(this.db);
27556
+ installChangeFeed(this.db);
26258
27557
  this.stmts = {
26259
27558
  insertNode: this.db.prepare(`
26260
27559
  INSERT INTO nodes (
@@ -26293,7 +27592,19 @@ var SqliteGraphStore = class {
26293
27592
  last_reinforced_at_seq = excluded.last_reinforced_at_seq,
26294
27593
  attrs_json = excluded.attrs_json
26295
27594
  `),
26296
- getNode: this.db.prepare("SELECT * FROM nodes WHERE id = ?"),
27595
+ nodeUpsertTarget: this.db.prepare(`SELECT rowid AS rid, ${NODE_UPSERT_COLUMNS.join(", ")} FROM nodes WHERE id = ?`),
27596
+ edgeUpsertTarget: this.db.prepare(`SELECT rowid AS rid, ${EDGE_UPSERT_COLUMNS.join(", ")} FROM edges WHERE from_id = ? AND type = ? AND to_id = ?`),
27597
+ getNode: this.db.prepare("SELECT nodes.*, (SELECT x.attrs_json FROM node_exposure x WHERE x.id = nodes.id) AS exposure_json FROM nodes WHERE id = ?"),
27598
+ exposureOf: this.db.prepare("SELECT attrs_json FROM node_exposure WHERE id = ?"),
27599
+ writeExposure: this.db.prepare("INSERT INTO node_exposure(id, attrs_json) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET attrs_json = excluded.attrs_json"),
27600
+ lastUpdatedOf: this.db.prepare("SELECT last_updated_at AS t, attrs_json FROM nodes WHERE id = ?"),
27601
+ labelOf: this.db.prepare("SELECT label FROM nodes WHERE id = ?"),
27602
+ nodeContent: this.db.prepare(
27603
+ "SELECT label, description, extraction_confidence, extraction_source, stability, valid_to, attrs_json FROM nodes WHERE id = ?"
27604
+ ),
27605
+ edgeContent: this.db.prepare(
27606
+ "SELECT confidence, valid_to, attrs_json FROM edges WHERE from_id = ? AND type = ? AND to_id = ?"
27607
+ ),
26297
27608
  // Single-column fast paths for the nightly pass — writing 100k pageRank
26298
27609
  // values through the 18-column COALESCE updateNode took ~30s; these are ~10x
26299
27610
  // cheaper (one bound column, no COALESCE evaluation per row).
@@ -26450,6 +27761,7 @@ var SqliteGraphStore = class {
26450
27761
  "INSERT INTO store_meta (key, value) VALUES ('ingest_seq', :v) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
26451
27762
  )
26452
27763
  };
27764
+ this.moveExposureToSideRows();
26453
27765
  const seqRow = this.db.prepare("SELECT value FROM store_meta WHERE key = 'ingest_seq'").get();
26454
27766
  this.ingestSeq = seqRow ? Number(seqRow.value) : 0;
26455
27767
  }
@@ -26465,6 +27777,93 @@ var SqliteGraphStore = class {
26465
27777
  AND (t.id IS NULL OR t.valid_to IS NOT NULL)
26466
27778
  `).all();
26467
27779
  }
27780
+ strandedSymbolsForFiles(fileIds) {
27781
+ const out2 = [];
27782
+ for (let i2 = 0; i2 < fileIds.length; i2 += 500) {
27783
+ const slice = fileIds.slice(i2, i2 + 500);
27784
+ if (slice.length === 0) continue;
27785
+ out2.push(...this.db.prepare(`
27786
+ SELECT f.id AS fileId, e.to_id AS symbolId
27787
+ FROM nodes f CROSS JOIN edges e ON e.from_id = f.id
27788
+ LEFT JOIN nodes t ON t.id = e.to_id
27789
+ WHERE f.id IN (${slice.map(() => "?").join(",")}) AND f.label = 'File' AND f.valid_to IS NULL AND e.valid_to IS NULL
27790
+ AND e.type IN ('DEFINES', 'CONTAINS')
27791
+ AND (t.id IS NULL OR t.valid_to IS NOT NULL)
27792
+ `).all(...slice));
27793
+ }
27794
+ return out2;
27795
+ }
27796
+ firstLiveByNameOrQname(labels, name2) {
27797
+ if (labels.length === 0) return null;
27798
+ const inLabels = labels.map(() => "?").join(",");
27799
+ const probe = (index, match) => this.db.prepare(
27800
+ `SELECT rowid AS rid, created_at AS at, label, description, json_extract(attrs_json, '$.qname') AS qname FROM nodes INDEXED BY ${index}
27801
+ WHERE ${match} = ? AND label IN (${inLabels}) AND valid_to IS NULL`
27802
+ ).all(name2, ...labels);
27803
+ const rank = (r) => [labels.indexOf(r.label), r.at, r.rid];
27804
+ const before = (a, b) => a[0] < b[0] || a[0] === b[0] && (a[1] < b[1] || a[1] === b[1] && a[2] < b[2]);
27805
+ let best;
27806
+ for (const r of [...probe("nodes_live_description", "description"), ...probe("nodes_live_qname", "json_extract(attrs_json, '$.qname')")]) {
27807
+ if (!best || before(rank(r), rank(best))) best = r;
27808
+ }
27809
+ return best ? { label: best.label, description: best.description, qname: typeof best.qname === "string" ? best.qname : null } : null;
27810
+ }
27811
+ instanceGateRows(label) {
27812
+ return this.db.prepare(
27813
+ `SELECT id, json_extract(attrs_json, '$.source') AS source, json_extract(attrs_json, '$.privateFinding') AS privateFinding,
27814
+ json_extract(attrs_json, '$.resolvedAs') AS resolvedAs
27815
+ FROM nodes INDEXED BY nodes_live_instance_gate
27816
+ WHERE label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause') AND label = ? AND valid_to IS NULL
27817
+ ORDER BY label, created_at, rowid`
27818
+ ).all(label);
27819
+ }
27820
+ wmCalibrationRows(labels) {
27821
+ const counted = this.db.prepare(
27822
+ `SELECT rowid AS rid, logical_id, version, valid_to, label, ${WM_CALIBRATION_KEYS.map((k, i2) => `${wmCounterSql(k)} AS c${i2}`).join(", ")}
27823
+ FROM nodes INDEXED BY nodes_wm_counted WHERE ${WM_COUNTED_PREDICATE}`
27824
+ ).all();
27825
+ const exposed = this.db.prepare(
27826
+ `SELECT n.rowid AS rid, n.logical_id, n.version, n.valid_to, n.label, x.attrs_json AS exposure
27827
+ FROM node_exposure x JOIN nodes n ON n.id = x.id`
27828
+ ).all();
27829
+ const others = this.db.prepare(
27830
+ `SELECT rowid AS rid, logical_id, version, valid_to, label FROM nodes WHERE rowid IN (
27831
+ SELECT n.rowid FROM nodes AS n INDEXED BY nodes_logical
27832
+ WHERE n.logical_id IN (SELECT logical_id FROM nodes INDEXED BY nodes_wm_counted WHERE ${WM_COUNTED_PREDICATE}
27833
+ UNION SELECT n2.logical_id FROM node_exposure x2 JOIN nodes n2 ON n2.id = x2.id)
27834
+ EXCEPT SELECT rowid FROM nodes INDEXED BY nodes_wm_counted WHERE ${WM_COUNTED_PREDICATE}
27835
+ EXCEPT SELECT n3.rowid FROM node_exposure x3 JOIN nodes n3 ON n3.id = x3.id)`
27836
+ ).all();
27837
+ const byRid = /* @__PURE__ */ new Map();
27838
+ for (const r of [...counted, ...others]) {
27839
+ const attrs = {};
27840
+ WM_CALIBRATION_KEYS.forEach((k, i2) => {
27841
+ const v = r[`c${i2}`];
27842
+ if (typeof v === "number") attrs[k] = v;
27843
+ });
27844
+ byRid.set(r.rid, { row: r, attrs });
27845
+ }
27846
+ for (const r of exposed) {
27847
+ const side = JSON.parse(r.exposure);
27848
+ const entry = byRid.get(r.rid) ?? { row: r, attrs: {} };
27849
+ for (const k of WM_CALIBRATION_KEYS) if (typeof side[k] === "number" && Number.isFinite(side[k])) entry.attrs[k] = side[k];
27850
+ byRid.set(r.rid, entry);
27851
+ }
27852
+ const order = new Map(labels.map((l, i2) => [l, i2]));
27853
+ return [...byRid.values()].filter(({ row }) => order.has(row.label)).sort((a, b) => order.get(a.row.label) - order.get(b.row.label) || a.row.rid - b.row.rid).map(({ row, attrs }) => ({ logicalId: row.logical_id, version: Number(row.version), validTo: row.valid_to ?? null, attrs }));
27854
+ }
27855
+ liveCommentsAttachedTo(name2) {
27856
+ return this.db.prepare(
27857
+ `SELECT json_extract(attrs_json, '$.kind') AS kind, json_extract(attrs_json, '$.text') AS text, description FROM nodes INDEXED BY nodes_live_attached_to
27858
+ WHERE label = 'Comment' AND valid_to IS NULL AND json_extract(attrs_json, '$.attachedTo') = ? ORDER BY created_at, rowid`
27859
+ ).all(name2);
27860
+ }
27861
+ strandedEdges() {
27862
+ return countStrandedEdges(this.db);
27863
+ }
27864
+ liveHeadConflicts() {
27865
+ return countLiveHeadConflicts(this.db);
27866
+ }
26468
27867
  fileIndexStates(ids) {
26469
27868
  if (ids.length === 0) return [];
26470
27869
  if (ids.length > 500) throw new RangeError("fileIndexStates accepts at most 500 ids per read");
@@ -26563,7 +27962,7 @@ var SqliteGraphStore = class {
26563
27962
  }
26564
27963
  mergeNode(node) {
26565
27964
  this.mutations++;
26566
- this.stmts.insertNode.run({
27965
+ const values = {
26567
27966
  id: node.id,
26568
27967
  label: node.label,
26569
27968
  description: node.description,
@@ -26589,8 +27988,37 @@ var SqliteGraphStore = class {
26589
27988
  logical_id: node.logicalId ?? node.id,
26590
27989
  created_at_seq: node.createdAtSeq ?? null,
26591
27990
  last_reinforced_at_seq: node.lastReinforcedAtSeq ?? null,
26592
- attrs_json: JSON.stringify(node.attrs ?? {})
26593
- });
27991
+ attrs_json: this.nodeAttrsJson(node.id, node.attrs ?? {})
27992
+ };
27993
+ const current = this.stmts.nodeUpsertTarget.get(node.id);
27994
+ if (current) this.writeChangedColumns("nodes", NODE_UPSERT_COLUMNS, current, values);
27995
+ else this.stmts.insertNode.run(values);
27996
+ }
27997
+ /** What the upsert's ON CONFLICT would write over `current`, setting only the
27998
+ * columns whose value moves (NODE_UPSERT_COLUMNS says why). */
27999
+ writeChangedColumns(table, columns2, current, next) {
28000
+ const changed = columns2.filter((c) => !sameSqlValue(current[c], next[c]));
28001
+ if (changed.length === 0) return;
28002
+ const key = `${table}:${changed.join(",")}`;
28003
+ let stmt2 = this.changedColumnStmts.get(key);
28004
+ if (!stmt2) {
28005
+ stmt2 = this.db.prepare(`UPDATE ${table} SET ${changed.map((c) => `${c} = :${c}`).join(", ")} WHERE rowid = :rid`);
28006
+ this.changedColumnStmts.set(key, stmt2);
28007
+ }
28008
+ stmt2.run({ rid: current["rid"], ...Object.fromEntries(changed.map((c) => [c, next[c]])) });
28009
+ }
28010
+ /** mergeNode, unless the live row already holds this content. Content is what
28011
+ * the columns a merge rewrites from the producer (label, description, attrs,
28012
+ * confidence, stability);
28013
+ * rank, community, landmark, surprise, hits, tier and the vector belong to
28014
+ * the passes that compute them, and a skipped write leaves them as they are
28015
+ * where a merge would have reset them to the producer's defaults. Returns
28016
+ * whether it wrote. */
28017
+ mergeNodeIfChanged(node) {
28018
+ const row = this.stmts.nodeContent.get(node.id);
28019
+ if (row && row.valid_to === null && row.label === node.label && row.description === node.description && row.extraction_confidence === node.extractionConfidence && row.stability === node.stability && !EXPOSURE_ATTRS.some((k) => node.attrs?.[k] !== void 0) && row.attrs_json === JSON.stringify(node.attrs ?? {})) return false;
28020
+ this.mergeNode(node);
28021
+ return true;
26594
28022
  }
26595
28023
  updateNode(id, patch) {
26596
28024
  const hasEmbedding = patch.embedding !== void 0 && patch.embedding.length > 0;
@@ -26615,7 +28043,37 @@ var SqliteGraphStore = class {
26615
28043
  logical_id: patch.logicalId ?? null,
26616
28044
  created_at_seq: patch.createdAtSeq ?? null,
26617
28045
  last_reinforced_at_seq: patch.lastReinforcedAtSeq ?? null,
26618
- attrs_json: patch.attrs ? JSON.stringify(patch.attrs) : null
28046
+ attrs_json: patch.attrs ? this.nodeAttrsJson(id, patch.attrs) : null
28047
+ });
28048
+ }
28049
+ /**
28050
+ * The node-row attrs of a write, after handing any exposure keys to the side
28051
+ * row (exposure-attrs.ts). `getNode` returns exposure merged into attrs, so a
28052
+ * read-modify-write carries it; kept in the row it would re-bloat the row and
28053
+ * drift from the side row. Unchanged exposure costs no write.
28054
+ */
28055
+ nodeAttrsJson(id, attrs) {
28056
+ if (!EXPOSURE_ATTRS.some((k) => attrs[k] !== void 0)) return JSON.stringify(attrs);
28057
+ const current = this.stmts.exposureOf.get(id);
28058
+ const next = JSON.stringify({ ...current ? JSON.parse(current.attrs_json) : {}, ...pickExposure(attrs) });
28059
+ if (current?.attrs_json !== next) this.stmts.writeExposure.run(id, next);
28060
+ const rest = { ...attrs };
28061
+ for (const k of EXPOSURE_ATTRS) delete rest[k];
28062
+ return JSON.stringify(rest);
28063
+ }
28064
+ /** One-time: exposure keys written to node rows before the side table existed
28065
+ * move to it. Only rows carrying a counter can carry exposure, and those are
28066
+ * what nodes_wm_counted holds, so this reads the index, not the table. */
28067
+ moveExposureToSideRows() {
28068
+ if (this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(EXPOSURE_SIDE_KEY)) return;
28069
+ const rows = this.db.prepare(`SELECT id, attrs_json FROM nodes INDEXED BY nodes_wm_counted WHERE ${WM_COUNTED_PREDICATE}`).all();
28070
+ const move = this.db.prepare("UPDATE nodes SET attrs_json = ? WHERE id = ?");
28071
+ this.db.transaction(() => {
28072
+ for (const r of rows) {
28073
+ const stripped = this.nodeAttrsJson(r.id, JSON.parse(r.attrs_json));
28074
+ if (stripped !== r.attrs_json) move.run(stripped, r.id);
28075
+ }
28076
+ this.db.prepare("INSERT OR REPLACE INTO store_meta(key, value) VALUES (?, 'done')").run(EXPOSURE_SIDE_KEY);
26619
28077
  });
26620
28078
  }
26621
28079
  /** Fast single-column writes for the nightly pass (avoid the 18-column COALESCE
@@ -26626,26 +28084,30 @@ var SqliteGraphStore = class {
26626
28084
  setLandmark(id, isLandmark) {
26627
28085
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
26628
28086
  }
26629
- setLocalCommunity(id, community, column) {
26630
- this.stmts.setLocalCommunity.run({ id, v: community, col: column ? 1 : 0 });
28087
+ setLocalCommunity(id, community, column2) {
28088
+ this.stmts.setLocalCommunity.run({ id, v: community, col: column2 ? 1 : 0 });
26631
28089
  }
26632
28090
  fieldStmts = /* @__PURE__ */ new Map();
26633
28091
  findNodeFieldsByLabel(label, attrKeys) {
26634
28092
  for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeFieldsByLabel: bad attr key ${k}`);
26635
28093
  const cacheKey = attrKeys.join(",");
26636
- let stmt = this.fieldStmts.get(cacheKey);
26637
- if (!stmt) {
26638
- const cols = attrKeys.map((k, i2) => `, json_extract(attrs_json, '$.${k}') AS a${i2}`).join("");
26639
- stmt = this.db.prepare(
26640
- `SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL`
28094
+ let stmt2 = this.fieldStmts.get(cacheKey);
28095
+ if (!stmt2) {
28096
+ const cols = attrKeys.map((k, i2) => `, ${attrValueSql(`'$.${k}'`)} AS a${i2}, json_type(attrs_json, '$.${k}') AS t${i2}`).join("");
28097
+ stmt2 = this.db.prepare(
28098
+ // Ordered, not left to the planner: readers take "first row wins" (the
28099
+ // symbol lexicon's name winner and doc pick), and the order otherwise
28100
+ // followed whichever partial index the planner chose. nodes_live_created
28101
+ // serves this order without a sort.
28102
+ `SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY created_at, rowid`
26641
28103
  );
26642
- this.fieldStmts.set(cacheKey, stmt);
28104
+ this.fieldStmts.set(cacheKey, stmt2);
26643
28105
  }
26644
- return stmt.all(label).map((r) => {
28106
+ return stmt2.all(label).map((r) => {
26645
28107
  const attrs = {};
26646
28108
  attrKeys.forEach((k, i2) => {
26647
- const v = r[`a${i2}`];
26648
- if (v !== null && v !== void 0) attrs[k] = v;
28109
+ const v = decodeAttr(r[`a${i2}`], r[`t${i2}`]);
28110
+ if (v !== void 0) attrs[k] = v;
26649
28111
  });
26650
28112
  return {
26651
28113
  id: r["id"],
@@ -26656,6 +28118,15 @@ var SqliteGraphStore = class {
26656
28118
  };
26657
28119
  });
26658
28120
  }
28121
+ selectNodes(q) {
28122
+ const { sql, params } = compileNodeSelect(q);
28123
+ const rows = this.db.prepare(sql).all(...params);
28124
+ return rows.map((r) => decodeSelectedRow(r, q.attrs ?? [], q.withEmbedding ? decodeEmbedding : void 0));
28125
+ }
28126
+ countNodes(q) {
28127
+ const { where, params } = compileNodeWhere(q);
28128
+ return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM ${nodeSelectFrom(q)} WHERE ${where}`).get(...params).n);
28129
+ }
26659
28130
  setCommunity(id, community) {
26660
28131
  this.stmts.setCommunity.run({ id, v: community });
26661
28132
  }
@@ -26668,7 +28139,7 @@ var SqliteGraphStore = class {
26668
28139
  return;
26669
28140
  }
26670
28141
  this.mutations++;
26671
- this.stmts.insertEdge.run({
28142
+ const values = {
26672
28143
  id: edge.id,
26673
28144
  from_id: edge.from,
26674
28145
  to_id: edge.to,
@@ -26682,8 +28153,33 @@ var SqliteGraphStore = class {
26682
28153
  valid_from: edge.validFrom ?? edge.createdAt,
26683
28154
  valid_to: edge.validTo ?? null,
26684
28155
  attrs_json: JSON.stringify(edge.attrs ?? {})
28156
+ };
28157
+ const current = this.stmts.edgeUpsertTarget.get(edge.from, edge.type, edge.to);
28158
+ if (!current) {
28159
+ this.stmts.insertEdge.run(values);
28160
+ return;
28161
+ }
28162
+ this.writeChangedColumns("edges", EDGE_UPSERT_COLUMNS, current, {
28163
+ ...values,
28164
+ confidence: Math.max(current["confidence"], edge.confidence),
28165
+ valid_to: null
26685
28166
  });
26686
28167
  }
28168
+ /** mergeEdge, unless the live edge already holds this content: same attrs, and
28169
+ * a confidence the upsert's MAX would keep. Its navigation posteriors and
28170
+ * last-seen stamp stay as they are where a merge would have reset them. The
28171
+ * ontology gate runs first either way, so refusals are recorded as before.
28172
+ * Returns whether it wrote (or refused). */
28173
+ mergeEdgeIfChanged(edge) {
28174
+ if (!this.edgeRuleViolation(edge)) {
28175
+ const row = this.stmts.edgeContent.get(edge.from, edge.type, edge.to);
28176
+ if (row && row.valid_to === null && row.confidence >= edge.confidence && row.attrs_json === JSON.stringify(edge.attrs ?? {})) {
28177
+ return false;
28178
+ }
28179
+ }
28180
+ this.mergeEdge(edge);
28181
+ return true;
28182
+ }
26687
28183
  /** EDGE_RULES check against the stored endpoints' labels, with the LOCAL
26688
28184
  * overlay consulted first. Returns the reason string on a documented-
26689
28185
  * forbidden combination, else null. Point lookups on the id PK — negligible
@@ -26728,11 +28224,13 @@ var SqliteGraphStore = class {
26728
28224
  }
26729
28225
  }
26730
28226
  edgeRuleViolation(edge) {
26731
- return localEdgeViolation(
26732
- this.getNode(edge.from)?.label,
26733
- edge.type,
26734
- this.getNode(edge.to)?.label
26735
- );
28227
+ return localEdgeViolation(this.labelOf(edge.from), edge.type, this.labelOf(edge.to));
28228
+ }
28229
+ /** An endpoint's label, any version, as `getNode(id)?.label` reads it. Every
28230
+ * edge write checks both endpoints, and hydrating them (attrs + vector) to
28231
+ * read one leading column was most of an incremental reindex's reads. */
28232
+ labelOf(id) {
28233
+ return this.stmts.labelOf.get(id)?.label;
26736
28234
  }
26737
28235
  updateEdge(id, patch) {
26738
28236
  this.stmts.updateEdge.run({
@@ -26748,18 +28246,38 @@ var SqliteGraphStore = class {
26748
28246
  }
26749
28247
  getNode(id) {
26750
28248
  const row = this.stmts.getNode.get(id);
26751
- return row ? rowToNode(row) : null;
28249
+ if (!row) return null;
28250
+ const node = rowToNode(row);
28251
+ if (row.exposure_json) Object.assign(node.attrs, JSON.parse(row.exposure_json));
28252
+ return node;
28253
+ }
28254
+ /** A node's render exposure: the side row's keys over the node row's own
28255
+ * (exposure-attrs.ts), plus the node's `lastUpdatedAt` (the "shown since
28256
+ * touch" counter is relative to it) — without reading the node's attrs. */
28257
+ exposureOf(id) {
28258
+ const row = this.stmts.lastUpdatedOf.get(id);
28259
+ if (!row) return null;
28260
+ const side = this.stmts.exposureOf.get(id);
28261
+ return {
28262
+ attrs: { ...pickExposure(JSON.parse(row.attrs_json)), ...side ? JSON.parse(side.attrs_json) : {} },
28263
+ lastUpdatedAt: row.t
28264
+ };
28265
+ }
28266
+ /** Replace a node's exposure (only EXPOSURE_ATTRS keys belong here). Touches
28267
+ * neither the node row nor its indexes, nor the change feed. */
28268
+ writeExposure(id, attrs) {
28269
+ this.stmts.writeExposure.run(id, JSON.stringify(attrs));
26752
28270
  }
26753
28271
  nodeLabels(ids) {
26754
28272
  const width = NODE_LABELS_CHUNK;
26755
- const stmt = this.typedEdgeStmt(
28273
+ const stmt2 = this.typedEdgeStmt(
26756
28274
  `SELECT id, label FROM nodes WHERE id IN (${Array.from({ length: width }, () => "?").join(",")})`
26757
28275
  );
26758
28276
  const labels = /* @__PURE__ */ new Map();
26759
28277
  for (let i2 = 0; i2 < ids.length; i2 += width) {
26760
28278
  const chunk = ids.slice(i2, i2 + width);
26761
28279
  while (chunk.length < width) chunk.push(null);
26762
- for (const row of stmt.all(...chunk)) labels.set(row.id, row.label);
28280
+ for (const row of stmt2.all(...chunk)) labels.set(row.id, row.label);
26763
28281
  }
26764
28282
  return labels;
26765
28283
  }
@@ -26776,7 +28294,21 @@ var SqliteGraphStore = class {
26776
28294
  * per project per request; the materializing form held the daemon's event
26777
28295
  * loop for seconds at scale. */
26778
28296
  countNodesByLabel(label) {
26779
- return Number(this.stmts.countByLabel.get(label).n);
28297
+ return this.countAt(`label:${label}`, [nodeScope(label)], () => Number(this.stmts.countByLabel.get(label).n));
28298
+ }
28299
+ /** Counts asked for on every status poll (/health, `errata status`, the
28300
+ * dashboards): a live-node COUNT(*) reads the whole liveness index, ~3 MB per
28301
+ * call on a 1.1 GB store, to recount a set that moves only on a write. Each is
28302
+ * kept with the change-feed reading of the rows it counts — triggers bump it on
28303
+ * every write from any connection, so a hit is exact, not a TTL guess. */
28304
+ counts = /* @__PURE__ */ new Map();
28305
+ countAt(key, scopes, count) {
28306
+ const seq = readChangeSeq(this.db, scopes);
28307
+ const hit = this.counts.get(key);
28308
+ if (hit && hit.seq === seq) return hit.n;
28309
+ const n = count();
28310
+ this.counts.set(key, { seq, n });
28311
+ return n;
26780
28312
  }
26781
28313
  /** Live rows for a label with attrs and creation stamps only — for scans that
26782
28314
  * read attrs and never the vector. `findNodesByLabel` decodes every embedding
@@ -26785,16 +28317,39 @@ var SqliteGraphStore = class {
26785
28317
  findNodeStampsByLabel(label, attrKey) {
26786
28318
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
26787
28319
  const rows = this.db.prepare(
26788
- `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
28320
+ `SELECT id, created_at, created_at_seq, json_type(${attrDocSql(attrKey)}, '$.${attrKey}') IS NOT NULL AS has,
28321
+ COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
26789
28322
  FROM nodes WHERE label = ? AND valid_to IS NULL`
26790
28323
  ).all(label);
26791
28324
  return rows.map((r) => ({
26792
28325
  id: r.id,
26793
28326
  createdAt: r.created_at,
26794
28327
  ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
26795
- has: r.has === 1
28328
+ has: r.has === 1,
28329
+ cloud: r.cloud === 1
26796
28330
  }));
26797
28331
  }
28332
+ findNodeStampsByLabelAttrs(label, attrKeys) {
28333
+ for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeStampsByLabelAttrs: bad attr key ${k}`);
28334
+ const keys = [...new Set(attrKeys)];
28335
+ const rows = this.db.prepare(
28336
+ `SELECT id, created_at, created_at_seq,
28337
+ ${keys.map((k, i2) => `json_type(${attrDocSql(k)}, '$.${k}') IS NOT NULL AS h${i2}`).join(", ")}${keys.length ? "," : ""}
28338
+ COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
28339
+ FROM nodes WHERE label = ? AND valid_to IS NULL`
28340
+ ).all(label);
28341
+ const out2 = new Map(keys.map((k) => [k, []]));
28342
+ for (const r of rows) {
28343
+ keys.forEach((k, i2) => out2.get(k).push({
28344
+ id: r.id,
28345
+ createdAt: r.created_at,
28346
+ ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
28347
+ has: r[`h${i2}`] === 1,
28348
+ cloud: r.cloud === 1
28349
+ }));
28350
+ }
28351
+ return out2;
28352
+ }
26798
28353
  findNodeAttrsByLabel(label) {
26799
28354
  const rows = this.stmts.attrsByLabel.all(label);
26800
28355
  return rows.map((r) => ({
@@ -26822,8 +28377,8 @@ var SqliteGraphStore = class {
26822
28377
  after = rows[rows.length - 1].rid;
26823
28378
  }
26824
28379
  }
26825
- recentNodeIds(label, limit) {
26826
- const rows = this.db.prepare("SELECT id FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY last_updated_at DESC LIMIT ?").all(label, Math.max(0, limit));
28380
+ recentProblemIds(limit) {
28381
+ const rows = this.db.prepare("SELECT id FROM nodes WHERE label = 'Problem' AND valid_to IS NULL ORDER BY last_updated_at DESC LIMIT ?").all(Math.max(0, limit));
26827
28382
  return rows.map((r) => r.id);
26828
28383
  }
26829
28384
  recentOpenProblemCandidates(opts) {
@@ -26903,6 +28458,20 @@ var SqliteGraphStore = class {
26903
28458
  }
26904
28459
  searchTextCandidates(terms) {
26905
28460
  if (terms.length === 0) return [];
28461
+ const indexed = terms.filter((t) => t.length >= TEXT_INDEX_MIN_TERM);
28462
+ if (indexed.length > 0 && textIndexReady(this.db)) {
28463
+ const short = terms.filter((t) => t.length < TEXT_INDEX_MIN_TERM).map((t) => t.toLowerCase());
28464
+ const rows2 = this.db.prepare(`WITH hits AS MATERIALIZED (
28465
+ SELECT t.rowid AS rid, COUNT(*) AS matched FROM json_each(:terms) q, nodes_text t
28466
+ WHERE t.description LIKE '%' || q.value || '%' GROUP BY t.rowid
28467
+ ) SELECT ${TEXT_SEARCH_COLUMNS}, hits.matched FROM hits JOIN nodes ON nodes.rowid = hits.rid
28468
+ WHERE nodes.valid_to IS NULL ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(indexed) });
28469
+ return rows2.map((row) => {
28470
+ const text = row.description.toLowerCase();
28471
+ const extra = short.filter((t) => text.includes(t)).length;
28472
+ return { node: textSearchNode(row), matched: row.matched + extra };
28473
+ });
28474
+ }
26906
28475
  const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
26907
28476
  SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
26908
28477
  WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
@@ -26911,6 +28480,18 @@ var SqliteGraphStore = class {
26911
28480
  JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
26912
28481
  return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
26913
28482
  }
28483
+ commentAnchors(commentIds) {
28484
+ const out2 = /* @__PURE__ */ new Map();
28485
+ if (commentIds.length === 0) return out2;
28486
+ const rows = this.db.prepare(`WITH a AS MATERIALIZED (
28487
+ SELECT q.value AS cid, COALESCE(
28488
+ (SELECT to_id FROM edges WHERE from_id = q.value AND type IN ('EXPLAINS', 'ANNOTATES') AND valid_to IS NULL LIMIT 1),
28489
+ (SELECT from_id FROM edges WHERE to_id = q.value AND type = 'DOCUMENTED_BY' AND valid_to IS NULL LIMIT 1)
28490
+ ) AS aid FROM json_each(:ids) q
28491
+ ) SELECT a.cid AS cid, ${TEXT_SEARCH_COLUMNS} FROM a JOIN nodes ON nodes.id = a.aid AND nodes.valid_to IS NULL`).all({ ids: JSON.stringify(commentIds) });
28492
+ for (const row of rows) out2.set(row.cid, textSearchNode(row));
28493
+ return out2;
28494
+ }
26914
28495
  getTextSearchNode(id) {
26915
28496
  const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
26916
28497
  return row ? textSearchNode(row) : null;
@@ -26930,12 +28511,12 @@ var SqliteGraphStore = class {
26930
28511
  return scale;
26931
28512
  }
26932
28513
  typedEdgeStmt(sql) {
26933
- let stmt = this.typedEdgeStmts.get(sql);
26934
- if (!stmt) {
26935
- stmt = this.db.prepare(sql);
26936
- this.typedEdgeStmts.set(sql, stmt);
28514
+ let stmt2 = this.typedEdgeStmts.get(sql);
28515
+ if (!stmt2) {
28516
+ stmt2 = this.db.prepare(sql);
28517
+ this.typedEdgeStmts.set(sql, stmt2);
26937
28518
  }
26938
- return stmt;
28519
+ return stmt2;
26939
28520
  }
26940
28521
  outEdges(nodeId, types) {
26941
28522
  if (!types || types.length === 0) {
@@ -26994,21 +28575,54 @@ var SqliteGraphStore = class {
26994
28575
  return out2;
26995
28576
  }
26996
28577
  nodeCount() {
26997
- return Number(this.stmts.nodeCount.get().n);
28578
+ return this.countAt("nodes", [ANY_CHANGE], () => Number(this.stmts.nodeCount.get().n));
26998
28579
  }
26999
28580
  mutationCount() {
27000
28581
  return this.mutations;
27001
28582
  }
28583
+ changeStamp() {
28584
+ const { data_version } = this.db.pragma("data_version");
28585
+ const { n } = this.db.prepare("SELECT total_changes() AS n").get();
28586
+ return `${data_version}:${n}`;
28587
+ }
28588
+ changeSeq(scopes) {
28589
+ return readChangeSeq(this.db, scopes);
28590
+ }
28591
+ lineageChangedFiles(sinceSeq) {
28592
+ return readLineageChangedFiles(this.db, sinceSeq);
28593
+ }
28594
+ changedNodeIds(sinceSeq, labels) {
28595
+ return readChangedNodeIds(this.db, sinceSeq, labels);
28596
+ }
28597
+ changedAmong(sinceSeq, ids) {
28598
+ return readChangedAmong(this.db, sinceSeq, ids);
28599
+ }
28600
+ pruneChangeLog() {
28601
+ return pruneChangeLog(this.db);
28602
+ }
28603
+ fileRowStates(ids) {
28604
+ if (ids.length === 0) return [];
28605
+ if (ids.length > 500) throw new RangeError("fileRowStates accepts at most 500 ids per read");
28606
+ return this.db.prepare(`SELECT id, last_updated_at AS lastUpdatedAt, valid_to AS validTo FROM nodes WHERE id IN (${ids.map(() => "?").join(",")})`).all(...ids);
28607
+ }
28608
+ // Read and advanced in SQL, never from a per-connection copy: pass workers and
28609
+ // MCP processes open their own connections and advance the same row, so a
28610
+ // copy loaded at open went stale, and `copy + 1` wrote a duplicate or a
28611
+ // backwards seq from whichever connection had fallen behind.
27002
28612
  currentIngestSeq() {
28613
+ const row = this.db.prepare("SELECT value FROM store_meta WHERE key = 'ingest_seq'").get();
28614
+ this.ingestSeq = row ? Number(row.value) : 0;
27003
28615
  return this.ingestSeq;
27004
28616
  }
27005
28617
  nextIngestSeq() {
27006
- this.ingestSeq += 1;
27007
- this.stmts.setIngestSeq.run({ v: String(this.ingestSeq) });
28618
+ const row = this.db.prepare(
28619
+ "INSERT INTO store_meta (key, value) VALUES ('ingest_seq', '1') ON CONFLICT(key) DO UPDATE SET value = CAST(value AS INTEGER) + 1 RETURNING value"
28620
+ ).get();
28621
+ this.ingestSeq = Number(row.value);
27008
28622
  return this.ingestSeq;
27009
28623
  }
27010
28624
  edgeCount() {
27011
- return Number(this.stmts.edgeCount.get().n);
28625
+ return this.countAt("edges", [ANY_CHANGE], () => Number(this.stmts.edgeCount.get().n));
27012
28626
  }
27013
28627
  // Lightweight whole-graph scans — select only the columns the caller needs so a
27014
28628
  // 100k-node pass skips the per-row attrs JSON.parse + embedding decode rowToNode
@@ -27136,28 +28750,63 @@ var SqliteGraphStore = class {
27136
28750
  }
27137
28751
  }
27138
28752
  reviveReobserved(relPaths, workspaceId, since) {
27139
- let revived = 0;
28753
+ const revived = [];
27140
28754
  const CHUNK = 400;
27141
28755
  for (let i2 = 0; i2 < relPaths.length; i2 += CHUNK) {
27142
28756
  const slice = relPaths.slice(i2, i2 + CHUNK);
27143
28757
  if (slice.length === 0) continue;
27144
- const r = this.db.prepare(
27145
- `UPDATE nodes SET valid_to = NULL
28758
+ const rows = this.db.prepare(
28759
+ `SELECT id, valid_to AS closedAt, COALESCE(logical_id, id) AS lid FROM nodes
27146
28760
  WHERE valid_to IS NOT NULL
27147
28761
  AND last_updated_at >= ?
27148
28762
  AND json_extract(attrs_json, '$.workspaceId') = ?
27149
- AND json_extract(attrs_json, '$.relPath') IN (${slice.map(() => "?").join(",")})`
27150
- ).run(since, workspaceId, ...slice);
27151
- revived += Number(r.changes);
27152
- }
27153
- if (revived > 0) this.mutations++;
27154
- return revived;
28763
+ AND json_extract(attrs_json, '$.relPath') IN (${slice.map(() => "?").join(",")})
28764
+ AND json_type(attrs_json, '$.historical') IS NOT 'true'`
28765
+ ).all(since, workspaceId, ...slice);
28766
+ revived.push(...rows);
28767
+ }
28768
+ if (revived.length === 0) return 0;
28769
+ const reopen = this.db.prepare("UPDATE nodes SET valid_to = NULL WHERE id = ? AND valid_to IS NOT NULL");
28770
+ for (const r of revived) reopen.run(r.id);
28771
+ for (const r of revived) reopenCascadeClosedEdges(this.db, r.id, Number(r.closedAt));
28772
+ collapseLiveHeads(this.db, revived.map((r) => r.lid), since);
28773
+ this.mutations++;
28774
+ return revived.length;
28775
+ }
28776
+ incomingEdgeCoverage(label, edgeTypes, cloudOnly) {
28777
+ if (edgeTypes.length === 0) return { count: 0, total: 0 };
28778
+ const r = this.db.prepare(
28779
+ `SELECT COUNT(*) AS total,
28780
+ COALESCE(SUM(CASE WHEN EXISTS (
28781
+ SELECT 1 FROM edges e WHERE e.to_id = n.id AND e.valid_to IS NULL
28782
+ AND e.type IN (${edgeTypes.map(() => "?").join(",")})
28783
+ ) THEN 1 ELSE 0 END), 0) AS count
28784
+ FROM nodes n
28785
+ WHERE n.label = ? AND n.valid_to IS NULL
28786
+ AND (? = 0 OR json_extract(n.attrs_json, '$.source') = 'cloud')`
28787
+ ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
28788
+ return { count: Number(r.count), total: Number(r.total) };
28789
+ }
28790
+ liveEdgeTargets(edgeTypes) {
28791
+ if (edgeTypes.length === 0) return [];
28792
+ const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
28793
+ return rows.map((r) => r.to_id);
27155
28794
  }
27156
28795
  recentEdgeAttrCoverage(marker, attr, limit) {
28796
+ if (marker === PRIOR_TAG_MARKER) {
28797
+ const r2 = this.db.prepare(
28798
+ `SELECT COUNT(*) AS total,
28799
+ COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
28800
+ FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
28801
+ WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
28802
+ ORDER BY created_at DESC LIMIT ?)`
28803
+ ).get(attr, limit);
28804
+ return { count: Number(r2.count), total: Number(r2.total) };
28805
+ }
27157
28806
  const r = this.db.prepare(
27158
28807
  `SELECT COUNT(*) AS total,
27159
28808
  COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
27160
- FROM (SELECT attrs_json FROM edges
28809
+ FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_created
27161
28810
  WHERE valid_to IS NULL AND attrs_json LIKE ?
27162
28811
  ORDER BY created_at DESC LIMIT ?)`
27163
28812
  ).get(attr, `%${marker}%`, limit);
@@ -27170,7 +28819,7 @@ var SqliteGraphStore = class {
27170
28819
  const slice = cloudIds.slice(i2, i2 + CHUNK);
27171
28820
  if (slice.length === 0) continue;
27172
28821
  const rows = this.db.prepare(
27173
- `SELECT id, json_extract(attrs_json, '$.cloudNodeId') AS cloud FROM nodes INDEXED BY nodes_cloud_node_id WHERE json_extract(attrs_json, '$.cloudNodeId') IN (${slice.map(() => "?").join(",")}) AND valid_to IS NULL ORDER BY id`
28822
+ `SELECT id, json_extract(attrs_json, '$.cloudNodeId') AS cloud FROM nodes INDEXED BY nodes_cloud_node_id_v2 WHERE json_extract(attrs_json, '$.cloudNodeId') IN (${slice.map(() => "?").join(",")}) AND valid_to IS NULL ORDER BY id`
27174
28823
  ).all(...slice);
27175
28824
  for (const r of rows) out2.set(r.cloud, [...out2.get(r.cloud) ?? [], r.id]);
27176
28825
  }
@@ -27283,8 +28932,9 @@ var SqliteGraphStore = class {
27283
28932
  this.stmts.advanceLive.run({ live_id: liveId, t });
27284
28933
  return frozenId;
27285
28934
  }
27286
- closeNode(id, t) {
27287
- this.stmts.closeNode.run({ id, t });
28935
+ closeNode(id, t, opts = {}) {
28936
+ const r = this.stmts.closeNode.run({ id, t });
28937
+ if (Number(r.changes) > 0 && !opts.retainEdges) closeIncidentEdges(this.db, id, t);
27288
28938
  }
27289
28939
  closeEdge(id, t) {
27290
28940
  this.stmts.closeEdge.run({ id, t });
@@ -27304,9 +28954,11 @@ var SqliteGraphStore = class {
27304
28954
  * so it must be a plain identifier. */
27305
28955
  nodesAsOfWhereTrue(t, attr) {
27306
28956
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
28957
+ const indexed = attr === "revisit" ? " INDEXED BY nodes_revisit_true" : "";
27307
28958
  const rows = this.db.prepare(
27308
- `SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
27309
- AND json_type(attrs_json, '$.${attr}') = 'true'`
28959
+ `SELECT * FROM nodes${indexed} WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
28960
+ AND json_type(attrs_json, '$.${attr}') = 'true'
28961
+ ORDER BY rowid`
27310
28962
  ).all({ t });
27311
28963
  return rows.map(rowToNode);
27312
28964
  }
@@ -27390,19 +29042,16 @@ function conditionOf(node) {
27390
29042
  }
27391
29043
  function clearAnsweredRevisits(store2, ts) {
27392
29044
  const report = { cleared: 0, standing: 0 };
27393
- for (const label of SEMANTIC_NODE_LABELS) {
27394
- for (const row of store2.findNodeFieldsByLabel(label, ["revisit"])) {
27395
- if (row.attrs["revisit"] !== 1 && row.attrs["revisit"] !== true) continue;
27396
- const node = store2.getNode(row.id);
27397
- if (!node || node.attrs["revisit"] !== true) continue;
27398
- const condition = conditionOf(node);
27399
- if (condition === void 0 || !isRevisitAnswered(store2, node, condition)) {
27400
- report.standing++;
27401
- continue;
27402
- }
27403
- clearRevisit(store2, node.id, ts);
27404
- report.cleared++;
29045
+ const semantic = new Set(SEMANTIC_NODE_LABELS);
29046
+ for (const node of store2.nodesAsOfWhereTrue(ts, "revisit")) {
29047
+ if (!semantic.has(node.label) || node.validTo != null) continue;
29048
+ const condition = conditionOf(node);
29049
+ if (condition === void 0 || !isRevisitAnswered(store2, node, condition)) {
29050
+ report.standing++;
29051
+ continue;
27405
29052
  }
29053
+ clearRevisit(store2, node.id, ts);
29054
+ report.cleared++;
27406
29055
  }
27407
29056
  return report;
27408
29057
  }
@@ -27566,7 +29215,7 @@ var NAME_SEPARATOR = /[@/\-._]/;
27566
29215
  var MIN_NAME_LEN = 3;
27567
29216
  function buildPackageIndex(store2) {
27568
29217
  const idx = /* @__PURE__ */ new Map();
27569
- for (const n of store2.findNodesByLabel("Package")) {
29218
+ for (const n of store2.selectNodes({ labels: ["Package"], attrs: ["name", "resolved"] })) {
27570
29219
  const name2 = String(n.attrs["name"] ?? "").trim();
27571
29220
  if (!name2) continue;
27572
29221
  const key = name2.toLowerCase();
@@ -27633,7 +29282,7 @@ function backfillProblemPackageLinks(store2, ts) {
27633
29282
  const report = { problems: 0, edges: 0 };
27634
29283
  const idx = buildPackageIndex(store2);
27635
29284
  if (idx.size === 0) return report;
27636
- for (const p of store2.findNodesByLabel("Problem")) {
29285
+ for (const p of store2.selectNodes({ labels: ["Problem"], attrs: ["resolvedAs"] })) {
27637
29286
  if (p.attrs["resolvedAs"] === "false_positive") continue;
27638
29287
  const { linked } = linkProblemToPackages(store2, p.id, problemText(store2, p), ts, idx);
27639
29288
  if (linked.length > 0) {
@@ -27673,7 +29322,7 @@ function deriveContextFromAnchors(store2, problemId, ts, pkgIndex) {
27673
29322
  if (!p || p.label !== "Problem" && p.label !== "Vulnerability") return report;
27674
29323
  const files = store2.outEdges(problemId, ["ANCHORED_AT"]).map((e) => store2.getNode(e.to)).filter((n) => !!n && n.label === "File");
27675
29324
  if (files.length === 0) return report;
27676
- const idx = pkgIndex ?? buildPackageIndex(store2);
29325
+ let idx = pkgIndex;
27677
29326
  const haveLang = new Set(store2.outEdges(problemId, ["OCCURS_IN"]).map((e) => e.to));
27678
29327
  const havePkg = new Set(store2.outEdges(problemId, ["DEPENDS_ON"]).map((e) => e.to));
27679
29328
  for (const file2 of files) {
@@ -27712,7 +29361,7 @@ function deriveContextFromAnchors(store2, problemId, ts, pkgIndex) {
27712
29361
  if (!mod) continue;
27713
29362
  const name2 = specToPackageName(mod.description);
27714
29363
  if (!name2) continue;
27715
- const pkg = idx.get(name2);
29364
+ const pkg = (idx ??= buildPackageIndex(store2)).get(name2);
27716
29365
  if (!pkg || havePkg.has(pkg.id)) continue;
27717
29366
  addDependency(store2, {
27718
29367
  fromId: problemId,
@@ -27731,7 +29380,7 @@ function deriveContextFromAnchors(store2, problemId, ts, pkgIndex) {
27731
29380
  function backfillProblemContext(store2, ts) {
27732
29381
  const report = { problems: 0, edges: 0 };
27733
29382
  const idx = buildPackageIndex(store2);
27734
- for (const p of store2.findNodesByLabel("Problem")) {
29383
+ for (const p of store2.selectNodes({ labels: ["Problem"], attrs: ["resolvedAs"] })) {
27735
29384
  if (p.attrs["resolvedAs"] === "false_positive") continue;
27736
29385
  const r = deriveContextFromAnchors(store2, p.id, ts, idx);
27737
29386
  const n = r.languages.length + r.packages.length;
@@ -27757,6 +29406,11 @@ var REDIRECT_EDGES = [
27757
29406
  "MANIFESTED_IN",
27758
29407
  "EVIDENCED_BY"
27759
29408
  ];
29409
+ var OPEN_PROBLEM_WHERE = [
29410
+ { attr: "resolvedAt", nullish: true },
29411
+ { attr: "mergedInto", absent: true }
29412
+ ];
29413
+ var OPEN_PROBLEM_KEYS = ["kind", "corroborations"];
27760
29414
  function corroborations(n) {
27761
29415
  return Number(n.attrs["corroborations"] ?? 0);
27762
29416
  }
@@ -27770,7 +29424,7 @@ function mergeDuplicateProblems(store2, opts) {
27770
29424
  const minOverlap = opts.minOverlap ?? 0.85;
27771
29425
  const minTokens = opts.minTokens ?? 4;
27772
29426
  const report = { clusters: 0, merged: 0 };
27773
- const open = store2.findNodesByLabel("Problem").filter((p) => p.attrs["resolvedAt"] == null && p.attrs["mergedInto"] === void 0);
29427
+ const open = store2.selectNodes({ labels: ["Problem"], attrs: OPEN_PROBLEM_KEYS, where: OPEN_PROBLEM_WHERE });
27774
29428
  const tokens = /* @__PURE__ */ new Map();
27775
29429
  for (const p of open) tokens.set(p.id, new Set(retrievalTokens(p.description)));
27776
29430
  const consumed = /* @__PURE__ */ new Set();
@@ -27794,8 +29448,9 @@ function mergeDuplicateProblems(store2, opts) {
27794
29448
  if (cluster.length < 2) continue;
27795
29449
  report.clusters++;
27796
29450
  cluster.sort((x, y) => corroborations(y) - corroborations(x) || x.createdAt - y.createdAt);
27797
- const survivor = cluster[0];
27798
- for (const dup of cluster.slice(1)) {
29451
+ const members = cluster.map((m) => store2.getNode(m.id)).filter((n) => n !== null);
29452
+ const survivor = members[0];
29453
+ for (const dup of members.slice(1)) {
27799
29454
  foldDuplicateProblem(store2, dup, survivor, opts.ts);
27800
29455
  report.merged++;
27801
29456
  }
@@ -27808,16 +29463,19 @@ function foldDuplicateProblem(store2, dup, survivor, ts) {
27808
29463
  if (!surv) return;
27809
29464
  const sources = new Set(surv.attrs["sources"] ?? []);
27810
29465
  for (const s of dup.attrs["sources"] ?? []) sources.add(s);
27811
- const dupSeq = dup.attrs["createdAtSeq"] ?? store2.currentIngestSeq();
27812
- const exposure = priorExposure(store2, survivor.id, dupSeq);
27813
- const expField = `reinforce${exposure[0].toUpperCase()}${exposure.slice(1)}Count`;
29466
+ const samePass = dup.createdAt === surv.createdAt;
29467
+ const [held, restated] = dup.createdAt < surv.createdAt ? [dup, surv] : [surv, dup];
29468
+ const at = {
29469
+ seq: restated.createdAtSeq ?? restated.attrs["createdAtSeq"] ?? store2.currentIngestSeq(),
29470
+ ts: restated.createdAt
29471
+ };
29472
+ const exposure = samePass ? null : priorExposure(store2, held.id, at);
27814
29473
  store2.updateNode(survivor.id, {
27815
29474
  attrs: {
27816
29475
  ...surv.attrs,
27817
29476
  sources: [...sources],
27818
29477
  corroborations: corroborations(surv) + corroborations(dup) + 1,
27819
- [expField]: (surv.attrs[expField] ?? 0) + 1,
27820
- lastReinforceExposure: exposure
29478
+ ...exposure ? exposureOutcomeAttrs(surv, exposure, at) : {}
27821
29479
  },
27822
29480
  cumulativeHits: (surv.cumulativeHits ?? 0) + (dup.cumulativeHits ?? 0),
27823
29481
  lastUpdatedAt: ts
@@ -27848,11 +29506,21 @@ function isConstraintProblem(node) {
27848
29506
  return node.attrs["kind"] === "constraint";
27849
29507
  }
27850
29508
  var RECURRENCE_DEBOUNCE_MS = 60 * 60 * 1e3;
27851
- function resolveFileNode(store2, path, workspaceId) {
27852
- const want = path.trim().replace(/^\.?\//, "");
27853
- for (const n of store2.findNodesByLabel("File")) {
27854
- if (n.attrs["workspaceId"] && n.attrs["workspaceId"] !== workspaceId) continue;
27855
- if (n.attrs["relPath"] === want || n.description === want) return n;
29509
+ function resolveFileNode(store2, path2, workspaceId) {
29510
+ const want = path2.trim().replace(/^\.?\//, "");
29511
+ const id = firstFileByPath(store2, want, (a) => !(a["workspaceId"] && a["workspaceId"] !== workspaceId));
29512
+ return id ? store2.getNode(id) : null;
29513
+ }
29514
+ function firstFileByPath(store2, want, accept) {
29515
+ const byPath = store2.selectNodes({ labels: ["File"], attrs: ["workspaceId"], where: [{ attr: "relPath", eq: want }] }).find((r) => accept(r.attrs))?.id;
29516
+ const described = store2.liveNodesByDescription([want], ["File"]).filter((n) => accept(n.attrs));
29517
+ const byDescription = described.length === 1 ? described[0].id : void 0;
29518
+ if (described.length <= 1 && (byPath === void 0 || byDescription === void 0 || byPath === byDescription)) {
29519
+ return byPath ?? byDescription ?? null;
29520
+ }
29521
+ for (const r of store2.selectNodes({ labels: ["File"], attrs: ["workspaceId", "relPath"] })) {
29522
+ if (!accept(r.attrs)) continue;
29523
+ if (r.attrs["relPath"] === want || r.description === want) return r.id;
27856
29524
  }
27857
29525
  return null;
27858
29526
  }
@@ -27868,13 +29536,8 @@ function isAutoMinted(n) {
27868
29536
  }
27869
29537
  function priorsForFile(store2, relPath) {
27870
29538
  const want = relPath.trim().replace(/^\.?\//, "");
27871
- let file2 = null;
27872
- for (const n of store2.findNodesByLabel("File")) {
27873
- if (n.description === want || n.attrs["relPath"] === want) {
27874
- file2 = n;
27875
- break;
27876
- }
27877
- }
29539
+ const fileId = firstFileByPath(store2, want, () => true);
29540
+ const file2 = fileId ? store2.getNode(fileId) : null;
27878
29541
  if (!file2) return null;
27879
29542
  const openProblems = [];
27880
29543
  const constraints = [];
@@ -28064,10 +29727,10 @@ function openAnchorHint(p) {
28064
29727
  if (!h || typeof h.path !== "string" || h.upgradedAt) return null;
28065
29728
  return { path: h.path, ts: typeof h.ts === "number" ? h.ts : 0 };
28066
29729
  }
28067
- function consumeAnchorHint(store2, p, ts) {
29730
+ function consumeAnchorHint(store2, p, ts, pkgIndex) {
28068
29731
  const hint = p.attrs["anchorHint"];
28069
29732
  store2.updateNode(p.id, { attrs: { ...p.attrs, anchorHint: { ...hint, upgradedAt: ts } } });
28070
- deriveContextFromAnchors(store2, p.id, ts);
29733
+ deriveContextFromAnchors(store2, p.id, ts, pkgIndex);
28071
29734
  }
28072
29735
  function upgradeAnchorHints(store2, workspaceId, ts) {
28073
29736
  let upgraded = 0;
@@ -28075,14 +29738,21 @@ function upgradeAnchorHints(store2, workspaceId, ts) {
28075
29738
  let unresolvable = 0;
28076
29739
  let blocked = 0;
28077
29740
  const filesByPath = /* @__PURE__ */ new Map();
28078
- for (const f of store2.findNodesByLabel("File")) {
29741
+ for (const f of store2.selectNodes({ labels: ["File"], attrs: ["workspaceId", "relPath", "contentChangedAt"] })) {
28079
29742
  if (f.attrs["workspaceId"] && f.attrs["workspaceId"] !== workspaceId) continue;
28080
29743
  const rel = typeof f.attrs["relPath"] === "string" ? f.attrs["relPath"] : f.description;
28081
29744
  if (rel && !filesByPath.has(rel)) filesByPath.set(rel, f);
28082
29745
  }
28083
- for (const p of store2.findNodesByLabel("Problem")) {
28084
- if (p.validTo != null || p.attrs["resolvedAt"]) continue;
28085
- const hint = openAnchorHint(p);
29746
+ let pkgIndex;
29747
+ const hinted = store2.selectNodes({
29748
+ labels: ["Problem"],
29749
+ attrs: ["resolvedAt", "anchorHint"],
29750
+ where: [{ attr: "anchorHint", notNullish: true }],
29751
+ indexedBy: "nodes_live_anchor_hint"
29752
+ });
29753
+ for (const row of hinted) {
29754
+ if (row.attrs["resolvedAt"]) continue;
29755
+ const hint = openAnchorHint(row);
28086
29756
  if (!hint) continue;
28087
29757
  const file2 = filesByPath.get(hint.path.trim().replace(/^\.?\//, ""));
28088
29758
  if (!file2 || !isAnchorableCodePath(hint.path)) {
@@ -28092,8 +29762,10 @@ function upgradeAnchorHints(store2, workspaceId, ts) {
28092
29762
  standing++;
28093
29763
  const changedAt = Number(file2.attrs["contentChangedAt"] ?? 0);
28094
29764
  if (changedAt <= hint.ts) continue;
29765
+ const p = store2.getNode(row.id);
29766
+ if (!p) continue;
28095
29767
  if (anchorProblemToWorkingFile(store2, p.id, hint.path, workspaceId, ts, "hint-confirmed")) {
28096
- consumeAnchorHint(store2, p, ts);
29768
+ consumeAnchorHint(store2, p, ts, pkgIndex ??= buildPackageIndex(store2));
28097
29769
  upgraded++;
28098
29770
  standing--;
28099
29771
  } else {
@@ -28104,7 +29776,13 @@ function upgradeAnchorHints(store2, workspaceId, ts) {
28104
29776
  }
28105
29777
  function reopenAutoClosedProblems(store2, t) {
28106
29778
  const report = { reopened: 0, alreadySuspect: 0, agentDescribed: 0 };
28107
- for (const p of store2.findNodesByLabel("Problem")) {
29779
+ const closed = store2.selectNodes({
29780
+ labels: ["Problem"],
29781
+ attrs: ["resolvedAt", "resolvedAs", "mergedInto", "resolutionWitnessed", "retiredEditPlaceholder", "resolutionSuspect"],
29782
+ where: [{ attr: "resolvedAt", notNullish: true }, { attr: "resolvedAs", nullish: true }, { attr: "mergedInto", absent: true }],
29783
+ indexedBy: "nodes_live_resolved"
29784
+ });
29785
+ for (const p of closed) {
28108
29786
  if (p.attrs["resolvedAt"] == null) continue;
28109
29787
  if (p.attrs["resolvedAs"] != null) continue;
28110
29788
  if (p.attrs["mergedInto"] !== void 0) continue;
@@ -28119,7 +29797,9 @@ function reopenAutoClosedProblems(store2, t) {
28119
29797
  continue;
28120
29798
  }
28121
29799
  if (p.attrs["resolutionSuspect"] === true) report.alreadySuspect++;
28122
- const attrs = { ...p.attrs };
29800
+ const node = store2.getNode(p.id);
29801
+ if (!node) continue;
29802
+ const attrs = { ...node.attrs };
28123
29803
  delete attrs["resolvedAt"];
28124
29804
  attrs["reopenedFrom"] = "auto-close";
28125
29805
  attrs["reopenedAt"] = t;
@@ -28130,7 +29810,12 @@ function reopenAutoClosedProblems(store2, t) {
28130
29810
  }
28131
29811
  function markFixCandidates(store2, t) {
28132
29812
  let resolved = 0;
28133
- for (const p of store2.findNodesByLabel("Problem")) {
29813
+ const candidates = store2.selectNodes({
29814
+ labels: ["Problem"],
29815
+ attrs: ["resolvedAt", "kind", "fixCandidateClearedAt", "fixCandidateAt"],
29816
+ where: [{ idPrefix: "dprob_" }]
29817
+ });
29818
+ for (const p of candidates) {
28134
29819
  if (!p.id.startsWith("dprob_")) continue;
28135
29820
  if (p.attrs["resolvedAt"]) continue;
28136
29821
  if (isConstraintProblem(p)) continue;
@@ -28157,9 +29842,11 @@ function markFixCandidates(store2, t) {
28157
29842
  return s !== null && !String(s.description ?? "").startsWith(AUTO_MINT_PREFIX);
28158
29843
  }))
28159
29844
  continue;
29845
+ const node = store2.getNode(p.id);
29846
+ if (!node) continue;
28160
29847
  store2.updateNode(p.id, {
28161
29848
  attrs: {
28162
- ...p.attrs,
29849
+ ...node.attrs,
28163
29850
  // The cue, kept as structured data so the render can name the file it is
28164
29851
  // asking about. Deliberately NOT `resolvedAt` — this is a question.
28165
29852
  fixCandidateAt: t,
@@ -28169,7 +29856,7 @@ function markFixCandidates(store2, t) {
28169
29856
  // measurable. `shownCount` is the node's LIFETIME count across every
28170
29857
  // band, so comparing it raw would retire a fresh ask on a
28171
29858
  // frequently-surfaced problem before anyone had seen the question once.
28172
- fixCandidateShownBase: Number(p.attrs["shownCount"] ?? 0)
29859
+ fixCandidateShownBase: Number(node.attrs["shownCount"] ?? 0)
28173
29860
  }
28174
29861
  // No `lastUpdatedAt`: raising a question is bookkeeping, not a new
28175
29862
  // observation of the problem, and the passive block's recent-problems band
@@ -28182,7 +29869,10 @@ function markFixCandidates(store2, t) {
28182
29869
  var FIX_CANDIDATE_ASK_LIMIT = 5;
28183
29870
  function clearSettledFixCandidates(store2, t) {
28184
29871
  const report = { answered: 0, ignored: 0, unsubstantiated: 0, standing: 0 };
28185
- for (const p of store2.findNodesByLabel("Problem")) {
29872
+ const asked = store2.selectNodes({ labels: ["Problem"], where: [{ attr: "fixCandidateAt", present: true }], indexedBy: "nodes_live_fix_candidate" });
29873
+ for (const row of asked) {
29874
+ const p = store2.getNode(row.id);
29875
+ if (!p) continue;
28186
29876
  if (p.attrs["fixCandidateAt"] === void 0) continue;
28187
29877
  const fileAnchors = store2.outEdges(p.id, ["ANCHORED_AT"]).filter((e) => e.attrs?.["mention"] !== true && e.attrs?.["anchorProvenance"] !== "legacy").map((e) => store2.getNode(e.to)).filter((n) => n !== null && n.label === "File");
28188
29878
  const unsubstantiated = fileAnchors.length > 0 && fileAnchors.every((f) => f.attrs["contentChangedAt"] === void 0);
@@ -28211,16 +29901,77 @@ function clearSettledFixCandidates(store2, t) {
28211
29901
  }
28212
29902
  return report;
28213
29903
  }
28214
- function priorExposure(store2, nodeId, atSeq) {
29904
+ function exposureLog(attrs) {
29905
+ const raw = attrs["exposureLog"];
29906
+ if (!Array.isArray(raw)) return [];
29907
+ return raw.filter(
29908
+ (e) => Array.isArray(e) && typeof e[0] === "number" && (e[1] === "r" || e[1] === "c" || e[1] === "e")
29909
+ );
29910
+ }
29911
+ function priorExposure(store2, nodeId, at) {
28215
29912
  const n = store2.getNode(nodeId);
28216
29913
  if (!n || !n.attrs) return "unshown";
28217
- const shownSeq = n.attrs["lastShownAtSeq"];
28218
- if (shownSeq !== void 0 && shownSeq <= atSeq) return "shown";
28219
- const evictedSeq = n.attrs["lastEvictedAtSeq"];
28220
- if (evictedSeq !== void 0 && evictedSeq <= atSeq) return "evicted";
28221
- if ((n.attrs["evictedCount"] ?? 0) > 0) return "evicted";
29914
+ const a = n.attrs;
29915
+ const num2 = (k) => typeof a[k] === "number" ? a[k] : void 0;
29916
+ const since = num2("lastOutcomeAt");
29917
+ const outOfOrder = since !== void 0 && at.ts <= since;
29918
+ const lo = outOfOrder || since === void 0 ? -Infinity : since;
29919
+ const kinds = ["r", "c", "e"];
29920
+ const seen = { r: false, c: false, e: false };
29921
+ const maybe = { r: outOfOrder, c: outOfOrder, e: outOfOrder };
29922
+ for (const [t, kind] of exposureLog(a)) if (t > lo && t <= at.ts) seen[kind] = true;
29923
+ const logSince = num2("exposureLogSince");
29924
+ const trimmed = a["exposureTrimmed"] ?? {};
29925
+ if (logSince !== void 0 && lo < logSince) {
29926
+ for (const k of kinds) {
29927
+ const t = trimmed[k];
29928
+ if (typeof t !== "number" || t <= lo) continue;
29929
+ if (t <= at.ts) seen[k] = true;
29930
+ else maybe[k] = true;
29931
+ }
29932
+ }
29933
+ const firstShownAt = num2("firstShownAt");
29934
+ const firstEvictedAt = num2("firstEvictedAt");
29935
+ const legacyShowSeq = num2("firstShownAtSeq") ?? num2("lastShownAtSeq");
29936
+ const legacyShown = firstShownAt === 0 || firstShownAt === void 0 && legacyShowSeq !== void 0;
29937
+ const legacyEvicted = firstEvictedAt === 0 || firstEvictedAt === void 0 && (num2("lastEvictedAtSeq") !== void 0 || (num2("evictedCount") ?? 0) > 0);
29938
+ const logStart = num2("exposureLogStart");
29939
+ const beforeLog = logStart === void 0 || lo < logStart;
29940
+ if (beforeLog && legacyShown) maybe.r = true;
29941
+ if (beforeLog && legacyEvicted) maybe.e = true;
29942
+ const first = a["exposureFirst"] ?? {};
29943
+ const legacyBy = (seq) => logStart !== void 0 && at.ts >= logStart ? true : seq !== void 0 && seq <= at.seq;
29944
+ const happenedBy = {
29945
+ r: typeof first["r"] === "number" && first["r"] <= at.ts || legacyShown && legacyBy(legacyShowSeq),
29946
+ c: typeof first["c"] === "number" && first["c"] <= at.ts,
29947
+ e: typeof first["e"] === "number" && first["e"] <= at.ts || legacyEvicted && (legacyBy(num2("lastEvictedAtSeq")) || a["lastEvictedAtSeq"] === void 0 && (num2("evictedCount") ?? 0) > 0)
29948
+ };
29949
+ const present = (k) => seen[k] || maybe[k] && happenedBy[k];
29950
+ if (present("r")) return "shown";
29951
+ if (present("c")) return "recent";
29952
+ if (present("e")) return "evicted";
28222
29953
  return "unshown";
28223
29954
  }
29955
+ function passivelyShowable(n) {
29956
+ const quality = n.attrs["historyQuality"];
29957
+ const evaluatedAt = quality && typeof quality === "object" ? quality["evaluatedAtCommit"] : void 0;
29958
+ return historyReadPolicy(n, {
29959
+ mode: "passive",
29960
+ atCommit: typeof evaluatedAt === "string" ? evaluatedAt : void 0
29961
+ }).allow;
29962
+ }
29963
+ function exposureOutcomeAttrs(node, exposure, at) {
29964
+ const attrs = node.attrs;
29965
+ const field = `reinforce${exposure[0].toUpperCase()}${exposure.slice(1)}Count`;
29966
+ const prev = attrs["lastOutcomeAt"];
29967
+ const queryOnly = exposure === "unshown" && !passivelyShowable(node);
29968
+ return {
29969
+ [field]: (attrs[field] ?? 0) + 1,
29970
+ ...queryOnly ? { reinforceUnshownQueryOnlyCount: (attrs["reinforceUnshownQueryOnlyCount"] ?? 0) + 1 } : {},
29971
+ lastReinforceExposure: exposure,
29972
+ lastOutcomeAt: typeof prev === "number" ? Math.max(prev, at.ts) : at.ts
29973
+ };
29974
+ }
28224
29975
 
28225
29976
  // ../../packages/local-graph/src/intent.ts
28226
29977
  init_src();
@@ -28237,9 +29988,9 @@ var STATEMENT_PATH_RE = new RegExp(
28237
29988
  );
28238
29989
  function filePathResolver(store2) {
28239
29990
  const byPath = /* @__PURE__ */ new Map();
28240
- for (const f of store2.findNodesByLabel("File")) {
28241
- const path = String(f.attrs["relPath"] ?? f.description ?? "");
28242
- if (path) byPath.set(path, { id: f.id, path });
29991
+ for (const f of store2.selectNodes({ labels: ["File"], attrs: ["relPath"] })) {
29992
+ const path2 = String(f.attrs["relPath"] ?? f.description ?? "");
29993
+ if (path2) byPath.set(path2, { id: f.id, path: path2 });
28243
29994
  }
28244
29995
  return (named) => {
28245
29996
  const exact = byPath.get(named);
@@ -28283,7 +30034,7 @@ function repairLegacyAnchorsFromStatement(store2, ts) {
28283
30034
  alreadyCorrect: 0
28284
30035
  };
28285
30036
  const resolvePath = filePathResolver(store2);
28286
- for (const p of store2.findNodesByLabel("Problem")) {
30037
+ for (const p of store2.selectNodes({ labels: ["Problem"] })) {
28287
30038
  try {
28288
30039
  const anchors = store2.outEdges(p.id, ["ANCHORED_AT"]);
28289
30040
  const legacy = anchors.filter((e) => e.attrs?.["anchorProvenance"] === "legacy");
@@ -28347,10 +30098,12 @@ function backfillLegacyAnchors(store2, ts) {
28347
30098
  suspects: []
28348
30099
  };
28349
30100
  let resolvePath;
28350
- for (const p of store2.findNodesByLabel("Problem")) {
28351
- const resolved = p.attrs["resolvedAt"] !== void 0;
28352
- const legacy = store2.outEdges(p.id, ["ANCHORED_AT"]).filter((e) => isLegacyAnchor(e.attrs) || !resolved && e.attrs?.["anchorProvenance"] === "legacy");
30101
+ for (const row of store2.selectNodes({ labels: ["Problem"], attrs: ["resolvedAt"] })) {
30102
+ const resolved = row.attrs["resolvedAt"] !== void 0;
30103
+ const legacy = store2.outEdges(row.id, ["ANCHORED_AT"]).filter((e) => isLegacyAnchor(e.attrs) || !resolved && e.attrs?.["anchorProvenance"] === "legacy");
28353
30104
  if (legacy.length === 0) continue;
30105
+ const p = store2.getNode(row.id);
30106
+ if (!p) continue;
28354
30107
  try {
28355
30108
  if (!resolved) {
28356
30109
  resolvePath ??= filePathResolver(store2);
@@ -28365,8 +30118,8 @@ function backfillLegacyAnchors(store2, ts) {
28365
30118
  const retired = legacy.filter((e) => !(target && e.to === target.id));
28366
30119
  for (const e of retired) {
28367
30120
  const file2 = store2.getNode(e.to);
28368
- const path = String(file2?.attrs["relPath"] ?? file2?.description ?? "");
28369
- if (path) recordAnchorHint(store2, p.id, path, "legacy", ts);
30121
+ const path2 = String(file2?.attrs["relPath"] ?? file2?.description ?? "");
30122
+ if (path2) recordAnchorHint(store2, p.id, path2, "legacy", ts);
28370
30123
  store2.closeEdge(e.id, ts);
28371
30124
  report.demotedEdges++;
28372
30125
  }
@@ -28491,7 +30244,7 @@ function detectLocalCommunities(store2, opts = {}) {
28491
30244
  for (const n of unowned) {
28492
30245
  const pulled = n.attrs["source"] === "cloud";
28493
30246
  const clearColumn = !!n.community && !pulled;
28494
- if (n.attrs["localCommunity"] === void 0 && !clearColumn) continue;
30247
+ if (n.attrs["localCommunity"] == null && !clearColumn) continue;
28495
30248
  store2.setLocalCommunity(n.id, null, clearColumn);
28496
30249
  if (clearColumn) report.cleared++;
28497
30250
  }
@@ -28559,13 +30312,13 @@ function detectLocalCommunities(store2, opts = {}) {
28559
30312
  // ../../packages/local-graph/src/tools.ts
28560
30313
  init_src();
28561
30314
  function rankToolsForHandles(store2, limit = 5) {
28562
- const scored = store2.findNodesByLabel("Tool").map((node) => ({
28563
- node,
28564
- concerns: store2.inEdges(node.id, ["CONCERNS"]).length,
28565
- hits: node.cumulativeHits ?? 0
30315
+ const scored = store2.selectNodes({ labels: ["Tool"] }).map((row) => ({
30316
+ id: row.id,
30317
+ concerns: store2.inEdges(row.id, ["CONCERNS"]).length,
30318
+ hits: row.cumulativeHits ?? 0
28566
30319
  }));
28567
30320
  scored.sort((a, b) => b.concerns - a.concerns || b.hits - a.hits);
28568
- return scored.slice(0, Math.max(0, limit)).map((s) => s.node);
30321
+ return scored.slice(0, Math.max(0, limit)).map((s) => store2.getNode(s.id)).filter((n) => n !== null);
28569
30322
  }
28570
30323
 
28571
30324
  // ../../packages/local-graph/src/principle-sync.ts
@@ -28621,6 +30374,7 @@ var MECHANISMS = [
28621
30374
  },
28622
30375
  {
28623
30376
  id: "fix-candidate-ask",
30377
+ requiresNodes: ["Problem"],
28624
30378
  what: "asks an agent whether an edit to a problem's anchor fixed it",
28625
30379
  pass: "semantic-maintenance",
28626
30380
  // markFixCandidates fails CLOSED on a File anchor with no contentChangedAt —
@@ -28672,7 +30426,12 @@ var MECHANISMS = [
28672
30426
  // the producer was verifiably stamping every new node.
28673
30427
  minFraction: 0.9,
28674
30428
  recent: 200,
28675
- sinceFirstStamp: true
30429
+ sinceFirstStamp: true,
30430
+ // The anchor-feed pull lands cloud mirrors by the hundreds every ten
30431
+ // minutes (createdAt = pull time, no local seq — stamping them would age
30432
+ // every local node by Δseq). On 2026-10-09 1,146 mirrors in a few hours
30433
+ // dragged this to 62% and toasted "ingest-sequence DEAD" with effect 41.
30434
+ localOnly: true
28676
30435
  },
28677
30436
  effectCounter: "seqAdvanced",
28678
30437
  note: "column, not attr; measured over nodes born since the first stamp in the recent window"
@@ -28710,6 +30469,28 @@ var MECHANISMS = [
28710
30469
  // climbs while `accepted` stays flat is the shape of a silently-closed door.
28711
30470
  backlogCounter: "candidates"
28712
30471
  },
30472
+ {
30473
+ id: "edge-park-replay",
30474
+ what: "parks causal/anchor edges the door refused as unresolvable, replays them when due, drops them with a disposition",
30475
+ pass: "ship",
30476
+ // FED = a source whose whole binding-edge family LANDED: the digest is
30477
+ // stamped only when every edge in it came back created/reinforced, so it is
30478
+ // the store-side proof that edges (not just nodes) cross. Live dev
30479
+ // 2026-10-12 sat with the same 241 refusals re-sent every drain and this
30480
+ // stamp frozen — nodes crossed, their causal wiring did not.
30481
+ fed: {
30482
+ labels: ["Problem", "RootCause"],
30483
+ attr: "semanticEdgesContributedDigest",
30484
+ minFraction: 0.01
30485
+ },
30486
+ // A parked edge that later LANDED — the replay doing its job.
30487
+ effectCounter: "edgesReplayLanded",
30488
+ // Outstanding parked edges (a level). Flat-and-nonzero while replays keep
30489
+ // re-parking is an endpoint that never resolves; it drains to tombstones
30490
+ // (`edgesDroppedExhausted`) instead of being resent forever.
30491
+ backlogCounter: "edgeParkSize",
30492
+ note: "edge-park.ts; quiet (no-effect) is healthy when nothing is refused \u2014 read edgesParked/edgesDropped* on the ship row"
30493
+ },
28713
30494
  {
28714
30495
  id: "orphan-reap",
28715
30496
  what: "closes File nodes whose path the indexer no longer covers",
@@ -28764,12 +30545,31 @@ var MECHANISMS = [
28764
30545
  // the bar is "the field is written at all", the revisit-sweep precedent.
28765
30546
  fed: { labels: ["Problem"], attr: "foldCandidate", minFraction: 0 },
28766
30547
  effectCounter: "folded",
28767
- // Standing nominations ARE the judge-less backlog — without the gauge a
28768
- // deployment with no judge configured reads as "nothing to fold".
28769
- backlogCounter: "standing",
30548
+ // The open-nomination POOL is the backlog. It used to be `standing`, which
30549
+ // only counts what the pass examined — capped at the per-run limit — so it
30550
+ // read a flat 8 for weeks while 824 nominations sat open (2026-10-12): the
30551
+ // gauge could not see past the slice it was meant to be measuring.
30552
+ backlogCounter: "pending",
28770
30553
  configCounter: "judgeConfigured",
28771
30554
  note: "the ambiguous band needs the opt-in judge: set ERRATA_FOLD_JUDGE=1 + a configured chat provider (azure env), or leave it off and the nominations stand"
28772
30555
  },
30556
+ {
30557
+ id: "fold-candidate-coverage",
30558
+ what: "rotates the fold-judge pass through every open nomination (never-examined first, standing ones re-examined on new evidence)",
30559
+ // Judge-INDEPENDENT on purpose — no configCounter. The embedding-certain
30560
+ // bands fold/reject with no judge at all, and the defect this watches is
30561
+ // the pass re-reading the same oldest 8 forever (101 runs, 8 distinct
30562
+ // nodes, 816 of 824 nominations never looked at). That starves those
30563
+ // bands on a judge-less daemon exactly as much as on a judged one, so an
30564
+ // opt-in being off must not excuse it.
30565
+ pass: "fold-judge",
30566
+ fed: { labels: ["Problem"], attr: "foldCandidate", minFraction: 0 },
30567
+ effectCounter: "firstExamined",
30568
+ // A LEVEL: open nominations never examined. Flat-and-positive with no
30569
+ // first examinations across the stall window = the rotation is stuck.
30570
+ backlogCounter: "neverExamined",
30571
+ note: "neverExamined must drain while the pass runs; flat means the selection is re-reading the same slice"
30572
+ },
28773
30573
  {
28774
30574
  id: "cite-anchor-accrual",
28775
30575
  what: "accrues cite-context anchor evidence on anchorless cited priors; two distinct sessions promote a cite-confirmed ANCHORED_AT",
@@ -28817,6 +30617,7 @@ var MECHANISMS = [
28817
30617
  },
28818
30618
  {
28819
30619
  id: "liveness-watch",
30620
+ inputOptional: true,
28820
30621
  what: "the daemon-side schedule of this very verdict \u2014 alarms when a mechanism stops working",
28821
30622
  // The watcher is itself a row: a probe that only runs when a human remembers
28822
30623
  // is how the original six defects shipped, and a scheduled watch that
@@ -28831,12 +30632,46 @@ var MECHANISMS = [
28831
30632
  // reading is IDLE — correct, and it declares no backlog on purpose.
28832
30633
  effectCounter: "alarms",
28833
30634
  note: "steady-state IDLE is healthy; the row exists for its invocation age"
30635
+ },
30636
+ {
30637
+ id: "project-causal-sync",
30638
+ what: "lands the cloud project stratum's SOLVED_BY/FIXED_BY edges onto the knowledge the anchor feed mirrors",
30639
+ // PRODUCER: the anchor feed's causal leg — `fetchProjectAnchors` returns the
30640
+ // edges, `syncProjectAnchors` (apps/daemon/src/project-reanchor.ts) lands or
30641
+ // parks them, on the `anchor-pull` beat. CONSUMERS: every local walk that
30642
+ // crosses Problem→Solution — errata_trace/why/burst over the store, and the
30643
+ // passive priming block that renders a problem with its fix. Before
30644
+ // PJ-sync-causal the feed mirrored 5,054 cloud Solutions on the dev checkout
30645
+ // with not one incoming SOLVED_BY: this row would have read 0.0% for months.
30646
+ pass: "anchor-pull",
30647
+ fedIncoming: { label: "Solution", edgeTypes: ["SOLVED_BY", "FIXED_BY"], cloudOnly: true, minFraction: 0.5 },
30648
+ effectCounter: "edgesLanded",
30649
+ // Parked edges waiting on an endpoint — a flat, non-zero backlog is a stratum
30650
+ // whose other ends never arrive here (a cap, or a gate that refuses them).
30651
+ backlogCounter: "edgesPending",
30652
+ requiresNodes: ["Problem"],
30653
+ note: "an orphaned cloud Solution reads as a fix with no problem; the one-time causal re-walk lifts this after the server ships the leg"
28834
30654
  }
28835
30655
  ];
28836
30656
  var COLUMN_INPUTS = {
28837
30657
  __createdAtSeq: (n) => n.createdAtSeq !== void 0 && n.createdAtSeq !== null
28838
30658
  };
28839
- function evaluateFed(store2, d) {
30659
+ function evaluateFed(store2, d, stamps) {
30660
+ const incomingRows = d.fedIncoming && store2.liveEdgeTargets ? stamps?.(d.fedIncoming.label, "source") : void 0;
30661
+ if (d.fedIncoming && incomingRows) {
30662
+ const targets = new Set(store2.liveEdgeTargets(d.fedIncoming.edgeTypes));
30663
+ const rows = d.fedIncoming.cloudOnly ? incomingRows.filter((r) => r.cloud) : incomingRows;
30664
+ const count2 = rows.filter((r) => targets.has(r.id)).length;
30665
+ return { count: count2, total: rows.length, fraction: rows.length === 0 ? 0 : count2 / rows.length };
30666
+ }
30667
+ if (d.fedIncoming) {
30668
+ const { count: count2, total } = store2.incomingEdgeCoverage?.(
30669
+ d.fedIncoming.label,
30670
+ d.fedIncoming.edgeTypes,
30671
+ d.fedIncoming.cloudOnly
30672
+ ) ?? { count: 0, total: 0 };
30673
+ return { count: count2, total, fraction: total === 0 ? 0 : count2 / total };
30674
+ }
28840
30675
  if (d.fedEdges) {
28841
30676
  const { count: count2, total } = store2.recentEdgeAttrCoverage(
28842
30677
  d.fedEdges.marker,
@@ -28846,10 +30681,12 @@ function evaluateFed(store2, d) {
28846
30681
  return { count: count2, total, fraction: total === 0 ? 0 : count2 / total };
28847
30682
  }
28848
30683
  if (!d.fed) return { count: 0, total: 0, fraction: 0 };
28849
- const column = COLUMN_INPUTS[d.fed.attr];
30684
+ const column2 = COLUMN_INPUTS[d.fed.attr];
28850
30685
  const fed = d.fed;
28851
- const nodes = fed.labels.flatMap((label) => store2.findNodeStampsByLabel ? store2.findNodeStampsByLabel(label, fed.attr) : store2.findNodeAttrsByLabel(label));
28852
- const has = (n) => column ? column(n) : n.has ?? n.attrs?.[fed.attr] !== void 0;
30686
+ const all = fed.labels.flatMap((label) => stamps?.(label, fed.attr) ?? (store2.findNodeStampsByLabel ? store2.findNodeStampsByLabel(label, fed.attr) : store2.findNodeAttrsByLabel(label)));
30687
+ const isCloudMirror = (n) => n.cloud ?? n.attrs?.["source"] === "cloud";
30688
+ const nodes = fed.localOnly ? all.filter((n) => !isCloudMirror(n)) : all;
30689
+ const has = (n) => column2 ? column2(n) : n.has ?? n.attrs?.[fed.attr] !== void 0;
28853
30690
  let window2 = nodes;
28854
30691
  if (fed.recent !== void 0) {
28855
30692
  window2 = [...nodes].sort((a, b) => b.createdAt - a.createdAt).slice(0, fed.recent);
@@ -28864,8 +30701,21 @@ function evaluateFed(store2, d) {
28864
30701
  return { count, total: window2.length, fraction: window2.length === 0 ? 0 : count / window2.length };
28865
30702
  }
28866
30703
  function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mechanisms = MECHANISMS) {
30704
+ const counts = /* @__PURE__ */ new Map();
30705
+ const count = (label) => {
30706
+ if (!counts.has(label)) counts.set(label, store2.countNodesByLabel(label));
30707
+ return counts.get(label);
30708
+ };
30709
+ const wanted = /* @__PURE__ */ new Map();
30710
+ for (const d of mechanisms) for (const l of d.fed?.labels ?? []) wanted.set(l, (wanted.get(l) ?? /* @__PURE__ */ new Set()).add(d.fed.attr));
30711
+ for (const d of mechanisms) if (d.fedIncoming) wanted.set(d.fedIncoming.label, (wanted.get(d.fedIncoming.label) ?? /* @__PURE__ */ new Set()).add("source"));
30712
+ const byLabel = /* @__PURE__ */ new Map();
30713
+ const stamps = store2.findNodeStampsByLabelAttrs ? (label, attr) => {
30714
+ if (!byLabel.has(label)) byLabel.set(label, store2.findNodeStampsByLabelAttrs(label, [...wanted.get(label) ?? [attr]]));
30715
+ return byLabel.get(label).get(attr);
30716
+ } : void 0;
28867
30717
  return mechanisms.map((d) => {
28868
- const fed = evaluateFed(store2, d);
30718
+ const fed = evaluateFed(store2, d, stamps);
28869
30719
  const inv = invocations.get(d.pass);
28870
30720
  const effectCount = d.effectIsLevel ? Math.max(
28871
30721
  0,
@@ -28876,9 +30726,12 @@ function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mec
28876
30726
  const span = inv?.firstTs === void 0 ? 0 : inv.lastTs - inv.firstTs;
28877
30727
  const stalled = backlog !== void 0 && backlog > 0 && effectCount === 0 && (inv?.runs ?? 0) >= STALL_MIN_RUNS && span >= STALL_MIN_SPAN_MS && (backlogWas === void 0 || backlog >= backlogWas);
28878
30728
  let verdict;
28879
- if (!inv || inv.runs === 0) verdict = "never-invoked";
28880
- else if (d.configCounter && inv.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
28881
- else if (fed.fraction < (d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0)) verdict = "starved";
30729
+ const hasInput = fed.total > 0 || Boolean(d.fed?.sinceFirstStamp && d.fed.labels.some((label) => count(label) > 0));
30730
+ const missingRequiredNodes = d.requiresNodes?.some((label) => count(label) === 0) ?? false;
30731
+ if (d.configCounter && inv?.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
30732
+ else if ((backlog ?? 0) === 0 && (!hasInput && !d.inputOptional || missingRequiredNodes)) verdict = "no-input";
30733
+ else if (!inv || inv.runs === 0) verdict = "never-invoked";
30734
+ else if (fed.fraction < minFractionOf(d)) verdict = "starved";
28882
30735
  else if (stalled) verdict = "stalled";
28883
30736
  else if (effectCount === 0) verdict = "no-effect";
28884
30737
  else verdict = "ok";
@@ -28889,7 +30742,7 @@ function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mec
28889
30742
  fedCount: fed.count,
28890
30743
  fedTotal: fed.total,
28891
30744
  fedFraction: fed.fraction,
28892
- minFraction: d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0,
30745
+ minFraction: minFractionOf(d),
28893
30746
  ...inv ? { lastInvokedMs: inv.lastTs } : {},
28894
30747
  runs: inv?.runs ?? 0,
28895
30748
  effectCount,
@@ -28901,57 +30754,8 @@ function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mec
28901
30754
  };
28902
30755
  });
28903
30756
  }
28904
-
28905
- // ../../packages/local-graph/src/wm-calibration.ts
28906
- var WM_CALIBRATION_LABELS = [
28907
- "Problem",
28908
- "Solution",
28909
- "RootCause",
28910
- "Pattern",
28911
- "Technique",
28912
- "AntiPattern"
28913
- ];
28914
- var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
28915
- var WM_CALIBRATION_KEYS = [
28916
- "shownCount",
28917
- "evictedCount",
28918
- "reinforceShownCount",
28919
- "reinforceEvictedCount",
28920
- "reinforceUnshownCount"
28921
- ];
28922
- function wmCalibrationCells(store2) {
28923
- const cells = {
28924
- shownNodes: 0,
28925
- shownImpressions: 0,
28926
- evictedNodes: 0,
28927
- evictedImpressions: 0,
28928
- reinforceShown: 0,
28929
- reinforceEvicted: 0,
28930
- reinforceUnshown: 0,
28931
- reinforcedNodes: 0
28932
- };
28933
- for (const label of WM_CALIBRATION_LABELS) {
28934
- for (const n of store2.findNodeFieldsByLabel(label, WM_CALIBRATION_KEYS)) {
28935
- const shown = num(n.attrs["shownCount"]);
28936
- const evicted = num(n.attrs["evictedCount"]);
28937
- if (shown > 0) {
28938
- cells.shownNodes++;
28939
- cells.shownImpressions += shown;
28940
- }
28941
- if (evicted > 0) {
28942
- cells.evictedNodes++;
28943
- cells.evictedImpressions += evicted;
28944
- }
28945
- const rs = num(n.attrs["reinforceShownCount"]);
28946
- const re = num(n.attrs["reinforceEvictedCount"]);
28947
- const ru = num(n.attrs["reinforceUnshownCount"]);
28948
- cells.reinforceShown += rs;
28949
- cells.reinforceEvicted += re;
28950
- cells.reinforceUnshown += ru;
28951
- if (rs + re + ru > 0) cells.reinforcedNodes++;
28952
- }
28953
- }
28954
- return cells;
30757
+ function minFractionOf(d) {
30758
+ return d.fedIncoming?.minFraction ?? d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0;
28955
30759
  }
28956
30760
 
28957
30761
  // ../../packages/generalizer/src/generalizer.ts
@@ -29036,14 +30840,12 @@ function promoteMotifs(store2, t) {
29036
30840
  }
29037
30841
  report.communities = byCommunity.size;
29038
30842
  const existing = /* @__PURE__ */ new Map();
29039
- for (const label of MOTIF_LABELS) {
29040
- for (const node of store2.findNodesByLabel(label)) {
29041
- if (!node.id.startsWith("motif_")) continue;
29042
- const edges = store2.inEdges(node.id, ["INSTANCE_OF"]).filter(isDerived);
29043
- const remembered = node.attrs["memberIds"];
29044
- const members = new Set(Array.isArray(remembered) ? remembered : edges.map((e) => e.from));
29045
- existing.set(node.id, { node, edges, members });
29046
- }
30843
+ for (const row of store2.selectNodes({ labels: MOTIF_LABELS, where: [{ idPrefix: "motif_" }] })) {
30844
+ const node = store2.getNode(row.id);
30845
+ const edges = store2.inEdges(node.id, ["INSTANCE_OF"]).filter(isDerived);
30846
+ const remembered = node.attrs["memberIds"];
30847
+ const members = new Set(Array.isArray(remembered) ? remembered : edges.map((e) => e.from));
30848
+ existing.set(node.id, { node, edges, members });
29047
30849
  }
29048
30850
  const pairs = [];
29049
30851
  for (const [cid, members] of byCommunity) {
@@ -29484,24 +31286,129 @@ var AGENTS_POINTER_BODY = [
29484
31286
  // ../../packages/context-writer/src/render.ts
29485
31287
  init_src2();
29486
31288
  init_src();
31289
+
31290
+ // ../../packages/context-writer/src/snapshot-inputs.ts
31291
+ var SNAPSHOT_NODE_LABELS = [
31292
+ "Problem",
31293
+ "Vulnerability",
31294
+ "Solution",
31295
+ "Pattern",
31296
+ "Technique",
31297
+ "AntiPattern",
31298
+ "Language",
31299
+ "Package",
31300
+ "Tool"
31301
+ ];
31302
+ var SNAPSHOT_EDGE_TYPES = [
31303
+ "ANCHORED_AT",
31304
+ "CAUSED_BY",
31305
+ "CONCERNS",
31306
+ "DEPENDS_ON",
31307
+ "EVIDENCED_BY",
31308
+ "MANIFESTED_IN",
31309
+ "OCCURS_IN",
31310
+ "PERTAIN_TO",
31311
+ "REGRESSION_OF",
31312
+ "SOLVED_BY"
31313
+ ];
31314
+ var SNAPSHOT_READ_GUARD = typeof process !== "undefined" && Boolean(process.env["VITEST"]);
31315
+ var LABELS = new Set(SNAPSHOT_NODE_LABELS);
31316
+ var EDGES = new Set(SNAPSHOT_EDGE_TYPES);
31317
+ function guardSnapshotReads(store2) {
31318
+ const fail = (what) => {
31319
+ throw new Error(`buildSnapshot read ${what}, outside SNAPSHOT_NODE_LABELS/SNAPSHOT_EDGE_TYPES (snapshot-inputs.ts)`);
31320
+ };
31321
+ const label = (l, via) => {
31322
+ if (typeof l === "string" && !LABELS.has(l)) fail(`label ${l} via ${via}`);
31323
+ };
31324
+ const types = (t, via) => {
31325
+ if (!Array.isArray(t) || t.length === 0) fail(`every edge type via ${via}`);
31326
+ for (const x of t) if (!EDGES.has(String(x))) fail(`edge type ${String(x)} via ${via}`);
31327
+ };
31328
+ const nodes = (r, via) => {
31329
+ for (const n of Array.isArray(r) ? r : r ? [r] : []) label(n.label, via);
31330
+ return r;
31331
+ };
31332
+ const allowed = {
31333
+ getNode: (id) => nodes(store2.getNode(id), "getNode"),
31334
+ selectNodes: (q) => {
31335
+ for (const l of q.labels) label(l, "selectNodes");
31336
+ return store2.selectNodes(q);
31337
+ },
31338
+ countNodes: (q) => {
31339
+ for (const l of q.labels) label(l, "countNodes");
31340
+ return store2.countNodes(q);
31341
+ },
31342
+ findLiveNodesByAttr: (l, ...rest) => {
31343
+ label(l, "findLiveNodesByAttr");
31344
+ return store2.findLiveNodesByAttr(l, ...rest);
31345
+ },
31346
+ outEdges: (id, t) => {
31347
+ types(t, "outEdges");
31348
+ return store2.outEdges(id, t);
31349
+ },
31350
+ inEdges: (id, t) => {
31351
+ types(t, "inEdges");
31352
+ return store2.inEdges(id, t);
31353
+ },
31354
+ inDegreeByType: (t) => {
31355
+ types(t, "inDegreeByType");
31356
+ return store2.inDegreeByType(t);
31357
+ },
31358
+ nodesAsOfWhereTrue: (asOf, attr) => {
31359
+ if (attr !== "revisit") fail(`nodesAsOfWhereTrue(${String(attr)})`);
31360
+ return store2.nodesAsOfWhereTrue(asOf, attr);
31361
+ }
31362
+ };
31363
+ return new Proxy(store2, {
31364
+ get(target, prop) {
31365
+ if (typeof prop === "string" && prop in allowed) return allowed[prop];
31366
+ const v = Reflect.get(target, prop, target);
31367
+ if (typeof v === "function") return () => fail(`store.${String(prop)}()`);
31368
+ return v;
31369
+ }
31370
+ });
31371
+ }
31372
+
31373
+ // ../../packages/context-writer/src/render.ts
29487
31374
  var MOTIF_BAND = 10;
29488
31375
  var MOTIF_POOL = 1e3;
29489
31376
  function rankMotifs(pool, signal, k = MOTIF_BAND) {
29490
31377
  if (!signal) return pool.slice(0, k);
29491
31378
  return pool.filter((m) => (signal.get(m.id) ?? 0) > 0).sort((a, b) => signal.get(b.id) - signal.get(a.id) || b.pageRank - a.pageRank).slice(0, k);
29492
31379
  }
31380
+ var HISTORY_POLICY_ATTRS = ["source", "extractionSource", "historyQuality", "validationSource", "attrsJson"];
31381
+ function passiveAllowed(row, atCommit) {
31382
+ return historyReadPolicy({ extractionSource: row.extractionSource, attrs: row.attrs }, { mode: "passive", atCommit }).allow;
31383
+ }
31384
+ var PROBLEM_BAND_ATTRS = [
31385
+ "mergedInto",
31386
+ "resolvedAt",
31387
+ "resolvedAs",
31388
+ "kind",
31389
+ "shownSinceTouch",
31390
+ "shownSinceTouchAt",
31391
+ ...HISTORY_POLICY_ATTRS
31392
+ ];
29493
31393
  function buildSnapshot(opts) {
29494
- const problems = [...opts.store.findNodesByLabel("Problem"), ...opts.store.findNodesByLabel("Vulnerability")].filter((p) => p.attrs["mergedInto"] === void 0 && historyReadPolicy(p, { mode: "passive", atCommit: opts.atCommit }).allow);
31394
+ const codeStore = opts.store;
31395
+ if (SNAPSHOT_READ_GUARD) opts = { ...opts, store: guardSnapshotReads(opts.store) };
31396
+ const hydrate = (id) => opts.store.getNode(id);
31397
+ const problems = opts.store.selectNodes({ labels: ["Problem", "Vulnerability"], attrs: PROBLEM_BAND_ATTRS }).filter((p) => p.attrs["mergedInto"] === void 0 && passiveAllowed(p, opts.atCommit));
29495
31398
  const stillOpen = problems.filter((p) => p.attrs["resolvedAt"] == null);
29496
31399
  const allProblems = rankRecentBand(stillOpen.filter((p) => !isConstraintProblem(p)));
29497
- const openPool = allProblems.slice(0, RECENT_OPEN * SCOPE_POOL_FACTOR).map((p) => ({
29498
- node: p,
31400
+ const openPool = allProblems.slice(0, Math.max(RECENT_OPEN * SCOPE_POOL_FACTOR, RECENT_WINDOW_BANDS * RECENT_OPEN)).map((p) => ({
31401
+ node: hydrate(p.id),
29499
31402
  anchors: opts.store.outEdges(p.id, ["MANIFESTED_IN", "EVIDENCED_BY"])
29500
31403
  }));
29501
31404
  const recent = openPool.slice(0, RECENT_OPEN);
29502
- const constraintPool = rankRecentBand(stillOpen.filter((p) => isConstraintProblem(p)), { window: RECENT_WINDOW_BANDS * RECENT_CONSTRAINTS }).slice(0, RECENT_CONSTRAINTS * SCOPE_POOL_FACTOR);
31405
+ const constraintPool = rankRecentBand(stillOpen.filter((p) => isConstraintProblem(p)), { window: RECENT_WINDOW_BANDS * RECENT_CONSTRAINTS }).slice(0, Math.max(RECENT_CONSTRAINTS * SCOPE_POOL_FACTOR, RECENT_WINDOW_BANDS * RECENT_CONSTRAINTS)).map((p) => hydrate(p.id));
29503
31406
  const recentConstraints = constraintPool.slice(0, RECENT_CONSTRAINTS);
29504
- const regressions = problems.filter((p) => p.attrs["resolvedAt"] == null && p.attrs["mergedInto"] === void 0).flatMap(
31407
+ const regressionSources = /* @__PURE__ */ new Set();
31408
+ for (const target of opts.store.inDegreeByType(["REGRESSION_OF"]).keys()) {
31409
+ for (const e of opts.store.inEdges(target, ["REGRESSION_OF"])) regressionSources.add(e.from);
31410
+ }
31411
+ const regressions = problems.filter((p) => p.attrs["resolvedAt"] == null && p.attrs["mergedInto"] === void 0 && regressionSources.has(p.id)).map((p) => hydrate(p.id)).flatMap(
29505
31412
  (open) => opts.store.outEdges(open.id, ["REGRESSION_OF"]).flatMap((e) => {
29506
31413
  const closed = opts.store.getNode(e.to);
29507
31414
  if (!closed || closed.attrs["resolutionSuspect"] !== true || closed.attrs["resolvedAt"] == null) {
@@ -29516,18 +31423,14 @@ function buildSnapshot(opts) {
29516
31423
  const resolvedPool = problems.filter((p) => p.attrs["resolvedAt"] != null && p.attrs["resolvedAs"] == null).filter((p) => !regressionClosedIds.has(p.id)).sort((a, b) => Number(b.attrs["resolvedAt"] ?? 0) - Number(a.attrs["resolvedAt"] ?? 0)).slice(0, RECENT_RESOLVED * SCOPE_POOL_FACTOR).map((p) => {
29517
31424
  const solEdge = opts.store.outEdges(p.id, ["SOLVED_BY"])[0];
29518
31425
  const solution = solEdge ? opts.store.getNode(solEdge.to) ?? void 0 : void 0;
29519
- return { node: p, ...solution ? { solution } : {} };
31426
+ return { node: hydrate(p.id), ...solution ? { solution } : {} };
29520
31427
  });
29521
31428
  const recentResolved = resolvedPool.slice(0, RECENT_RESOLVED);
29522
- const motifPool = [
29523
- ...opts.store.findNodesByLabel("Pattern"),
29524
- ...opts.store.findNodesByLabel("Technique"),
29525
- ...opts.store.findNodesByLabel("AntiPattern")
29526
- ].filter((n) => historyReadPolicy(n, { mode: "passive", atCommit: opts.atCommit }).allow).filter((n) => !(Number(n.attrs["missedRuns"] ?? 0) > 0)).sort((a, b) => b.pageRank - a.pageRank).slice(0, MOTIF_POOL).map((n) => n.embedding.length > 0 ? { ...n, embedding: [] } : n);
31429
+ const motifPool = opts.store.selectNodes({ labels: ["Pattern", "Technique", "AntiPattern"], attrs: ["missedRuns", ...HISTORY_POLICY_ATTRS] }).filter((n) => passiveAllowed(n, opts.atCommit)).filter((n) => !(Number(n.attrs["missedRuns"] ?? 0) > 0)).sort((a, b) => b.pageRank - a.pageRank).slice(0, MOTIF_POOL).map((r) => hydrate(r.id)).map((n) => n.embedding.length > 0 ? { ...n, embedding: [] } : n);
29527
31430
  const motifs = rankMotifs(motifPool, void 0);
29528
- const workingFile = opts.workingFile ? sliceForFile(opts.store, opts.workingFile, opts.atCommit) : void 0;
31431
+ const workingFile = opts.workingFile ? sliceForFile(codeStore, opts.workingFile, opts.atCommit) : void 0;
29529
31432
  const byEpisode = /* @__PURE__ */ new Map();
29530
- for (const sol of opts.store.findNodesByLabel("Solution")) {
31433
+ for (const sol of opts.store.findLiveNodesByAttr("Solution", "enrichmentPending", 1)) {
29531
31434
  if (!historyReadPolicy(sol, { mode: "passive", atCommit: opts.atCommit }).allow) continue;
29532
31435
  if (sol.attrs["enrichmentPending"] !== true) continue;
29533
31436
  const ep = sol.attrs["episodeId"] ?? sol.id;
@@ -29558,13 +31461,14 @@ function buildSnapshot(opts) {
29558
31461
  const matchNode = (cands, key) => {
29559
31462
  const k = norm(key);
29560
31463
  if (k.length < 2) return null;
29561
- return cands.find((n) => norm(n.description ?? "") === k) ?? cands.find((n) => {
31464
+ const hit = cands.find((n) => norm(n.description ?? "") === k) ?? cands.find((n) => {
29562
31465
  const d = norm(n.description ?? "");
29563
31466
  return d.length >= 2 && (d.includes(k) || k.includes(d));
29564
- }) ?? null;
31467
+ });
31468
+ return hit ? hydrate(hit.id) : null;
29565
31469
  };
29566
- const langNodes = opts.store.findNodesByLabel("Language");
29567
- const pkgNodes = opts.store.findNodesByLabel("Package");
31470
+ const langNodes = opts.store.selectNodes({ labels: ["Language"] });
31471
+ const pkgNodes = opts.store.selectNodes({ labels: ["Package"] });
29568
31472
  const toolNodes = rankToolsForHandles(opts.store, 5);
29569
31473
  const profileContext = {
29570
31474
  languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
@@ -29615,8 +31519,8 @@ var RECENT_RESOLVED = 4;
29615
31519
  var RECENT_CONSTRAINTS = 3;
29616
31520
  var SCOPE_POOL_FACTOR = 3;
29617
31521
  function sliceForFile(store2, relPath, atCommit) {
29618
- const candidates = store2.findNodesByLabel("File");
29619
- const file2 = candidates.find((n) => n.description === relPath);
31522
+ const hit = store2.selectNodes({ labels: ["File"], where: [{ descriptionIn: [relPath] }], limit: 1 })[0];
31523
+ const file2 = hit ? store2.getNode(hit.id) : null;
29620
31524
  if (!file2) return void 0;
29621
31525
  const symbols = [];
29622
31526
  for (const e of store2.outEdges(file2.id, ["DEFINES"])) {
@@ -29794,11 +31698,20 @@ function listSourceFiles(root) {
29794
31698
  return gitSourceFiles(root) ?? walkSource(root);
29795
31699
  }
29796
31700
  var SCAN_YIELD_EVERY = 100;
29797
- async function findStaleFiles(store2, rootPath, workspaceId) {
31701
+ async function findStaleFiles(store2, rootPath, workspaceId, lineageVerifiedAt) {
29798
31702
  const stale = [];
31703
+ const changed = lineageVerifiedAt !== void 0 && store2.fileRowStates ? store2.lineageChangedFiles?.(lineageVerifiedAt) : null;
31704
+ const relineage = changed ? new Set(changed) : null;
29799
31705
  let pending = [];
29800
31706
  const check2 = () => {
29801
- const states = new Map(store2.fileIndexStates(pending.map((f) => f.id)).map((s) => [s.id, s]));
31707
+ const full = relineage ? pending.filter((f) => relineage.has(f.id)) : pending;
31708
+ const states = new Map(
31709
+ store2.fileIndexStates(full.map((f) => f.id)).map((s) => [s.id, s])
31710
+ );
31711
+ if (relineage) {
31712
+ const rowOnly = pending.filter((f) => !relineage.has(f.id)).map((f) => f.id);
31713
+ for (const s of store2.fileRowStates(rowOnly)) states.set(s.id, { ...s, complete: true });
31714
+ }
29802
31715
  for (const f of pending) {
29803
31716
  const state = states.get(f.id);
29804
31717
  if (!state || state.validTo !== null || state.lastUpdatedAt < f.mtimeMs || !state.complete) stale.push(f.abs);
@@ -29820,9 +31733,34 @@ async function findStaleFiles(store2, rootPath, workspaceId) {
29820
31733
  check2();
29821
31734
  return stale;
29822
31735
  }
31736
+ var FILE_DECLARATION_LABELS = [
31737
+ "Function",
31738
+ "Class",
31739
+ "Method",
31740
+ "Module",
31741
+ "Interface",
31742
+ "Const",
31743
+ "Static",
31744
+ "Property",
31745
+ "TypeAlias",
31746
+ "Namespace",
31747
+ "Enum",
31748
+ "Annotation",
31749
+ "Comment"
31750
+ ];
31751
+ var DECLARATION_LABEL_SET = new Set(FILE_DECLARATION_LABELS);
31752
+ var LINEAGE_VERIFIED_KEY = "pass-inputs:reconcile-lineage";
29823
31753
  async function reconcileStaleFiles(store2, rootPath, workspaceId) {
29824
- const stale = await findStaleFiles(store2, rootPath, workspaceId);
29825
- if (stale.length === 0) return 0;
31754
+ const startedAt = store2.changeSeq?.();
31755
+ const verified = Number(store2.getMeta?.(LINEAGE_VERIFIED_KEY) ?? NaN);
31756
+ const stale = await findStaleFiles(store2, rootPath, workspaceId, Number.isFinite(verified) ? verified : void 0);
31757
+ const verify = () => {
31758
+ if (startedAt !== void 0) store2.setMeta?.(LINEAGE_VERIFIED_KEY, String(startedAt));
31759
+ };
31760
+ if (stale.length === 0) {
31761
+ verify();
31762
+ return 0;
31763
+ }
29826
31764
  let total = 0;
29827
31765
  let failedBatches = 0;
29828
31766
  const BATCH = 20;
@@ -29840,11 +31778,15 @@ async function reconcileStaleFiles(store2, rootPath, workspaceId) {
29840
31778
  }
29841
31779
  if (failedBatches > 0) {
29842
31780
  console.warn(`[errata] reconcile: ${failedBatches} batch(es) failed; ${total} file(s) reindexed`);
31781
+ } else {
31782
+ verify();
29843
31783
  }
29844
31784
  return total;
29845
31785
  }
29846
31786
 
29847
31787
  // src/workspace-maintenance.ts
31788
+ var WM_CALIBRATION_AT_KEY = "wm-calibration-at";
31789
+ var WM_CALIBRATION_INTERVAL_MS = 30 * 6e4;
29848
31790
  function runWorkspaceMaintenance(store2, workspaceId) {
29849
31791
  const seqBefore = store2.currentIngestSeq();
29850
31792
  const report = runSemanticMaintenance(store2);
@@ -29855,9 +31797,13 @@ function runWorkspaceMaintenance(store2, workspaceId) {
29855
31797
  }
29856
31798
  let calibration = null;
29857
31799
  const calibrationStarted = Date.now();
29858
- try {
29859
- calibration = wmCalibrationCells(store2);
29860
- } catch {
31800
+ const lastCalibration = Number(store2.getMeta?.(WM_CALIBRATION_AT_KEY) ?? 0);
31801
+ if (!(calibrationStarted - lastCalibration < WM_CALIBRATION_INTERVAL_MS)) {
31802
+ try {
31803
+ calibration = wmCalibrationCells(store2);
31804
+ store2.setMeta?.(WM_CALIBRATION_AT_KEY, String(calibrationStarted));
31805
+ } catch {
31806
+ }
29861
31807
  }
29862
31808
  return {
29863
31809
  report,
@@ -30114,9 +32060,9 @@ function readDirectDependencies(root) {
30114
32060
  const hit = directCache.get(root);
30115
32061
  if (hit && hit.key === key) return hit.direct;
30116
32062
  const direct = [];
30117
- for (const { c, path } of found) {
32063
+ for (const { c, path: path2 } of found) {
30118
32064
  try {
30119
- direct.push(...c.parse(readFileSync3(path, "utf8")).direct ?? []);
32065
+ direct.push(...c.parse(readFileSync3(path2, "utf8")).direct ?? []);
30120
32066
  } catch {
30121
32067
  }
30122
32068
  }
@@ -30199,7 +32145,7 @@ function scanManifests(root) {
30199
32145
  try {
30200
32146
  const spine = buildSpine("workspace", [...texts.keys()], (p) => texts.get(p) ?? "");
30201
32147
  scan2.deps = Object.values(spine.manifests).flat();
30202
- for (const [path, text] of texts) scan2.self.push(...parseManifestSelf(path, text));
32148
+ for (const [path2, text] of texts) scan2.self.push(...parseManifestSelf(path2, text));
30203
32149
  } catch {
30204
32150
  scan2.deps = [];
30205
32151
  scan2.self = [];