@inerrata-corporation/errata 2.0.16 → 2.0.17-dev.3407
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/consolidate-worker.mjs +55 -13
- package/errata.mjs +469 -186
- package/package.json +1 -1
- package/pass-worker.mjs +1574 -18
package/errata.mjs
CHANGED
|
@@ -139,6 +139,7 @@ var init_castalia = __esm({
|
|
|
139
139
|
ROUTING_REASONS = [
|
|
140
140
|
/** Harness org (CTF lane, e2e battery, canary) — forced org-private. */
|
|
141
141
|
"harness-clamp",
|
|
142
|
+
"witnessed-vulnerability-private",
|
|
142
143
|
/** A signed gateway write target named the destination. */
|
|
143
144
|
"signed-target-public",
|
|
144
145
|
"signed-target-org",
|
|
@@ -1080,6 +1081,12 @@ function identityId(input) {
|
|
|
1080
1081
|
}
|
|
1081
1082
|
case "Claim":
|
|
1082
1083
|
return canonicalClaimId(input.text, input.scope);
|
|
1084
|
+
case "WitnessedVulnerability":
|
|
1085
|
+
return genericCanonicalId("dvuln", {
|
|
1086
|
+
workspaceId: input.workspaceId,
|
|
1087
|
+
target: input.target.replace(/\\/g, "/").replace(/^\.\//, ""),
|
|
1088
|
+
statement: canonicalClaimId(input.statement.trim())
|
|
1089
|
+
});
|
|
1083
1090
|
case "DesignProblem":
|
|
1084
1091
|
return `${DESIGN_PROBLEM_PREFIX}${canonicalClaimId(input.statement.trim())}`.slice(
|
|
1085
1092
|
0,
|
|
@@ -15849,7 +15856,7 @@ var init_edge_rules = __esm({
|
|
|
15849
15856
|
// anchor anything at anything, e.g. at a public `Package`, quietly re-creating
|
|
15850
15857
|
// the code↔collective bridge the membrane exists to prevent.
|
|
15851
15858
|
ANCHORED_AT: {
|
|
15852
|
-
from: ["Problem", "Solution", "RootCause", "Claim"],
|
|
15859
|
+
from: ["Problem", "Vulnerability", "Solution", "RootCause", "Claim"],
|
|
15853
15860
|
to: ["Symbol"]
|
|
15854
15861
|
},
|
|
15855
15862
|
// ── Security spine (v1 taxonomy.ts SECURITY_FORWARD_ONLY commentary) ──
|
|
@@ -15894,7 +15901,7 @@ var init_edge_rules = __esm({
|
|
|
15894
15901
|
// `Component` joined the target set with OM-agent-anchors: an agent-named
|
|
15895
15902
|
// component ("React Router") is the same knowledge→named-unit anchor shape as
|
|
15896
15903
|
// a Tool — the knowledge is ABOUT it, not dependent on it.
|
|
15897
|
-
CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
|
|
15904
|
+
CONCERNS: { from: ["Problem", "Vulnerability", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
|
|
15898
15905
|
OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
|
|
15899
15906
|
INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
|
|
15900
15907
|
// ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
|
|
@@ -18005,8 +18012,6 @@ function repairSessionEvidence(input, aliases = /* @__PURE__ */ new Map()) {
|
|
|
18005
18012
|
const mapping = new Map(aliases);
|
|
18006
18013
|
const uuid3 = "[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}";
|
|
18007
18014
|
const codex = new RegExp(`^codex:(?:rollout-.*?)?(${uuid3})$`, "i");
|
|
18008
|
-
const arrays = /* @__PURE__ */ new Set(["sources", "recurrenceSources", "contributors", "inferredContributors", "citeSessions"]);
|
|
18009
|
-
const scalars = /* @__PURE__ */ new Set(["discriminatorSource", "originSession", "sessionId", "sourceSession"]);
|
|
18010
18015
|
const discover = (value, key = "") => {
|
|
18011
18016
|
if (typeof value === "string" && (arrays.has(key) || scalars.has(key) || key === "citeAnchorHints")) {
|
|
18012
18017
|
const match2 = value.match(codex);
|
|
@@ -18064,9 +18069,13 @@ function repairSessionEvidence(input, aliases = /* @__PURE__ */ new Map()) {
|
|
|
18064
18069
|
}
|
|
18065
18070
|
return repaired;
|
|
18066
18071
|
}
|
|
18072
|
+
var arrays, scalars, SESSION_EVIDENCE_FIELDS;
|
|
18067
18073
|
var init_session_evidence = __esm({
|
|
18068
18074
|
"../../packages/local-graph/src/session-evidence.ts"() {
|
|
18069
18075
|
"use strict";
|
|
18076
|
+
arrays = /* @__PURE__ */ new Set(["sources", "recurrenceSources", "contributors", "inferredContributors", "citeSessions"]);
|
|
18077
|
+
scalars = /* @__PURE__ */ new Set(["discriminatorSource", "originSession", "sessionId", "sourceSession"]);
|
|
18078
|
+
SESSION_EVIDENCE_FIELDS = [...arrays, ...scalars, "citeAnchorHints"];
|
|
18070
18079
|
}
|
|
18071
18080
|
});
|
|
18072
18081
|
|
|
@@ -18146,7 +18155,7 @@ function rowToEdge(r) {
|
|
|
18146
18155
|
function openGraphStore(opts) {
|
|
18147
18156
|
return new SqliteGraphStore(opts);
|
|
18148
18157
|
}
|
|
18149
|
-
var LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, SqliteGraphStore;
|
|
18158
|
+
var LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SESSION_EVIDENCE_PREDICATE, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, SqliteGraphStore;
|
|
18150
18159
|
var init_store = __esm({
|
|
18151
18160
|
"../../packages/local-graph/src/store.ts"() {
|
|
18152
18161
|
"use strict";
|
|
@@ -18177,6 +18186,7 @@ var init_store = __esm({
|
|
|
18177
18186
|
REGRESSION_OF: { from: ["Problem"], to: ["Problem"] }
|
|
18178
18187
|
};
|
|
18179
18188
|
SCHEMA_VERSION = 6;
|
|
18189
|
+
SESSION_EVIDENCE_PREDICATE = SESSION_EVIDENCE_FIELDS.map((field) => `instr(attrs_json, '${JSON.stringify(field)}') > 0`).join(" OR ");
|
|
18180
18190
|
SCHEMA_SQL = `
|
|
18181
18191
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
18182
18192
|
version INTEGER PRIMARY KEY
|
|
@@ -18269,12 +18279,17 @@ CREATE UNIQUE INDEX IF NOT EXISTS edges_triple ON edges(from_id, type, to_id);
|
|
|
18269
18279
|
`;
|
|
18270
18280
|
TEMPORAL_INDEX_SQL = `
|
|
18271
18281
|
CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
|
|
18282
|
+
CREATE INDEX IF NOT EXISTS nodes_live_count ON nodes(valid_to);
|
|
18283
|
+
CREATE INDEX IF NOT EXISTS nodes_live_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL;
|
|
18284
|
+
CREATE INDEX IF NOT EXISTS nodes_session_evidence ON nodes(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
18285
|
+
CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
18272
18286
|
-- Covering + partial index for labelFingerprint over the instance labels: the
|
|
18273
18287
|
-- live-push probe runs it per workspace on a timer, and each hit used to read
|
|
18274
18288
|
-- its table row. Partial, so it maintains a few thousand rows instead of adding
|
|
18275
18289
|
-- a write to every node write. Its label list is FINGERPRINT_INDEXED_LABELS.
|
|
18276
18290
|
DROP INDEX IF EXISTS nodes_live_fingerprint;
|
|
18277
|
-
|
|
18291
|
+
DROP INDEX IF EXISTS nodes_instance_fingerprint;
|
|
18292
|
+
CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_updated_at, last_reinforced_at_seq, created_at_seq) WHERE valid_to IS NULL AND label IN ('Problem','Vulnerability','Solution','RootCause');
|
|
18278
18293
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
18279
18294
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
18280
18295
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
@@ -18288,7 +18303,7 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
|
|
|
18288
18303
|
-- every edited file of every turn, and a scan parses every Problem's attrs.
|
|
18289
18304
|
CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
|
|
18290
18305
|
`;
|
|
18291
|
-
FINGERPRINT_INDEXED_LABELS = ["Problem", "Solution", "RootCause"];
|
|
18306
|
+
FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
|
|
18292
18307
|
SqliteGraphStore = class {
|
|
18293
18308
|
db;
|
|
18294
18309
|
// Typed edge lookups build their SQL from the number of types asked for, and
|
|
@@ -18580,12 +18595,13 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18580
18595
|
});
|
|
18581
18596
|
}
|
|
18582
18597
|
repairSessionAliases(canonical, aliases = []) {
|
|
18598
|
+
if (canonical && aliases.length === 0) return 0;
|
|
18583
18599
|
const mapping = new Map(aliases.map((alias) => [alias, canonical]));
|
|
18584
18600
|
let changed = 0;
|
|
18585
18601
|
for (const table of ["nodes", "edges"]) {
|
|
18586
18602
|
const predicates = canonical ? aliases.map(() => "instr(attrs_json, ?) > 0") : ["instr(attrs_json, 'codex:') > 0", "instr(attrs_json, 'discriminatorSource') > 0"];
|
|
18587
18603
|
if (!predicates.length) continue;
|
|
18588
|
-
const rows = this.db.prepare(`SELECT id, attrs_json FROM ${table} WHERE ${predicates.join(" OR ")}`).all(...canonical ? aliases : []);
|
|
18604
|
+
const rows = this.db.prepare(`SELECT id, attrs_json FROM ${table} WHERE (${SESSION_EVIDENCE_PREDICATE}) AND (${predicates.join(" OR ")})`).all(...canonical ? aliases.map((alias) => JSON.stringify(alias)) : []);
|
|
18589
18605
|
const update = this.db.prepare(`UPDATE ${table} SET attrs_json = ?${table === "edges" ? ", type = CASE WHEN type = 'CONFIRMS' AND json_extract(?, '$.provisional') = 1 THEN 'INDICATES' ELSE type END" : ""} WHERE id = ?`);
|
|
18590
18606
|
for (const row of rows) {
|
|
18591
18607
|
const attrs = JSON.stringify(repairSessionEvidence(JSON.parse(row.attrs_json), mapping));
|
|
@@ -18811,6 +18827,25 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18811
18827
|
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));
|
|
18812
18828
|
return rows.map((r) => r.id);
|
|
18813
18829
|
}
|
|
18830
|
+
recentOpenProblemCandidates(opts) {
|
|
18831
|
+
if (!Number.isSafeInteger(opts.limit) || opts.limit < 0) {
|
|
18832
|
+
throw new RangeError("candidate limit must be a non-negative safe integer");
|
|
18833
|
+
}
|
|
18834
|
+
return this.db.prepare(`SELECT id, description FROM nodes
|
|
18835
|
+
WHERE label = 'Problem' AND valid_to IS NULL
|
|
18836
|
+
AND json_extract(attrs_json, '$.resolvedAt') IS NULL
|
|
18837
|
+
AND json_type(attrs_json, '$.mergedInto') IS NULL
|
|
18838
|
+
AND (? IS NULL OR id != ?)
|
|
18839
|
+
AND (json_type(attrs_json, '$.workspaceId') IS NULL OR json_extract(attrs_json, '$.workspaceId') = ?)
|
|
18840
|
+
AND COALESCE(json_extract(attrs_json, '$.kind') = 'constraint', 0) = ?
|
|
18841
|
+
ORDER BY last_updated_at DESC, rowid ASC LIMIT ?`).all(
|
|
18842
|
+
opts.excludeId ?? null,
|
|
18843
|
+
opts.excludeId ?? null,
|
|
18844
|
+
opts.workspaceId,
|
|
18845
|
+
opts.constraint ? 1 : 0,
|
|
18846
|
+
opts.limit
|
|
18847
|
+
);
|
|
18848
|
+
}
|
|
18814
18849
|
hasLiveNodes() {
|
|
18815
18850
|
const r = this.db.prepare("SELECT EXISTS(SELECT 1 FROM nodes WHERE valid_to IS NULL) AS e").get();
|
|
18816
18851
|
return r.e === 1;
|
|
@@ -18966,8 +19001,8 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18966
19001
|
const r2 = this.db.prepare(
|
|
18967
19002
|
`SELECT COUNT(*) AS n, MAX(last_updated_at) AS t,
|
|
18968
19003
|
MAX(COALESCE(last_reinforced_at_seq, created_at_seq, 0)) AS s
|
|
18969
|
-
FROM nodes INDEXED BY
|
|
18970
|
-
WHERE valid_to IS NULL AND label IN ('Problem','Solution','RootCause')`
|
|
19004
|
+
FROM nodes INDEXED BY nodes_instance_fingerprint_v2
|
|
19005
|
+
WHERE valid_to IS NULL AND label IN ('Problem','Vulnerability','Solution','RootCause')`
|
|
18971
19006
|
).get();
|
|
18972
19007
|
return `${r2.n}:${r2.t ?? 0}:${r2.s ?? 0}`;
|
|
18973
19008
|
}
|
|
@@ -20263,7 +20298,7 @@ function mergeContextEdge(store, from, to, type, ts) {
|
|
|
20263
20298
|
function deriveContextFromAnchors(store, problemId, ts, pkgIndex) {
|
|
20264
20299
|
const report = { languages: [], packages: [] };
|
|
20265
20300
|
const p = store.getNode(problemId);
|
|
20266
|
-
if (!p || p.label !== "Problem") return report;
|
|
20301
|
+
if (!p || p.label !== "Problem" && p.label !== "Vulnerability") return report;
|
|
20267
20302
|
const files = store.outEdges(problemId, ["ANCHORED_AT"]).map((e) => store.getNode(e.to)).filter((n) => !!n && n.label === "File");
|
|
20268
20303
|
if (files.length === 0) return report;
|
|
20269
20304
|
const idx = pkgIndex ?? buildPackageIndex(store);
|
|
@@ -20901,6 +20936,81 @@ function ingestDesignProblem(store, flag, opts) {
|
|
|
20901
20936
|
...reopenedFromRegression ? { reopenedFromRegression } : {}
|
|
20902
20937
|
};
|
|
20903
20938
|
}
|
|
20939
|
+
function ingestWitnessedVulnerability(store, flag, opts) {
|
|
20940
|
+
const statement = flag.statement.trim();
|
|
20941
|
+
if (isPlaceholderStatement(statement)) return { id: "", created: false, corroborated: false, upgraded: false, rejected: "statement" };
|
|
20942
|
+
const target = flag.target?.trim().replace(/\\/g, "/").replace(/^\.\//, "") ?? "";
|
|
20943
|
+
const file2 = target ? resolveFileNode(store, target, opts.workspaceId) : null;
|
|
20944
|
+
const symbol2 = file2 && flag.line !== void 0 && flag.fileText !== void 0 ? resolveEnclosingSymbol(store, file2.id, flag.line, flag.fileText) : null;
|
|
20945
|
+
const identityTarget = symbol2 ? String(symbol2.attrs["logicalId"] ?? `${target}#${symbol2.attrs["qname"] ?? symbol2.description}`) : target;
|
|
20946
|
+
const compatibleTarget = (n) => !symbol2 || !n.attrs["identityTarget"] || n.attrs["identityTarget"] === target || n.attrs["identityTarget"] === identityTarget;
|
|
20947
|
+
const bound = flag.existingId ? store.getNode(flag.existingId) : null;
|
|
20948
|
+
if (flag.existingId && (!bound || bound.label !== "Vulnerability" || bound.attrs["workspaceId"] !== opts.workspaceId || target && bound.attrs["affectedTarget"] && bound.attrs["affectedTarget"] !== target || !compatibleTarget(bound))) {
|
|
20949
|
+
return { id: "", created: false, corroborated: false, upgraded: false, rejected: "binding-conflict" };
|
|
20950
|
+
}
|
|
20951
|
+
const statementKey = identityId({ kind: "DesignProblem", statement });
|
|
20952
|
+
const restated = bound ? null : store.findNodesByLabel("Vulnerability").find((n) => n.attrs["workspaceId"] === opts.workspaceId && n.attrs["affectedTarget"] === target && compatibleTarget(n) && [n.description, ...n.attrs["statementAliases"] ?? []].some((s) => identityId({ kind: "DesignProblem", statement: s }) === statementKey));
|
|
20953
|
+
const id = bound?.id ?? restated?.id ?? identityId({ kind: "WitnessedVulnerability", workspaceId: opts.workspaceId, target: identityTarget, statement });
|
|
20954
|
+
const existing = bound ?? store.getNode(id);
|
|
20955
|
+
const sources = existing?.attrs["sources"] ?? [];
|
|
20956
|
+
const corroborated = !!existing && !sources.includes(opts.source);
|
|
20957
|
+
const upgraded = !!existing && existing.attrs["assessment"] !== "asserted" && flag.assessment === "asserted";
|
|
20958
|
+
const assessment = existing?.attrs["assessment"] === "asserted" ? "asserted" : flag.assessment;
|
|
20959
|
+
if (!existing) {
|
|
20960
|
+
store.mergeNode(buildNode(store, id, "Vulnerability", statement, opts.ts, {
|
|
20961
|
+
source: "convo",
|
|
20962
|
+
sourceClass: "agent-observation",
|
|
20963
|
+
privateFinding: id,
|
|
20964
|
+
workspaceId: opts.workspaceId,
|
|
20965
|
+
affectedTarget: target,
|
|
20966
|
+
identityTarget,
|
|
20967
|
+
assessment,
|
|
20968
|
+
anchorDisposition: target ? "unresolved" : "absent",
|
|
20969
|
+
provisional: true,
|
|
20970
|
+
sources: [opts.source],
|
|
20971
|
+
corroborations: 0,
|
|
20972
|
+
...opts.hostHarness ? { hostHarness: opts.hostHarness } : {}
|
|
20973
|
+
}));
|
|
20974
|
+
} else if (corroborated || upgraded || !existing.attrs["affectedTarget"] && target || symbol2 && existing.attrs["identityTarget"] !== identityTarget) {
|
|
20975
|
+
store.updateNode(id, {
|
|
20976
|
+
attrs: {
|
|
20977
|
+
...existing.attrs,
|
|
20978
|
+
assessment,
|
|
20979
|
+
...upgraded && existing.description !== statement ? { statementAliases: [...existing.attrs["statementAliases"] ?? [], existing.description].slice(-5) } : {},
|
|
20980
|
+
affectedTarget: existing.attrs["affectedTarget"] || target,
|
|
20981
|
+
...symbol2 ? { identityTarget } : {},
|
|
20982
|
+
sources: corroborated ? [...sources, opts.source] : sources,
|
|
20983
|
+
corroborations: (Number(existing.attrs["corroborations"]) || 0) + (corroborated ? 1 : 0)
|
|
20984
|
+
},
|
|
20985
|
+
// Assessment strengthens on evidence, but does not certify exploitability.
|
|
20986
|
+
...upgraded ? { description: statement } : {},
|
|
20987
|
+
...corroborated ? { cumulativeHits: existing.cumulativeHits + 1 } : {},
|
|
20988
|
+
...reinforcedSeqAttrs(store, "Vulnerability"),
|
|
20989
|
+
lastUpdatedAt: opts.ts
|
|
20990
|
+
});
|
|
20991
|
+
}
|
|
20992
|
+
return { id, created: !existing, corroborated, upgraded };
|
|
20993
|
+
}
|
|
20994
|
+
function recordVulnerabilityCause(store, findingId, causes, ts) {
|
|
20995
|
+
const finding = store.getNode(findingId);
|
|
20996
|
+
if (finding?.label !== "Vulnerability") return 0;
|
|
20997
|
+
let from = findingId;
|
|
20998
|
+
let count = 0;
|
|
20999
|
+
for (const description of causes) {
|
|
21000
|
+
if (isPlaceholderStatement(description)) continue;
|
|
21001
|
+
const id = genericCanonicalId("dcause", { findingId, description: description.trim() });
|
|
21002
|
+
if (!store.getNode(id)) store.mergeNode(buildNode(store, id, "RootCause", description.trim(), ts, {
|
|
21003
|
+
source: "convo",
|
|
21004
|
+
privateFinding: findingId,
|
|
21005
|
+
sources: finding.attrs["sources"],
|
|
21006
|
+
assessment: finding.attrs["assessment"]
|
|
21007
|
+
}));
|
|
21008
|
+
mergeEdge(store, from, id, "CAUSED_BY", ts);
|
|
21009
|
+
from = id;
|
|
21010
|
+
count++;
|
|
21011
|
+
}
|
|
21012
|
+
return count;
|
|
21013
|
+
}
|
|
20904
21014
|
function canonicalizePatternText(name2) {
|
|
20905
21015
|
const stripped = name2.replace(/^\s*pattern(?:\s*[×x]\s*\d+)?\s*(?:\(exemplar\))?\s*[:—–-]\s*/i, "").replace(/\s+/g, " ").trim();
|
|
20906
21016
|
return stripped.length > 0 ? stripped : name2.replace(/\s+/g, " ").trim();
|
|
@@ -21211,6 +21321,7 @@ function findReusableSolution(store, fixText) {
|
|
|
21211
21321
|
const key = solutionTextKey(fixText);
|
|
21212
21322
|
if (!key) return null;
|
|
21213
21323
|
for (const s of store.findNodesByLabel("Solution")) {
|
|
21324
|
+
if (s.attrs["privateFinding"]) continue;
|
|
21214
21325
|
if (s.validTo != null) continue;
|
|
21215
21326
|
if (isAutoMinted(s)) continue;
|
|
21216
21327
|
if (solutionTextKey(s.description ?? "") === key) return s;
|
|
@@ -21235,7 +21346,7 @@ function priorsForFile(store, relPath) {
|
|
|
21235
21346
|
for (const e of store.inEdges(file2.id, ["ANCHORED_AT"])) {
|
|
21236
21347
|
const n = store.getNode(e.from);
|
|
21237
21348
|
if (!n) continue;
|
|
21238
|
-
if (n.label === "Problem") {
|
|
21349
|
+
if (n.label === "Problem" || n.label === "Vulnerability") {
|
|
21239
21350
|
if (seenProblem.has(n.id)) continue;
|
|
21240
21351
|
seenProblem.add(n.id);
|
|
21241
21352
|
if (!n.attrs["resolvedAt"]) {
|
|
@@ -21305,7 +21416,8 @@ function solutionForProblem(store, problemId) {
|
|
|
21305
21416
|
}
|
|
21306
21417
|
function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts, provenance = "edited", opts = {}) {
|
|
21307
21418
|
const p = store.getNode(problemId);
|
|
21308
|
-
if (!p || p.label !== "Problem") return false;
|
|
21419
|
+
if (!p || p.label !== "Problem" && p.label !== "Vulnerability") return false;
|
|
21420
|
+
if (p.label === "Vulnerability" && provenance !== "witnessed") return false;
|
|
21309
21421
|
if (!isAnchorableCodePath(relPath)) return false;
|
|
21310
21422
|
const file2 = resolveFileNode(store, relPath, workspaceId2);
|
|
21311
21423
|
if (!file2) return false;
|
|
@@ -21484,18 +21596,22 @@ function resolveDesignProblemById(store, id, fixNote, t) {
|
|
|
21484
21596
|
}
|
|
21485
21597
|
function closeDesignProblem(store, problemId, fixNote, t) {
|
|
21486
21598
|
const p = store.getNode(problemId);
|
|
21487
|
-
if (!p || p.label !== "Problem") return false;
|
|
21599
|
+
if (!p || p.label !== "Problem" && p.label !== "Vulnerability") return false;
|
|
21488
21600
|
if (p.attrs["resolvedAs"]) return false;
|
|
21489
21601
|
if (fixNote?.trim() && !isFragmentFixNote(fixNote)) {
|
|
21490
21602
|
const sols = store.outEdges(problemId, ["SOLVED_BY"]).map((e) => store.getNode(e.to)).filter((n) => n !== null);
|
|
21491
21603
|
if (sols.every((s) => isAutoMinted(s))) {
|
|
21492
|
-
const reuse = findReusableSolution(store, fixNote);
|
|
21604
|
+
const reuse = p.label === "Vulnerability" ? null : findReusableSolution(store, fixNote);
|
|
21493
21605
|
if (reuse) {
|
|
21494
21606
|
mergeEdge(store, problemId, reuse.id, "SOLVED_BY", t);
|
|
21495
21607
|
} else {
|
|
21496
21608
|
const solId = `dfix_${digest({ problemId, fix: fixNote })}`.slice(0, 56);
|
|
21497
21609
|
store.mergeNode(
|
|
21498
|
-
buildNode(store, solId, "Solution", fixNote.trim(), t, {
|
|
21610
|
+
buildNode(store, solId, "Solution", fixNote.trim(), t, {
|
|
21611
|
+
source: "convo",
|
|
21612
|
+
provisional: false,
|
|
21613
|
+
...p.label === "Vulnerability" ? { privateFinding: problemId, sources: p.attrs["sources"] } : {}
|
|
21614
|
+
})
|
|
21499
21615
|
);
|
|
21500
21616
|
mergeEdge(store, problemId, solId, "SOLVED_BY", t);
|
|
21501
21617
|
}
|
|
@@ -21509,6 +21625,7 @@ function closeDesignProblem(store, problemId, fixNote, t) {
|
|
|
21509
21625
|
// mints no Solution, and a legacy placeholder beside it reads as
|
|
21510
21626
|
// all-heuristic either way.
|
|
21511
21627
|
attrs: { ...p.attrs, provisional: false, resolvedAt: t, resolutionWitnessed: true },
|
|
21628
|
+
...reinforcedSeqAttrs(store, p.label),
|
|
21512
21629
|
lastUpdatedAt: t
|
|
21513
21630
|
});
|
|
21514
21631
|
return true;
|
|
@@ -23860,7 +23977,7 @@ function detectLocalCommunities(store, opts = {}) {
|
|
|
23860
23977
|
const ids = /* @__PURE__ */ new Set();
|
|
23861
23978
|
for (const label of JOINT_COMMUNITY_LABELS) {
|
|
23862
23979
|
for (const n of store.findNodesByLabel(label)) {
|
|
23863
|
-
if (
|
|
23980
|
+
if (n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
|
|
23864
23981
|
ids.add(n.id);
|
|
23865
23982
|
}
|
|
23866
23983
|
}
|
|
@@ -23997,6 +24114,7 @@ var init_community2 = __esm({
|
|
|
23997
24114
|
init_src4();
|
|
23998
24115
|
JOINT_COMMUNITY_LABELS = [
|
|
23999
24116
|
"Problem",
|
|
24117
|
+
"Vulnerability",
|
|
24000
24118
|
"Solution",
|
|
24001
24119
|
"RootCause",
|
|
24002
24120
|
"Pattern"
|
|
@@ -24041,10 +24159,12 @@ function markFoldCandidate(store, problemId, targetId, info2) {
|
|
|
24041
24159
|
}
|
|
24042
24160
|
function findWorkspaceFoldCandidate(store, workspaceId2, statement, kind, opts) {
|
|
24043
24161
|
const stmtVec = embed(statement);
|
|
24044
|
-
const
|
|
24045
|
-
|
|
24046
|
-
|
|
24047
|
-
|
|
24162
|
+
const open2 = store.recentOpenProblemCandidates({
|
|
24163
|
+
workspaceId: workspaceId2,
|
|
24164
|
+
constraint: kind === "constraint",
|
|
24165
|
+
limit: opts?.scanCap ?? WORKSPACE_SCAN_CAP,
|
|
24166
|
+
...opts?.excludeId !== void 0 ? { excludeId: opts.excludeId } : {}
|
|
24167
|
+
});
|
|
24048
24168
|
let best = null;
|
|
24049
24169
|
for (const p of open2) {
|
|
24050
24170
|
const c = cosine(stmtVec, embed(p.description));
|
|
@@ -24858,6 +24978,7 @@ __export(src_exports2, {
|
|
|
24858
24978
|
induceAbstractions: () => induceAbstractions,
|
|
24859
24979
|
induceTriage: () => induceTriage,
|
|
24860
24980
|
ingestDesignProblem: () => ingestDesignProblem,
|
|
24981
|
+
ingestWitnessedVulnerability: () => ingestWitnessedVulnerability,
|
|
24861
24982
|
isConstraintProblem: () => isConstraintProblem,
|
|
24862
24983
|
isFragmentFixNote: () => isFragmentFixNote,
|
|
24863
24984
|
isPlaceholderStatement: () => isPlaceholderStatement,
|
|
@@ -24905,6 +25026,7 @@ __export(src_exports2, {
|
|
|
24905
25026
|
recordMisreadPrior: () => recordMisreadPrior,
|
|
24906
25027
|
recordRenderLedger: () => recordRenderLedger,
|
|
24907
25028
|
recordTriageObservation: () => recordTriageObservation,
|
|
25029
|
+
recordVulnerabilityCause: () => recordVulnerabilityCause,
|
|
24908
25030
|
reinforceSameAnchorProblem: () => reinforceSameAnchorProblem,
|
|
24909
25031
|
relateClaims: () => relateClaims,
|
|
24910
25032
|
reopenAutoClosedProblems: () => reopenAutoClosedProblems,
|
|
@@ -24974,7 +25096,7 @@ function isPassiveInjectable(node2, atCommit) {
|
|
|
24974
25096
|
return false;
|
|
24975
25097
|
}
|
|
24976
25098
|
function buildSnapshot(opts) {
|
|
24977
|
-
const problems = opts.store.findNodesByLabel("Problem").filter((p) => p.attrs["mergedInto"] === void 0 && historyReadPolicy(p, { mode: "passive", atCommit: opts.atCommit }).allow);
|
|
25099
|
+
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);
|
|
24978
25100
|
const stillOpen = problems.filter((p) => p.attrs["resolvedAt"] == null);
|
|
24979
25101
|
const allProblems = stillOpen.filter((p) => !isConstraintProblem(p));
|
|
24980
25102
|
allProblems.sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt);
|
|
@@ -25129,11 +25251,11 @@ function sliceForFile(store, relPath, atCommit) {
|
|
|
25129
25251
|
const priors = fp ? {
|
|
25130
25252
|
openProblems: fp.openProblems.slice(0, 3).map((p) => ({
|
|
25131
25253
|
id: p.id,
|
|
25132
|
-
description: p.description,
|
|
25254
|
+
description: p.label === "Vulnerability" ? `Vulnerability (${p.attrs["assessment"] ?? "unassessed"}): ${p.description}` : p.description,
|
|
25133
25255
|
...typeof p.attrs["fixCandidateFile"] === "string" ? { fixCandidateFile: p.attrs["fixCandidateFile"] } : {}
|
|
25134
25256
|
})),
|
|
25135
25257
|
constraints: fp.constraints.slice(0, 2).map((c) => ({ id: c.id, description: c.description })),
|
|
25136
|
-
resolvedProblems: fp.resolvedProblems.slice(0, 3).map((p) => ({ id: p.id, description: p.description })),
|
|
25258
|
+
resolvedProblems: fp.resolvedProblems.slice(0, 3).map((p) => ({ id: p.id, description: p.label === "Vulnerability" ? `Vulnerability (${p.attrs["assessment"] ?? "unassessed"}): ${p.description}` : p.description })),
|
|
25137
25259
|
related: fp.related.slice(0, 4).map((n) => ({ id: n.id, label: n.label, description: n.description })),
|
|
25138
25260
|
solutionsByProblem: Object.fromEntries(
|
|
25139
25261
|
[...fp.openProblems.slice(0, 3), ...fp.resolvedProblems.slice(0, 3)].map((p) => [
|
|
@@ -25251,7 +25373,8 @@ function renderSnapshot(s) {
|
|
|
25251
25373
|
if (s.recentProblems.length > 0) {
|
|
25252
25374
|
lines.push("_Open \u2014 recently observed here, derived from your work (a recency slice, not an inventory \u2014 burst an id for its full neighborhood):_");
|
|
25253
25375
|
for (const r of s.recentProblems) {
|
|
25254
|
-
|
|
25376
|
+
const badge = r.node.label === "Vulnerability" ? `Vulnerability (${r.node.attrs["assessment"] ?? "unassessed"}): ` : "";
|
|
25377
|
+
lines.push(`- **${badge}${r.node.description}** \u2014 \`${r.node.id}\`${tagOf(r.node)}`);
|
|
25255
25378
|
const hits = r.node.cumulativeHits ?? 0;
|
|
25256
25379
|
const surprise = (r.node.cumulativeSurprise ?? 0).toFixed(2);
|
|
25257
25380
|
lines.push(` - observed ${hits}\xD7 \xB7 cumulativeSurprise ${surprise}`);
|
|
@@ -25292,7 +25415,8 @@ function renderSnapshot(s) {
|
|
|
25292
25415
|
if (s.recentResolved.length > 0) {
|
|
25293
25416
|
lines.push("_Recently resolved \u2014 solved here; jumping-off points, not live defects:_");
|
|
25294
25417
|
for (const r of s.recentResolved) {
|
|
25295
|
-
|
|
25418
|
+
const badge = r.node.label === "Vulnerability" ? `Vulnerability (${r.node.attrs["assessment"] ?? "unassessed"}): ` : "";
|
|
25419
|
+
lines.push(`- \u2713 **${badge}${r.node.description}** \u2014 \`${r.node.id}\`${tagOf(r.node)}`);
|
|
25296
25420
|
if (r.solution) {
|
|
25297
25421
|
lines.push(` - solved: ${r.solution.description.slice(0, 160)} \u2014 \`${r.solution.id}\`${tagOf(r.solution)}`);
|
|
25298
25422
|
}
|
|
@@ -27152,8 +27276,8 @@ var init_config = __esm({
|
|
|
27152
27276
|
"use strict";
|
|
27153
27277
|
init_paths();
|
|
27154
27278
|
LEGACY_CLOUD_URL = "https://inerrata-gateway.onrender.com";
|
|
27155
|
-
DEFAULT_CLOUD_URL = true ? "https://inerrata.dev" : DEV_CLOUD_URL;
|
|
27156
|
-
DEFAULT_UPDATE_CHANNEL =
|
|
27279
|
+
DEFAULT_CLOUD_URL = true ? "https://dev.inerrata.dev" : DEV_CLOUD_URL;
|
|
27280
|
+
DEFAULT_UPDATE_CHANNEL = false ? "latest" : "dev";
|
|
27157
27281
|
}
|
|
27158
27282
|
});
|
|
27159
27283
|
|
|
@@ -31713,7 +31837,7 @@ var init_src8 = __esm({
|
|
|
31713
31837
|
|
|
31714
31838
|
// src/agent-signals.ts
|
|
31715
31839
|
function buildFileRecallInstruction(referent = "\u2026") {
|
|
31716
|
-
return `Touching one? paste its token: ${TAG_EXAMPLE.fix(referent)} resolved \xB7 ${TAG_EXAMPLE.prior(referent)} leaned-on \xB7 ${TAG_EXAMPLE.problem()} new. We harvest it.`;
|
|
31840
|
+
return `Touching one? paste its token: ${TAG_EXAMPLE.fix(referent)} resolved \xB7 ${TAG_EXAMPLE.prior(referent)} leaned-on \xB7 ${TAG_EXAMPLE.problem()} new \xB7 ${TAG_EXAMPLE.vulnerability()} security. We harvest it.`;
|
|
31717
31841
|
}
|
|
31718
31842
|
function triageBullet(ref) {
|
|
31719
31843
|
return [
|
|
@@ -31749,15 +31873,15 @@ function attemptBullet() {
|
|
|
31749
31873
|
].join("\n");
|
|
31750
31874
|
}
|
|
31751
31875
|
function buildAgentInstruction(opts = {}) {
|
|
31752
|
-
const signals = opts.signals ?? ["prior", "problem", "domain", "fix", "constraint", "triage", "attempt", "link"];
|
|
31876
|
+
const signals = opts.signals ?? ["prior", "problem", "vulnerability", "domain", "fix", "constraint", "triage", "attempt", "link"];
|
|
31753
31877
|
const ref = opts.referent ?? "its-handle";
|
|
31754
31878
|
const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "domain" ? TAG_EXAMPLE.domain() : s === "link" ? TAG_EXAMPLE.pattern() : s === "verdict" ? TAG_EXAMPLE.confirm(ref) : TAG_EXAMPLE[s](ref);
|
|
31755
|
-
const head2 =
|
|
31756
|
-
const tail = "
|
|
31879
|
+
const head2 = "Tag inline (no fences or backticks). Untagged findings are silently lost. Cite short handles; tag everything, we filter downstream. Requested errata-* answer blocks are the exception: keep their fences in your turn-final reply:";
|
|
31880
|
+
const tail = "Restate mid-turn tags in your final reply; the harness can drop mid-turn text. EXCEPT one already shown with an id: cite [its-handle] instead of retyping (drift mints a duplicate).";
|
|
31757
31881
|
return [
|
|
31758
31882
|
head2,
|
|
31759
31883
|
...signals.map(
|
|
31760
|
-
(s) => s === "triage" ? triageBullet(ref) : s === "attempt" ? attemptBullet() : s === "link" ? linkBullet(ref) : s === "verdict" ? verdictBullet(ref) : ` \u2022 ${GLOSS[s]} \u2192 ${token(s)}`
|
|
31884
|
+
(s) => s === "triage" ? triageBullet(ref) : s === "vulnerability" ? ` \u2022 ${GLOSS.vulnerability} \u2192 ${TAG_EXAMPLE.vulnerability()}. Uncertain? ${TAG_EXAMPLE.suspectedVulnerability()}. Code review counts, even if immediately fixed. No CVE/exploit needed. For fixes: ${TAG_EXAMPLE.vulnerabilityThread()} ${TAG_EXAMPLE.fixThread("v")}.` : s === "attempt" ? attemptBullet() : s === "link" ? linkBullet(ref) : s === "verdict" ? verdictBullet(ref) : ` \u2022 ${GLOSS[s]} \u2192 ${token(s)}`
|
|
31761
31885
|
),
|
|
31762
31886
|
tail
|
|
31763
31887
|
].join("\n");
|
|
@@ -31769,6 +31893,9 @@ var init_agent_signals = __esm({
|
|
|
31769
31893
|
TAG_EXAMPLE = {
|
|
31770
31894
|
prior: (ref) => `([${ref}])`,
|
|
31771
31895
|
problem: () => `[!one line on what's wrong]`,
|
|
31896
|
+
vulnerability: () => `[!vuln: who can do what; observed basis @ path:line]`,
|
|
31897
|
+
suspectedVulnerability: () => `[?vuln: consequence; missing check]`,
|
|
31898
|
+
vulnerabilityThread: () => `[!#v vuln: finding here]`,
|
|
31772
31899
|
fix: (ref) => `(fix:[${ref}])`,
|
|
31773
31900
|
// CONSTRAINT — the native capture path for a DIFFUSE problem (a constraint/tension/
|
|
31774
31901
|
// conflict that shaped a decision). Free text, attaches to the decision sentence the
|
|
@@ -31789,7 +31916,7 @@ var init_agent_signals = __esm({
|
|
|
31789
31916
|
// tags never need one — the id is for diagnoses that unfold over distance.
|
|
31790
31917
|
problemThread: () => `[!#slug one line on what's wrong]`,
|
|
31791
31918
|
causeThread: () => `(cause:#slug the mechanism)`,
|
|
31792
|
-
fixThread: () => `(fix
|
|
31919
|
+
fixThread: (thread = "slug") => `(fix:#${thread} what you changed)`,
|
|
31793
31920
|
// ATTEMPT arc — what's being tried and what didn't work. A failed attempt is a
|
|
31794
31921
|
// witnessed NEGATIVE result: it saves the next agent the same dead end.
|
|
31795
31922
|
tried: () => `(tried: the approach you're attempting)`,
|
|
@@ -31831,8 +31958,9 @@ var init_agent_signals = __esm({
|
|
|
31831
31958
|
// problems, and narrated them as progress (a pick-best-before-scoring bug lost).
|
|
31832
31959
|
// Every example here was diagnosis-framed, so nothing contradicted that sorting.
|
|
31833
31960
|
// Kept to 29 chars: the instruction sits at the 2600 passive-budget ceiling.
|
|
31834
|
-
problem: "
|
|
31835
|
-
|
|
31961
|
+
problem: "any bug or finding, even in code you just wrote; name affected code: [!what's wrong @ path:42]",
|
|
31962
|
+
vulnerability: "unauthorized actions, data exposure, or execution/disruption an attacker can trigger",
|
|
31963
|
+
fix: "you fixed a shown finding; for your own non-security finding: (fix: what changed) \u2014 a fix resolves a stated problem, completing routine work is not a fix",
|
|
31836
31964
|
constraint: "a design decision forced by conflicting requirements or constraints \u2014 tag the tension, especially when your fix makes it 'only look' resolved",
|
|
31837
31965
|
triage: "you diagnosed a cause \u2014 fold the chain into the flag with <- (caused-by), deepest sure mechanism rightmost",
|
|
31838
31966
|
attempt: "attempting an approach / an attempt failed \u2014 a failed attempt is knowledge, it rules out a path",
|
|
@@ -31854,7 +31982,7 @@ var init_agent_signals = __esm({
|
|
|
31854
31982
|
// Sim note (2026-08-02 shrink): domain emission held 4/4 with just the trigger
|
|
31855
31983
|
// clause; the pattern convergence hook now rides here too (it fell 0/4 when it
|
|
31856
31984
|
// only appeared in the link bullet's tail).
|
|
31857
|
-
domain: "
|
|
31985
|
+
domain: "no single file? name the area (Title Case), and (pattern: the shape). No code anchor needed; two agents naming the same shape converge on one node",
|
|
31858
31986
|
link: "the problem you flagged is an instance of priors/abstractions you can name \u2014 (instance:[h1],[h2],\u2026) / (pattern: \u2026) / (aids:[h]); rendered whole via linkBullet",
|
|
31859
31987
|
verdict: "you can judge a prior we SHOWED you \u2014 confirm it if it held, refute it (with why) if it didn't; rendered whole via verdictBullet"
|
|
31860
31988
|
};
|
|
@@ -32095,7 +32223,7 @@ function readContextCard(root, hash2) {
|
|
|
32095
32223
|
function openProblems(store, now = Date.now()) {
|
|
32096
32224
|
const hit = openProblemsCache.get(store);
|
|
32097
32225
|
if (hit && now - hit.at < OPEN_PROBLEMS_TTL_MS) return hit.nodes;
|
|
32098
|
-
const nodes = store.findNodesByLabel("Problem").filter((p) => live(p) && !p.attrs["resolvedAt"] && p.attrs["mergedInto"] === void 0 && !isConstraintProblem(p));
|
|
32226
|
+
const nodes = [...store.findNodesByLabel("Problem"), ...store.findNodesByLabel("Vulnerability")].filter((p) => live(p) && !p.attrs["resolvedAt"] && p.attrs["mergedInto"] === void 0 && !isConstraintProblem(p));
|
|
32099
32227
|
openProblemsCache.set(store, { at: now, nodes });
|
|
32100
32228
|
return nodes;
|
|
32101
32229
|
}
|
|
@@ -43482,47 +43610,9 @@ var init_mcp = __esm({
|
|
|
43482
43610
|
init_reconcile();
|
|
43483
43611
|
init_agent_signals();
|
|
43484
43612
|
INSTRUCTIONS = [
|
|
43485
|
-
|
|
43486
|
-
|
|
43487
|
-
|
|
43488
|
-
// from your WORK deterministically, and the one thing it asks of the agent — a
|
|
43489
|
-
// one-line root cause at a fix — rides INLINE on the next tool response (the ⚡
|
|
43490
|
-
// errata line; see the dispatch's enrichment piggyback) instead of a fenced
|
|
43491
|
-
// protocol the agent has to remember. So this stays short: tool-routing steering
|
|
43492
|
-
// plus a single line about the inline nudge. Per-tool routing lives in each tool's
|
|
43493
|
-
// own `description` (delivered via tools/list). Don't re-add a tool table here.
|
|
43494
|
-
"errata is a LIVE, bi-temporal code graph of this workspace, kept current by a",
|
|
43495
|
-
"file watcher \u2014 a SEPARATE DIAGNOSTIC AXIS to run ALONGSIDE grep/glob/read, not",
|
|
43496
|
-
"instead of them. For STRUCTURAL questions (callers of callers, blast-radius,",
|
|
43497
|
-
"rename lineage) prefer it: faster, more complete, and it reaches relationships",
|
|
43498
|
-
"grep can't. Each tool's description says when to reach for it. Fall back to",
|
|
43499
|
-
'grep/read when a tool returns found:false (ESPECIALLY reason:"unresolved" \u2014 the',
|
|
43500
|
-
"name was not recognized, NOT an empty answer; an empty list like callers:[] is a",
|
|
43501
|
-
'confident "none" \u2014 trust it), when you need EXACT bytes before a high-stakes',
|
|
43502
|
-
"edit, or for an unindexed file/language. Always confirm exact bytes with a read",
|
|
43503
|
-
"before editing.",
|
|
43504
|
-
"",
|
|
43505
|
-
"errata is a cloud knowledge substrate \u2014 AND ALSO this workspace's code graph.",
|
|
43506
|
-
"The problems you hit and the fixes you make become shared knowledge other agents",
|
|
43507
|
-
"recall. That capture is automatic: derived from your edits/commands/commits \u2014 no",
|
|
43508
|
-
"emit needed. Just after you resolve something a tool result may carry a one-line",
|
|
43509
|
-
"\u26A1 errata note asking the ROOT CAUSE; answer via errata.annotate_resolution when",
|
|
43510
|
-
"you know it, skip it otherwise.",
|
|
43511
|
-
"",
|
|
43512
|
-
"Two things it CAN'T derive \u2014 only you witness them, and this is a CAPTURE",
|
|
43513
|
-
"PROTOCOL, not optional formatting: a problem or fix you state only in prose, a",
|
|
43514
|
-
"list, or your own numbering is SILENTLY LOST \u2014 the tag is the ONLY thing recorded.",
|
|
43515
|
-
"So the moment you state one, wrap it inline (no fence, no extra call):",
|
|
43516
|
-
// Signal tokens come from the single source (agent-signals.ts) so this always-on
|
|
43517
|
-
// block can't teach a grammar the parser rejects. Referent is "its-id" here — the
|
|
43518
|
-
// raw MCP channel has no primed handles, so the agent cites a tool-result id.
|
|
43519
|
-
` \u2022 ${TAG_EXAMPLE.problem()} \u2014 EVERY problem you notice or report ([?\u2026] = TODO)`,
|
|
43520
|
-
` \u2022 ${TAG_EXAMPLE.fix("its-id")} \u2014 your edit fixed a problem errata showed you`,
|
|
43521
|
-
"Tag every one you state \u2014 we filter downstream, so don't self-censor or batch.",
|
|
43522
|
-
"",
|
|
43523
|
-
"Graph-as-files: the graph is ALSO a virtual FS \u2014 Read (or `cat`)",
|
|
43524
|
-
".errata/g/<verb>/<seed> to run a query as a file read (e.g. .errata/g/burst/",
|
|
43525
|
-
"<symbol>, /why/<sym>, /trace/<a>..<b>). Read .errata/g/index for the vocabulary."
|
|
43613
|
+
"errata is a live code and knowledge graph, a SEPARATE DIAGNOSTIC AXIS alongside grep/read for callers, blast radius, rename lineage and prior fixes. Fall back to read/search on found:false (unresolved is not an empty answer), or for unindexed code. Confirm exact bytes before editing.",
|
|
43614
|
+
buildAgentInstruction({ signals: ["prior", "problem", "vulnerability", "fix"], referent: "its-id" }),
|
|
43615
|
+
"Read .errata/g/index for graph-as-files query paths. A tool result may ask for a root cause; answer via errata.annotate_resolution when known."
|
|
43526
43616
|
].join("\n");
|
|
43527
43617
|
AUDIT_RUN_THRESHOLD = 5;
|
|
43528
43618
|
AUDIT_NUDGE_COOLDOWN = 12;
|
|
@@ -44114,7 +44204,7 @@ var init_mcp = __esm({
|
|
|
44114
44204
|
},
|
|
44115
44205
|
{
|
|
44116
44206
|
name: "errata.problems",
|
|
44117
|
-
description: "List the workspace's Problem backlog \u2014 the triage view that search/why/impact can't give because they need a seed. status: 'open' (default) | 'resolved' (a real fix) | 'retracted' (false alarms \u2014 false_positive/dissolution) | 'constraint' (design TENSIONS captured via `(constraint: \u2026)` \u2014 standing context, not open work, so they're excluded from 'open') | 'all'. Also returns a `retracted` breakdown so the false-positive rate stays visible.",
|
|
44207
|
+
description: "List the workspace's Problem and Vulnerability backlog \u2014 the triage view that search/why/impact can't give because they need a seed. status: 'open' (default) | 'resolved' (a real fix) | 'retracted' (false alarms \u2014 false_positive/dissolution) | 'constraint' (design TENSIONS captured via `(constraint: \u2026)` \u2014 standing context, not open work, so they're excluded from 'open') | 'all'. Also returns a `retracted` breakdown so the false-positive rate stays visible.",
|
|
44118
44208
|
inputSchema: {
|
|
44119
44209
|
type: "object",
|
|
44120
44210
|
properties: {
|
|
@@ -44126,13 +44216,15 @@ var init_mcp = __esm({
|
|
|
44126
44216
|
const want = String(args2["status"] ?? "open");
|
|
44127
44217
|
const limit = Math.max(1, Math.min(200, Number(args2["limit"] ?? 50)));
|
|
44128
44218
|
const RETRACTIONS = /* @__PURE__ */ new Set(["false_positive", "invalid", "duplicate"]);
|
|
44129
|
-
const rows = store.findAllVersionsByLabel("Problem").map((p) => {
|
|
44219
|
+
const rows = [...store.findAllVersionsByLabel("Problem"), ...store.findAllVersionsByLabel("Vulnerability")].map((p) => {
|
|
44130
44220
|
const ra = p.attrs["resolvedAs"];
|
|
44131
44221
|
const status = ra && RETRACTIONS.has(ra) ? ra : p.attrs["resolvedAt"] != null ? "resolved" : isConstraintProblem(p) ? "constraint" : "open";
|
|
44132
44222
|
const anchorEdge = store.outEdges(p.id, ["ANCHORED_AT"])[0];
|
|
44133
44223
|
const anchor = anchorEdge ? store.getNode(anchorEdge.to)?.description : void 0;
|
|
44134
44224
|
return {
|
|
44135
44225
|
id: p.id,
|
|
44226
|
+
label: p.label,
|
|
44227
|
+
...p.label === "Vulnerability" ? { assessment: p.attrs["assessment"] } : {},
|
|
44136
44228
|
problem: p.description,
|
|
44137
44229
|
status,
|
|
44138
44230
|
createdAt: p.createdAt,
|
|
@@ -52697,7 +52789,8 @@ function errorRecallTerms(errorText) {
|
|
|
52697
52789
|
}
|
|
52698
52790
|
function recallLine(n, token) {
|
|
52699
52791
|
const desc = (n.description ?? "").replace(/\s+/g, " ").slice(0, 120);
|
|
52700
|
-
|
|
52792
|
+
const label = n.label === "Vulnerability" ? `Vulnerability; ${n.attrs["assessment"] ?? "unassessed"}` : n.label;
|
|
52793
|
+
return `- [${label}] ${desc} \u2192 ${token}`;
|
|
52701
52794
|
}
|
|
52702
52795
|
function recallForFile(store, relPath) {
|
|
52703
52796
|
return fileRecall(store, relPath)?.context ?? null;
|
|
@@ -52718,7 +52811,7 @@ function fileRecall(store, relPath) {
|
|
|
52718
52811
|
const shownRelated = priors.related.slice(0, 4);
|
|
52719
52812
|
for (const p of shownProblems) {
|
|
52720
52813
|
const hasCause = store.outEdges(p.id, ["CAUSED_BY"]).some((e) => store.getNode(e.to)?.label === "RootCause");
|
|
52721
|
-
const causeCue = hasCause ? "" : ` \xB7 ${TAG_EXAMPLE.triageMint()} to diagnose its cause`;
|
|
52814
|
+
const causeCue = hasCause ? "" : ` \xB7 ${p.label === "Vulnerability" ? `(cause:#${p.id} the mechanism)` : TAG_EXAMPLE.triageMint()} to diagnose its cause`;
|
|
52722
52815
|
lines.push(
|
|
52723
52816
|
recallLine(p, `${TAG_EXAMPLE.fix(p.id)} if you resolved it \xB7 ${TAG_EXAMPLE.prior(p.id)} to cite${causeCue}`)
|
|
52724
52817
|
);
|
|
@@ -75988,7 +76081,7 @@ init_src5();
|
|
|
75988
76081
|
import { readFileSync as readFileSync17, writeFileSync as writeFileSync13 } from "node:fs";
|
|
75989
76082
|
var NEG = /n['']t|\b(?:not|never|no|none|neither|nor|unrelated|irrelevant|would|might|could|if)\b/i;
|
|
75990
76083
|
var CITE_GROUP_RE = /\(((?:[^()\n]|\([^()\n]*\)){1,200})\)/g;
|
|
75991
|
-
var HANDLE_RE = /\[([a-z0-9][\w-]{0,80})\]|((?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,})/gi;
|
|
76084
|
+
var HANDLE_RE = /\[([a-z0-9][\w-]{0,80})\]|((?:pat|sol|drc|dcause|dfix|dprob|dvuln|prob|claim|err)_[0-9a-f]{6,})/gi;
|
|
75992
76085
|
var PLACEHOLDER_HANDLES = /* @__PURE__ */ new Set([
|
|
75993
76086
|
"handle",
|
|
75994
76087
|
"its-handle",
|
|
@@ -76003,7 +76096,7 @@ var PLACEHOLDER_HANDLES = /* @__PURE__ */ new Set([
|
|
|
76003
76096
|
"b"
|
|
76004
76097
|
]);
|
|
76005
76098
|
var isPlaceholderHandle = (h) => PLACEHOLDER_HANDLES.has(h.toLowerCase());
|
|
76006
|
-
var FLAG_BODY_HANDLE_RE = /^(?:[a-z0-9]+(?:-[a-z0-9]+){2,}-(?=[0-9a-f]{0,3}\d)[0-9a-f]{4}|(?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,})$/i;
|
|
76099
|
+
var FLAG_BODY_HANDLE_RE = /^(?:[a-z0-9]+(?:-[a-z0-9]+){2,}-(?=[0-9a-f]{0,3}\d)[0-9a-f]{4}|(?:pat|sol|drc|dcause|dfix|dprob|dvuln|prob|claim|err)_[0-9a-f]{6,})$/i;
|
|
76007
76100
|
var FIX_PREFIX = /^\s*fix:(?:#([a-z][\w-]{0,63}))?\s*/i;
|
|
76008
76101
|
var CONSTRAINT_RE = /\(\s*constraint:\s*([^()\n]{8,}?)\s*\)/gi;
|
|
76009
76102
|
var CAUSE_PREFIX = /^\s*cause:(?:#([a-z][\w-]{0,63}))?\s*/i;
|
|
@@ -76028,7 +76121,7 @@ var DOMAIN_RE = /\(\s*domain:\s*([^()\n]{3,}?)\s*\)/gi;
|
|
|
76028
76121
|
var PACKAGE_RE = /\(\s*package:\s*([^()\n]{2,}?)\s*\)/gi;
|
|
76029
76122
|
var COMPONENT_RE = /\(\s*component:\s*([^()\n]{2,}?)\s*\)/gi;
|
|
76030
76123
|
var CAUSE_TEXT_MIN = 8;
|
|
76031
|
-
var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*((?:\[[^\]\n]*\]|[^\]\n])
|
|
76124
|
+
var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*((?:\[[^\]\n]*\]|[^\]\n])*?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g;
|
|
76032
76125
|
var CONSTRAINT_MIN = 8;
|
|
76033
76126
|
function clauseBefore(sentence, idx) {
|
|
76034
76127
|
const win = sentence.slice(Math.max(0, idx - 80), idx);
|
|
@@ -76172,6 +76265,7 @@ function cleanEmittedTags(tags) {
|
|
|
76172
76265
|
}
|
|
76173
76266
|
function emptyTagDispositions() {
|
|
76174
76267
|
return {
|
|
76268
|
+
invalidVulnerability: 0,
|
|
76175
76269
|
oversizeSegments: 0,
|
|
76176
76270
|
codeSpanNeutralized: 0,
|
|
76177
76271
|
refuteTooShort: 0,
|
|
@@ -76184,6 +76278,7 @@ function emptyTagDispositions() {
|
|
|
76184
76278
|
};
|
|
76185
76279
|
}
|
|
76186
76280
|
function addTagDispositions(a, b) {
|
|
76281
|
+
a.invalidVulnerability += b.invalidVulnerability;
|
|
76187
76282
|
a.oversizeSegments += b.oversizeSegments;
|
|
76188
76283
|
a.codeSpanNeutralized += b.codeSpanNeutralized;
|
|
76189
76284
|
a.refuteTooShort += b.refuteTooShort;
|
|
@@ -76197,12 +76292,31 @@ function addTagDispositions(a, b) {
|
|
|
76197
76292
|
function parseInlineTags(text) {
|
|
76198
76293
|
return parseInlineTagsWithDispositions(text).tags;
|
|
76199
76294
|
}
|
|
76295
|
+
function* captureSentences(text) {
|
|
76296
|
+
for (const line of text.split(/\n+/)) {
|
|
76297
|
+
if (line.length > 2e4) {
|
|
76298
|
+
yield line;
|
|
76299
|
+
continue;
|
|
76300
|
+
}
|
|
76301
|
+
const flags2 = [...line.matchAll(new RegExp(FLAG_RE.source, FLAG_RE.flags))].map((m) => ({ start: m.index, end: m.index + m[0].length }));
|
|
76302
|
+
let flag = 0;
|
|
76303
|
+
let start2 = 0;
|
|
76304
|
+
for (const boundary of line.matchAll(/(?<=[.!?])\s+(?!\(fix:)/g)) {
|
|
76305
|
+
const index = boundary.index;
|
|
76306
|
+
while (flags2[flag] && flags2[flag].end <= index) flag++;
|
|
76307
|
+
if (flags2[flag] && flags2[flag].start < index) continue;
|
|
76308
|
+
yield line.slice(start2, index);
|
|
76309
|
+
start2 = index + boundary[0].length;
|
|
76310
|
+
}
|
|
76311
|
+
yield line.slice(start2);
|
|
76312
|
+
}
|
|
76313
|
+
}
|
|
76200
76314
|
function parseInlineTagsWithDispositions(text) {
|
|
76201
76315
|
const out2 = [];
|
|
76202
76316
|
const dispositions = emptyTagDispositions();
|
|
76203
76317
|
const deFenced = text.replace(/```[\s\S]*?```/g, " ");
|
|
76204
76318
|
let seqNo = -1;
|
|
76205
|
-
for (const raw2 of deFenced
|
|
76319
|
+
for (const raw2 of captureSentences(deFenced)) {
|
|
76206
76320
|
seqNo++;
|
|
76207
76321
|
if (raw2.length > 2e4) {
|
|
76208
76322
|
dispositions.oversizeSegments++;
|
|
@@ -76428,6 +76542,29 @@ function parseInlineTagsWithDispositions(text) {
|
|
|
76428
76542
|
while ((f = FLAG_RE.exec(sentence)) !== null) {
|
|
76429
76543
|
const flagThread = f[2];
|
|
76430
76544
|
const raw3 = f[3].trim();
|
|
76545
|
+
if (/^vuln\b/i.test(raw3)) {
|
|
76546
|
+
const typed = /^vuln:\s*([\s\S]*)$/i.exec(raw3);
|
|
76547
|
+
const body2 = typed?.[1]?.trim() ?? "";
|
|
76548
|
+
const parts2 = body2.split(CAUSE_ARROW).map((s) => s.trim());
|
|
76549
|
+
const symptom = f[1] === "!" && parts2.length > 1 && !f[4] ? new RegExp(FLAG_RE.source, "i").exec(`[!${parts2[0]}]`) : null;
|
|
76550
|
+
const statement = f[1] === "?" ? body2 : symptom?.[3]?.trim() ?? parts2[0];
|
|
76551
|
+
if (statement.length < 8 || /^<[^>]*>$/.test(statement)) {
|
|
76552
|
+
dispositions.invalidVulnerability++;
|
|
76553
|
+
continue;
|
|
76554
|
+
}
|
|
76555
|
+
const path2 = (f[4] ?? symptom?.[4])?.trim();
|
|
76556
|
+
const line = f[5] ?? symptom?.[5];
|
|
76557
|
+
out2.push({
|
|
76558
|
+
kind: "vulnerability",
|
|
76559
|
+
statement,
|
|
76560
|
+
assessment: f[1] === "!" ? "asserted" : "suspected",
|
|
76561
|
+
...f[1] === "!" && parts2.length > 1 ? { vulnerabilityCauses: parts2.slice(1).filter((s) => s.length >= CAUSE_TEXT_MIN) } : {},
|
|
76562
|
+
...path2 ? { location: { path: path2, ...line ? { line: Number(line) } : {} } } : {},
|
|
76563
|
+
...flagThread ? { threadId: flagThread } : {},
|
|
76564
|
+
sentence: sfield
|
|
76565
|
+
});
|
|
76566
|
+
continue;
|
|
76567
|
+
}
|
|
76431
76568
|
if (FLAG_BODY_HANDLE_RE.test(raw3) && !f[4]) {
|
|
76432
76569
|
dispositions.flagAsHandle++;
|
|
76433
76570
|
out2.push({ kind: "prior", handle: raw3, sentence: sfield });
|
|
@@ -76798,7 +76935,7 @@ function harvestInlineTags(store, text, opts) {
|
|
|
76798
76935
|
const parsed = parseInlineTagsWithDispositions(text);
|
|
76799
76936
|
const tags = parsed.tags;
|
|
76800
76937
|
plan.dispositions = parsed.dispositions;
|
|
76801
|
-
const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo") && t.statement).map((t) => ({ seq: t.seq ?? -1, statement: t.statement, threadId: t.threadId })).sort((a, b) => a.seq - b.seq);
|
|
76938
|
+
const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo" || t.kind === "vulnerability") && t.statement).map((t) => ({ seq: t.seq ?? -1, statement: t.statement, threadId: t.threadId, kind: t.kind })).sort((a, b) => a.seq - b.seq);
|
|
76802
76939
|
const bindSymptom = (seq, threadId) => {
|
|
76803
76940
|
if (threadId) {
|
|
76804
76941
|
const hit = symptomSeqs.find((s) => s.threadId === threadId);
|
|
@@ -76811,6 +76948,7 @@ function harvestInlineTags(store, text, opts) {
|
|
|
76811
76948
|
if (seq == null) return { evidence: "inferred" };
|
|
76812
76949
|
let best;
|
|
76813
76950
|
for (const s of symptomSeqs) {
|
|
76951
|
+
if (s.kind === "vulnerability") continue;
|
|
76814
76952
|
if (s.seq <= seq) best = s;
|
|
76815
76953
|
else break;
|
|
76816
76954
|
}
|
|
@@ -76825,10 +76963,13 @@ function harvestInlineTags(store, text, opts) {
|
|
|
76825
76963
|
return id;
|
|
76826
76964
|
};
|
|
76827
76965
|
for (const tag of tags) {
|
|
76828
|
-
if (tag.kind === "problem" || tag.kind === "todo") {
|
|
76966
|
+
if (tag.kind === "problem" || tag.kind === "todo" || tag.kind === "vulnerability") {
|
|
76829
76967
|
plan.problems.push({
|
|
76830
76968
|
statement: tag.statement,
|
|
76831
76969
|
kind: tag.kind,
|
|
76970
|
+
...tag.assessment ? { assessment: tag.assessment } : {},
|
|
76971
|
+
...tag.vulnerabilityCauses ? { vulnerabilityCauses: tag.vulnerabilityCauses } : {},
|
|
76972
|
+
...tag.kind === "vulnerability" && tag.seq !== void 0 ? { seq: tag.seq } : {},
|
|
76832
76973
|
...tag.location ? { location: tag.location } : {},
|
|
76833
76974
|
...tag.threadId ? { threadId: tag.threadId } : {}
|
|
76834
76975
|
});
|
|
@@ -76851,7 +76992,7 @@ function harvestInlineTags(store, text, opts) {
|
|
|
76851
76992
|
} else if (tag.threadId && !b.statement) {
|
|
76852
76993
|
plan.fixes.push({ inScope: true, fixNote: tag.fixRationale, threadId: tag.threadId });
|
|
76853
76994
|
} else if (b.statement && b.evidence === "witnessed") {
|
|
76854
|
-
plan.fixes.push({ inScope: true, fixNote: tag.fixRationale, boundStatement: b.statement });
|
|
76995
|
+
plan.fixes.push({ inScope: true, fixNote: tag.fixRationale, boundStatement: b.statement, ...tag.threadId ? { threadId: tag.threadId } : {} });
|
|
76855
76996
|
} else {
|
|
76856
76997
|
plan.fixes.push({ inScope: true, fixNote: tag.fixRationale, ambiguous: true });
|
|
76857
76998
|
}
|
|
@@ -77054,6 +77195,7 @@ function harvestInlineTags(store, text, opts) {
|
|
|
77054
77195
|
}
|
|
77055
77196
|
var CORROBORATABLE_LABELS = /* @__PURE__ */ new Set([
|
|
77056
77197
|
"Problem",
|
|
77198
|
+
"Vulnerability",
|
|
77057
77199
|
"Solution",
|
|
77058
77200
|
"RootCause",
|
|
77059
77201
|
"Pattern",
|
|
@@ -77746,6 +77888,15 @@ var PassWorker = class {
|
|
|
77746
77888
|
nightly() {
|
|
77747
77889
|
return this.call("nightly");
|
|
77748
77890
|
}
|
|
77891
|
+
semanticMaintenance() {
|
|
77892
|
+
return this.call("semanticMaintenance");
|
|
77893
|
+
}
|
|
77894
|
+
liveness(invocations) {
|
|
77895
|
+
return this.call("liveness", [...invocations]);
|
|
77896
|
+
}
|
|
77897
|
+
retrievalInputs(repoLocator) {
|
|
77898
|
+
return this.call("retrievalInputs", repoLocator);
|
|
77899
|
+
}
|
|
77749
77900
|
/** Reindex stale/drifted files on the worker; resolves to the count reindexed. */
|
|
77750
77901
|
reconcile() {
|
|
77751
77902
|
return this.call("reconcile");
|
|
@@ -78873,6 +79024,13 @@ function scanManifests(root) {
|
|
|
78873
79024
|
function readManifestDependencies(root) {
|
|
78874
79025
|
return scanManifests(root).deps;
|
|
78875
79026
|
}
|
|
79027
|
+
function readRetrievalInputs(root, repoLocator) {
|
|
79028
|
+
return {
|
|
79029
|
+
direct: readDirectDependencies(root),
|
|
79030
|
+
manifestDeps: readManifestDependencies(root),
|
|
79031
|
+
registry: loadRegistryPolicy(root, process.env, repoLocator)
|
|
79032
|
+
};
|
|
79033
|
+
}
|
|
78876
79034
|
|
|
78877
79035
|
// src/git-sensor.ts
|
|
78878
79036
|
import { existsSync as existsSync23, readFileSync as readFileSync23, watch as fsWatch } from "node:fs";
|
|
@@ -80832,9 +80990,9 @@ function partitionReplayable(queue, channel, isShipped) {
|
|
|
80832
80990
|
function retireWitnesses(queue, channel, settledKeys) {
|
|
80833
80991
|
return queue.filter((w) => !(w.channel === channel && settledKeys.has(w.witnessKey)));
|
|
80834
80992
|
}
|
|
80835
|
-
var WIRE_SHIPPED_LABELS = /* @__PURE__ */ new Set(["Problem", "Solution", "RootCause"]);
|
|
80993
|
+
var WIRE_SHIPPED_LABELS = /* @__PURE__ */ new Set(["Problem", "Vulnerability", "Solution", "RootCause"]);
|
|
80836
80994
|
var MOTIF_ID_PREFIX = "motif_community_";
|
|
80837
|
-
var CANONICAL_ID_RE = /^(?:pat|sol|drc|dcause|dfix|dprob|prob|claim|err)_[0-9a-f]{6,}$/i;
|
|
80995
|
+
var CANONICAL_ID_RE = /^(?:pat|sol|drc|dcause|dfix|dprob|dvuln|prob|claim|err)_[0-9a-f]{6,}$/i;
|
|
80838
80996
|
function classifyWitnessTarget(nodeId, getNode) {
|
|
80839
80997
|
if (nodeId.startsWith(MOTIF_ID_PREFIX)) {
|
|
80840
80998
|
const exemplar = nodeId.slice(MOTIF_ID_PREFIX.length);
|
|
@@ -81241,11 +81399,13 @@ function saveAlarmState(configDir, state) {
|
|
|
81241
81399
|
}
|
|
81242
81400
|
function createLivenessWatch(deps) {
|
|
81243
81401
|
let lastRunAt = 0;
|
|
81402
|
+
let running = false;
|
|
81244
81403
|
const lastAlarmedAt = loadAlarmState(deps.configDir);
|
|
81245
81404
|
return {
|
|
81246
|
-
maybeRun(nowMs = Date.now()) {
|
|
81247
|
-
if (nowMs - lastRunAt < LIVENESS_WATCH_INTERVAL_MS) return null;
|
|
81405
|
+
async maybeRun(nowMs = Date.now()) {
|
|
81406
|
+
if (running || nowMs - lastRunAt < LIVENESS_WATCH_INTERVAL_MS) return null;
|
|
81248
81407
|
lastRunAt = nowMs;
|
|
81408
|
+
running = true;
|
|
81249
81409
|
try {
|
|
81250
81410
|
const started2 = Date.now();
|
|
81251
81411
|
const invocations = /* @__PURE__ */ new Map();
|
|
@@ -81259,7 +81419,7 @@ function createLivenessWatch(deps) {
|
|
|
81259
81419
|
lastTotals: s.lastTotals
|
|
81260
81420
|
});
|
|
81261
81421
|
}
|
|
81262
|
-
const rows = evaluateMechanisms(deps.store, invocations);
|
|
81422
|
+
const rows = deps.evaluate ? await deps.evaluate(invocations) : evaluateMechanisms(deps.store, invocations);
|
|
81263
81423
|
const workspaceActive = invocations.has("capture") || invocations.has("render");
|
|
81264
81424
|
const bad = workspaceActive ? rows.filter((r) => hasStarvedMechanism([r])) : [];
|
|
81265
81425
|
const watch3 = watchCensus();
|
|
@@ -81296,13 +81456,42 @@ function createLivenessWatch(deps) {
|
|
|
81296
81456
|
}
|
|
81297
81457
|
}
|
|
81298
81458
|
return rows;
|
|
81299
|
-
} catch {
|
|
81459
|
+
} catch (err2) {
|
|
81460
|
+
console.warn("[errata] liveness watch failed:", err2 instanceof Error ? err2.message : String(err2));
|
|
81300
81461
|
return null;
|
|
81462
|
+
} finally {
|
|
81463
|
+
running = false;
|
|
81301
81464
|
}
|
|
81302
81465
|
}
|
|
81303
81466
|
};
|
|
81304
81467
|
}
|
|
81305
81468
|
|
|
81469
|
+
// src/workspace-maintenance.ts
|
|
81470
|
+
init_src8();
|
|
81471
|
+
init_src5();
|
|
81472
|
+
function runWorkspaceMaintenance(store, workspaceId2) {
|
|
81473
|
+
const seqBefore = store.currentIngestSeq();
|
|
81474
|
+
const report = runSemanticMaintenance(store);
|
|
81475
|
+
let hintUpgrade = { upgraded: 0, standing: 0, unresolvable: 0, blocked: 0 };
|
|
81476
|
+
try {
|
|
81477
|
+
hintUpgrade = upgradeAnchorHints(store, workspaceId2, Date.now());
|
|
81478
|
+
} catch {
|
|
81479
|
+
}
|
|
81480
|
+
let calibration = null;
|
|
81481
|
+
const calibrationStarted = Date.now();
|
|
81482
|
+
try {
|
|
81483
|
+
calibration = wmCalibrationCells(store);
|
|
81484
|
+
} catch {
|
|
81485
|
+
}
|
|
81486
|
+
return {
|
|
81487
|
+
report,
|
|
81488
|
+
hintUpgrade,
|
|
81489
|
+
seqAdvanced: store.currentIngestSeq() - seqBefore,
|
|
81490
|
+
calibration,
|
|
81491
|
+
calibrationMs: Date.now() - calibrationStarted
|
|
81492
|
+
};
|
|
81493
|
+
}
|
|
81494
|
+
|
|
81306
81495
|
// src/watch-breaker.ts
|
|
81307
81496
|
function numEnv3(key, fallback) {
|
|
81308
81497
|
const n = Number(process.env[key]);
|
|
@@ -81404,7 +81593,7 @@ function createWatchBreaker(deps) {
|
|
|
81404
81593
|
}
|
|
81405
81594
|
|
|
81406
81595
|
// src/engine.ts
|
|
81407
|
-
var DAEMON_VERSION = true ? "2.0.
|
|
81596
|
+
var DAEMON_VERSION = true ? "2.0.17-dev.3407" : "2.0.0-alpha.0";
|
|
81408
81597
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
81409
81598
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
81410
81599
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -81791,6 +81980,7 @@ function createWorkspaceEngine(opts) {
|
|
|
81791
81980
|
const livenessWatch = createLivenessWatch({
|
|
81792
81981
|
configDir: paths.configDir,
|
|
81793
81982
|
store,
|
|
81983
|
+
...passWorker ? { evaluate: (invocations) => passWorker.liveness(invocations) } : {},
|
|
81794
81984
|
onAlarm: (id, line) => {
|
|
81795
81985
|
console.warn(`[errata] mechanism not working: ${line}`);
|
|
81796
81986
|
notifyEvent("mechanism-stalled", line, { key: id });
|
|
@@ -81956,21 +82146,22 @@ function createWorkspaceEngine(opts) {
|
|
|
81956
82146
|
contextDirty = false;
|
|
81957
82147
|
notifyDigest("recall");
|
|
81958
82148
|
};
|
|
81959
|
-
const outboundStack = () =>
|
|
81960
|
-
|
|
81961
|
-
|
|
81962
|
-
|
|
81963
|
-
|
|
81964
|
-
|
|
81965
|
-
|
|
81966
|
-
|
|
81967
|
-
|
|
81968
|
-
|
|
81969
|
-
|
|
81970
|
-
|
|
81971
|
-
|
|
81972
|
-
|
|
81973
|
-
|
|
82149
|
+
const outboundStack = async () => {
|
|
82150
|
+
const inputs = passWorker ? await passWorker.retrievalInputs(profile?.repoLocator) : readRetrievalInputs(opts.workspaceRoot, profile?.repoLocator);
|
|
82151
|
+
return retrievalStackTokens({
|
|
82152
|
+
...inputs,
|
|
82153
|
+
profileStack: profile?.stack ?? [],
|
|
82154
|
+
// Languages ride the stack list: the cloud's context-affinity matcher
|
|
82155
|
+
// resolves each token against both the Package and Language namespaces,
|
|
82156
|
+
// and the profile keeps them in separate fields.
|
|
82157
|
+
languages: profile?.languages ?? [],
|
|
82158
|
+
contributePackages: consentNow().contributePackages,
|
|
82159
|
+
// `repoLocator` feeds the Maven self-disclosure rule ONLY: a groupId
|
|
82160
|
+
// carrying this project's own owner/repo token is the project naming
|
|
82161
|
+
// itself, not a library it depends on.
|
|
82162
|
+
ignorePatterns: loadClaimIgnorePatterns(opts.workspaceRoot)
|
|
82163
|
+
}).tokens;
|
|
82164
|
+
};
|
|
81974
82165
|
const maybeRefreshRemotePriors = () => {
|
|
81975
82166
|
if (opts.skipContextWriter || remoteInFlight) return;
|
|
81976
82167
|
const now = Date.now();
|
|
@@ -81980,11 +82171,12 @@ function createWorkspaceEngine(opts) {
|
|
|
81980
82171
|
if (typeof cloud.search !== "function") return;
|
|
81981
82172
|
remoteInFlight = true;
|
|
81982
82173
|
lastRemoteAt = now;
|
|
81983
|
-
|
|
82174
|
+
void outboundStack().then((stack) => {
|
|
82175
|
+
if (!(opts.syncConsent ?? consentNow().sync)) return;
|
|
81984
82176
|
const norm = normStackTokens;
|
|
81985
82177
|
const seed = store.recentNodeIds("Problem", 6);
|
|
81986
82178
|
const q = {
|
|
81987
|
-
stack
|
|
82179
|
+
stack,
|
|
81988
82180
|
domains: norm(profile.domains),
|
|
81989
82181
|
kinds: ["Pattern", "Technique", "AntiPattern"],
|
|
81990
82182
|
...seed.length ? { seed } : {},
|
|
@@ -81994,7 +82186,7 @@ function createWorkspaceEngine(opts) {
|
|
|
81994
82186
|
channel: "priming",
|
|
81995
82187
|
limit: 8
|
|
81996
82188
|
};
|
|
81997
|
-
cloud.search(q).then((res) => {
|
|
82189
|
+
return cloud.search(q).then((res) => {
|
|
81998
82190
|
remotePriors = res.nodes ?? [];
|
|
81999
82191
|
const contributorLabels = [];
|
|
82000
82192
|
for (const n of remotePriors) {
|
|
@@ -82004,13 +82196,11 @@ function createWorkspaceEngine(opts) {
|
|
|
82004
82196
|
}
|
|
82005
82197
|
if (contributorLabels.length > 0) registerRenderedContributorLabels(contributorLabels);
|
|
82006
82198
|
contextDirty = true;
|
|
82007
|
-
}).catch(() => {
|
|
82008
|
-
}).finally(() => {
|
|
82009
|
-
remoteInFlight = false;
|
|
82010
82199
|
});
|
|
82011
|
-
}
|
|
82200
|
+
}).catch(() => {
|
|
82201
|
+
}).finally(() => {
|
|
82012
82202
|
remoteInFlight = false;
|
|
82013
|
-
}
|
|
82203
|
+
});
|
|
82014
82204
|
};
|
|
82015
82205
|
const maybeRefreshIntentPriors = (liveIntent) => {
|
|
82016
82206
|
if (!liveIntent || opts.skipContextWriter || intentRemoteInFlight) return;
|
|
@@ -82019,22 +82209,26 @@ function createWorkspaceEngine(opts) {
|
|
|
82019
82209
|
if (!syncOk) return;
|
|
82020
82210
|
if (typeof cloud.search !== "function") return;
|
|
82021
82211
|
intentRemoteInFlight = true;
|
|
82022
|
-
|
|
82023
|
-
|
|
82024
|
-
|
|
82025
|
-
|
|
82026
|
-
|
|
82027
|
-
|
|
82028
|
-
|
|
82029
|
-
|
|
82030
|
-
|
|
82031
|
-
|
|
82032
|
-
|
|
82033
|
-
|
|
82034
|
-
|
|
82035
|
-
|
|
82036
|
-
|
|
82212
|
+
void outboundStack().then((stack) => {
|
|
82213
|
+
if (!(opts.syncConsent ?? consentNow().sync)) return;
|
|
82214
|
+
return cloud.search({
|
|
82215
|
+
// VS-context-affinity: the intent lane used to send an empty context
|
|
82216
|
+
// while the priming lane sent the profile — opposite postures on the
|
|
82217
|
+
// same method. Under "union derived + stated, canonicalize once"
|
|
82218
|
+
// (VS-intent-fence) the stated intent IS the query and the derived
|
|
82219
|
+
// stack rides along as structured relevanceContext: the cloud no
|
|
82220
|
+
// longer concatenates these tokens into the embedding string, it
|
|
82221
|
+
// re-weights anchored hits with them (stated beats derived — the
|
|
82222
|
+
// intent text drives entry search, the stack only re-ranks).
|
|
82223
|
+
stack,
|
|
82224
|
+
domains: normStackTokens(profile?.domains ?? []),
|
|
82225
|
+
kinds: ["Pattern", "Technique", "AntiPattern", "Problem", "Solution"],
|
|
82226
|
+
q: liveIntent,
|
|
82227
|
+
channel: "intent",
|
|
82228
|
+
limit: 6
|
|
82229
|
+
});
|
|
82037
82230
|
}).then((res) => {
|
|
82231
|
+
if (!res) return;
|
|
82038
82232
|
intentRemote = {
|
|
82039
82233
|
forIntent: liveIntent,
|
|
82040
82234
|
hits: res.nodes ?? [],
|
|
@@ -82094,7 +82288,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82094
82288
|
if (isWorkerOom(err2)) {
|
|
82095
82289
|
console.warn("[errata] nightly worker hit its heap ceiling \u2014 heavy pass skipped this fire");
|
|
82096
82290
|
appendPassLedger(paths.configDir, "graph-rescore", 0, { oomSkipped: 1 });
|
|
82097
|
-
const sem =
|
|
82291
|
+
const { report: sem } = await passWorker.semanticMaintenance();
|
|
82098
82292
|
return {
|
|
82099
82293
|
report: {
|
|
82100
82294
|
scoredNodes: 0,
|
|
@@ -82296,6 +82490,9 @@ function createWorkspaceEngine(opts) {
|
|
|
82296
82490
|
const harvestTextsInner = async (sessionId, items) => {
|
|
82297
82491
|
let minted = 0;
|
|
82298
82492
|
let tagsSeen = 0;
|
|
82493
|
+
let vulnerabilitiesSeen = 0;
|
|
82494
|
+
let vulnerabilitiesMinted = 0;
|
|
82495
|
+
let vulnerabilitiesSuspected = 0;
|
|
82299
82496
|
let tagsRejected = 0;
|
|
82300
82497
|
let tagsRestated = 0;
|
|
82301
82498
|
let resolved = 0;
|
|
@@ -82526,10 +82723,73 @@ function createWorkspaceEngine(opts) {
|
|
|
82526
82723
|
if ((toolRuns.get(sessionId)?.size ?? 0) > 0) touchedToolTurns++;
|
|
82527
82724
|
const wf = workingFiles.get(sessionId);
|
|
82528
82725
|
let inScopeProblemId;
|
|
82726
|
+
const findingIds = /* @__PURE__ */ new Map();
|
|
82727
|
+
const conflictingThreads = /* @__PURE__ */ new Set();
|
|
82529
82728
|
const threads = sessionThreads.get(sessionId) ?? /* @__PURE__ */ new Map();
|
|
82530
82729
|
sessionThreads.set(sessionId, threads);
|
|
82531
82730
|
for (const p of plan.problems) {
|
|
82532
82731
|
tagsSeen++;
|
|
82732
|
+
if (p.kind === "vulnerability") {
|
|
82733
|
+
vulnerabilitiesSeen++;
|
|
82734
|
+
if (p.assessment === "suspected") vulnerabilitiesSuspected++;
|
|
82735
|
+
let fileText;
|
|
82736
|
+
let anchorReadFailed = false;
|
|
82737
|
+
if (p.location) {
|
|
82738
|
+
try {
|
|
82739
|
+
fileText = readFileSync31(join35(opts.workspaceRoot, p.location.path), "utf8");
|
|
82740
|
+
} catch {
|
|
82741
|
+
anchorReadFailed = true;
|
|
82742
|
+
}
|
|
82743
|
+
}
|
|
82744
|
+
const result = ingestWitnessedVulnerability(store, {
|
|
82745
|
+
statement: p.statement,
|
|
82746
|
+
assessment: p.assessment,
|
|
82747
|
+
target: p.location?.path,
|
|
82748
|
+
line: p.location?.line,
|
|
82749
|
+
fileText,
|
|
82750
|
+
existingId: p.threadId ? threads.get(p.threadId) ?? handleMap[p.threadId]?.id ?? store.getNode(p.threadId)?.id : void 0
|
|
82751
|
+
}, { workspaceId: profile.id, source: sessionId, ts: t, hostHarness: turn.hostHarness });
|
|
82752
|
+
let anchorDisposition = p.location ? "unresolved" : "absent";
|
|
82753
|
+
if (result.rejected) {
|
|
82754
|
+
tagsRejected++;
|
|
82755
|
+
if (p.threadId) conflictingThreads.add(p.threadId);
|
|
82756
|
+
} else {
|
|
82757
|
+
findingIds.set(p.statement, result.id);
|
|
82758
|
+
if (p.threadId) threads.set(p.threadId, result.id);
|
|
82759
|
+
if (result.created || result.corroborated || result.upgraded) minted++;
|
|
82760
|
+
else tagsRestated++;
|
|
82761
|
+
if (result.created) vulnerabilitiesMinted++;
|
|
82762
|
+
if (p.location) {
|
|
82763
|
+
try {
|
|
82764
|
+
const anchored = anchorProblemToWorkingFile(store, result.id, p.location.path, profile.id, t, "witnessed", { line: p.location.line, fileText });
|
|
82765
|
+
anchorDisposition = anchored ? "resolved" : anchorReadFailed ? "error" : "unresolved";
|
|
82766
|
+
if (anchored) deriveContextFromAnchors(store, result.id, t);
|
|
82767
|
+
} catch {
|
|
82768
|
+
anchorDisposition = "error";
|
|
82769
|
+
}
|
|
82770
|
+
}
|
|
82771
|
+
const node2 = store.getNode(result.id);
|
|
82772
|
+
store.updateNode(result.id, { attrs: { ...node2.attrs, anchorDisposition } });
|
|
82773
|
+
if (p.vulnerabilityCauses) triaged += recordVulnerabilityCause(store, result.id, p.vulnerabilityCauses, t);
|
|
82774
|
+
}
|
|
82775
|
+
log.append({
|
|
82776
|
+
kind: "vulnerability.witness",
|
|
82777
|
+
workspaceId: profile.id,
|
|
82778
|
+
ts: t,
|
|
82779
|
+
digest: digest({ kind: "vulnerability.witness", workspaceId: profile.id, sessionId, turnId: turn.uuid, statement: p.statement, assessment: p.assessment, location: p.location }),
|
|
82780
|
+
sessionId,
|
|
82781
|
+
turnId: turn.uuid,
|
|
82782
|
+
harness: turn.hostHarness,
|
|
82783
|
+
findingId: result.id,
|
|
82784
|
+
statement: p.statement,
|
|
82785
|
+
assessment: p.assessment,
|
|
82786
|
+
location: p.location,
|
|
82787
|
+
seq: p.seq,
|
|
82788
|
+
anchorDisposition,
|
|
82789
|
+
disposition: result.rejected ?? (result.created ? "created" : result.upgraded ? "upgraded" : result.corroborated ? "corroborated" : "restated")
|
|
82790
|
+
});
|
|
82791
|
+
continue;
|
|
82792
|
+
}
|
|
82533
82793
|
const anchorPath = p.location?.path ?? editedTurnFile;
|
|
82534
82794
|
const anchorProvenance = p.location?.path ? "witnessed" : "edited";
|
|
82535
82795
|
const hintPath = anchorPath ? void 0 : turnFile ?? wf;
|
|
@@ -82624,10 +82884,10 @@ function createWorkspaceEngine(opts) {
|
|
|
82624
82884
|
if (r.created || r.corroborated) {
|
|
82625
82885
|
minted++;
|
|
82626
82886
|
if (p.kind !== "constraint") {
|
|
82627
|
-
sessionLastProblem.set(sessionId,
|
|
82628
|
-
inScopeProblemId =
|
|
82887
|
+
sessionLastProblem.set(sessionId, r.problemId);
|
|
82888
|
+
inScopeProblemId = r.problemId;
|
|
82629
82889
|
}
|
|
82630
|
-
if (p.threadId) threads.set(p.threadId,
|
|
82890
|
+
if (p.threadId) threads.set(p.threadId, r.problemId);
|
|
82631
82891
|
try {
|
|
82632
82892
|
if (anchorPath) {
|
|
82633
82893
|
let enclosing = {};
|
|
@@ -82664,7 +82924,8 @@ function createWorkspaceEngine(opts) {
|
|
|
82664
82924
|
);
|
|
82665
82925
|
}
|
|
82666
82926
|
for (const fx of plan.fixes) {
|
|
82667
|
-
|
|
82927
|
+
if (fx.threadId && conflictingThreads.has(fx.threadId)) continue;
|
|
82928
|
+
const pid = fx.problemId ?? (fx.threadId ? threads.get(fx.threadId) : void 0) ?? (fx.boundStatement ? findingIds.get(fx.boundStatement) ?? designProblemId(fx.boundStatement) : void 0);
|
|
82668
82929
|
if (!pid) {
|
|
82669
82930
|
if (fx.inScope) {
|
|
82670
82931
|
console.warn(
|
|
@@ -82676,7 +82937,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82676
82937
|
const closed = resolveDesignProblemById(store, pid, fx.fixNote, t);
|
|
82677
82938
|
if (!closed) {
|
|
82678
82939
|
const n = store.getNode(pid);
|
|
82679
|
-
if (!n || n.label !== "Problem" || n.attrs["resolvedAs"] != null) {
|
|
82940
|
+
if (!n || n.label !== "Problem" && n.label !== "Vulnerability" || n.attrs["resolvedAs"] != null) {
|
|
82680
82941
|
console.warn(
|
|
82681
82942
|
`[errata] fix tag went nowhere: ${!n ? `id ${pid.slice(0, 32)} unknown` : n.label !== "Problem" ? `${pid.slice(0, 32)} is a ${n.label}, not a Problem` : "the problem was retracted \u2014 a retraction is not fixable"} \u2014 the fix was NOT recorded`
|
|
82682
82943
|
);
|
|
@@ -82695,10 +82956,23 @@ function createWorkspaceEngine(opts) {
|
|
|
82695
82956
|
}
|
|
82696
82957
|
}
|
|
82697
82958
|
}
|
|
82959
|
+
const vulnerabilityTriages = /* @__PURE__ */ new Set();
|
|
82960
|
+
for (const tr of plan.triages) {
|
|
82961
|
+
if (tr.threadId && conflictingThreads.has(tr.threadId)) {
|
|
82962
|
+
vulnerabilityTriages.add(tr);
|
|
82963
|
+
continue;
|
|
82964
|
+
}
|
|
82965
|
+
const id = tr.symptomProblemId ?? (tr.threadId ? threads.get(tr.threadId) : void 0) ?? (tr.symptomStatement ? findingIds.get(tr.symptomStatement) : void 0);
|
|
82966
|
+
if (id && store.getNode(id)?.label === "Vulnerability") {
|
|
82967
|
+
vulnerabilityTriages.add(tr);
|
|
82968
|
+
if (tr.evidence === "witnessed" && tr.causeDescription) triaged += recordVulnerabilityCause(store, id, [tr.causeDescription], t);
|
|
82969
|
+
}
|
|
82970
|
+
}
|
|
82698
82971
|
if (opts.sharedStore && plan.triages.length > 0) {
|
|
82699
82972
|
const fallbackId = sessionLastProblem.get(sessionId);
|
|
82700
82973
|
const fallbackStatement = fallbackId ? store.getNode(fallbackId)?.description : void 0;
|
|
82701
82974
|
for (const tr of plan.triages) {
|
|
82975
|
+
if (vulnerabilityTriages.has(tr)) continue;
|
|
82702
82976
|
let presentingStatement = tr.symptomStatement;
|
|
82703
82977
|
let evidence = tr.evidence;
|
|
82704
82978
|
if (!presentingStatement && tr.threadId) {
|
|
@@ -82716,7 +82990,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82716
82990
|
evidence = "inferred";
|
|
82717
82991
|
}
|
|
82718
82992
|
if (!presentingStatement) continue;
|
|
82719
|
-
const presentingId = tr.symptomProblemId ?? designProblemId(presentingStatement);
|
|
82993
|
+
const presentingId = tr.symptomProblemId ?? (tr.threadId ? threads.get(tr.threadId) : void 0) ?? designProblemId(presentingStatement);
|
|
82720
82994
|
if (tr.causeId === presentingId) continue;
|
|
82721
82995
|
try {
|
|
82722
82996
|
recordTriageObservation(
|
|
@@ -82774,7 +83048,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82774
83048
|
}
|
|
82775
83049
|
}
|
|
82776
83050
|
for (const at of plan.attempts) {
|
|
82777
|
-
const pid = at.problemId ?? (at.threadId ? threads.get(at.threadId) : void 0) ?? (at.boundStatement ? designProblemId(at.boundStatement) : void 0);
|
|
83051
|
+
const pid = at.problemId ?? (at.threadId ? threads.get(at.threadId) : void 0) ?? (at.boundStatement ? findingIds.get(at.boundStatement) ?? designProblemId(at.boundStatement) : void 0);
|
|
82778
83052
|
const node2 = pid ? store.getNode(pid) : void 0;
|
|
82779
83053
|
if (!pid || !node2) continue;
|
|
82780
83054
|
try {
|
|
@@ -82790,7 +83064,7 @@ function createWorkspaceEngine(opts) {
|
|
|
82790
83064
|
}
|
|
82791
83065
|
}
|
|
82792
83066
|
const bindPid = (tag) => {
|
|
82793
|
-
const pid = tag.problemId ?? (tag.threadId ? threads.get(tag.threadId) : void 0) ?? (tag.boundStatement ? designProblemId(tag.boundStatement) : void 0) ?? inScopeProblemId ?? sessionLastProblem.get(sessionId);
|
|
83067
|
+
const pid = tag.problemId ?? (tag.threadId ? threads.get(tag.threadId) : void 0) ?? (tag.boundStatement ? findingIds.get(tag.boundStatement) ?? designProblemId(tag.boundStatement) : void 0) ?? inScopeProblemId ?? sessionLastProblem.get(sessionId);
|
|
82794
83068
|
return pid && store.getNode(pid) ? pid : void 0;
|
|
82795
83069
|
};
|
|
82796
83070
|
const mintCiteEdge = (from, to, type, confidence, extraAttrs) => {
|
|
@@ -82944,7 +83218,12 @@ function createWorkspaceEngine(opts) {
|
|
|
82944
83218
|
for (const [session, items2] of groups) {
|
|
82945
83219
|
if (items2.length === 0) continue;
|
|
82946
83220
|
try {
|
|
82947
|
-
const
|
|
83221
|
+
const wireItems = items2.map(({ nodeId, witnessKey }) => {
|
|
83222
|
+
const node2 = store.getNode(nodeId);
|
|
83223
|
+
const cloudId = node2?.attrs["privateFinding"] ? node2.attrs["cloudNodeId"] : void 0;
|
|
83224
|
+
return { nodeId: typeof cloudId === "string" ? cloudId : nodeId, witnessKey };
|
|
83225
|
+
});
|
|
83226
|
+
const raw2 = await send(wireItems, session);
|
|
82948
83227
|
const d = {
|
|
82949
83228
|
recorded: raw2?.recorded ?? 0,
|
|
82950
83229
|
unmatched: raw2?.unmatched ?? 0,
|
|
@@ -82957,8 +83236,8 @@ function createWorkspaceEngine(opts) {
|
|
|
82957
83236
|
duplicate += d.duplicate;
|
|
82958
83237
|
selfGated += d.selfGated;
|
|
82959
83238
|
const missing = new Set(d.unmatchedIds);
|
|
82960
|
-
for (const it of items2) {
|
|
82961
|
-
if (missing.has(
|
|
83239
|
+
for (const [index, it] of items2.entries()) {
|
|
83240
|
+
if (missing.has(wireItems[index].nodeId)) stillUnmatched.push({ channel, ...it, sessionKey: session, counted: isShipped(it.nodeId) });
|
|
82962
83241
|
else settled.add(it.witnessKey);
|
|
82963
83242
|
}
|
|
82964
83243
|
} catch (err2) {
|
|
@@ -83128,6 +83407,10 @@ function createWorkspaceEngine(opts) {
|
|
|
83128
83407
|
// but nothing judgeable was cited.
|
|
83129
83408
|
tagsVerdictNoHandle: dispositions.verdictNoHandle,
|
|
83130
83409
|
tagsFlagAsHandle: dispositions.flagAsHandle,
|
|
83410
|
+
tagsInvalidVulnerability: dispositions.invalidVulnerability,
|
|
83411
|
+
vulnerabilitiesSeen,
|
|
83412
|
+
vulnerabilitiesMinted,
|
|
83413
|
+
vulnerabilitiesSuspected,
|
|
83131
83414
|
unresolvedHandles,
|
|
83132
83415
|
priorEdgesFlagOff,
|
|
83133
83416
|
priorEdgesNoSource,
|
|
@@ -83525,15 +83808,7 @@ B: ${b}`,
|
|
|
83525
83808
|
return report;
|
|
83526
83809
|
},
|
|
83527
83810
|
async semanticMaintenance() {
|
|
83528
|
-
const
|
|
83529
|
-
const seqBefore = store.currentIngestSeq();
|
|
83530
|
-
const report = runSemanticMaintenance(store);
|
|
83531
|
-
await yieldLoop();
|
|
83532
|
-
let hintUpgrade = { upgraded: 0, standing: 0, unresolvable: 0, blocked: 0 };
|
|
83533
|
-
try {
|
|
83534
|
-
hintUpgrade = upgradeAnchorHints(store, profile.id, Date.now());
|
|
83535
|
-
} catch {
|
|
83536
|
-
}
|
|
83811
|
+
const { report, hintUpgrade, seqAdvanced, calibration, calibrationMs } = passWorker ? await passWorker.semanticMaintenance() : runWorkspaceMaintenance(store, profile.id);
|
|
83537
83812
|
appendPassLedger(paths.configDir, "semantic-maintenance", report.durationMs, {
|
|
83538
83813
|
revisitsCleared: report.revisitsCleared,
|
|
83539
83814
|
revisitsStanding: report.revisitsStanding,
|
|
@@ -83544,7 +83819,7 @@ B: ${b}`,
|
|
|
83544
83819
|
fixCandidatesStanding: report.fixCandidates.standing,
|
|
83545
83820
|
designResolved: report.designResolved,
|
|
83546
83821
|
claimsEvaluated: report.claimsEvaluated,
|
|
83547
|
-
seqAdvanced
|
|
83822
|
+
seqAdvanced,
|
|
83548
83823
|
anchorHintsUpgraded: hintUpgrade.upgraded,
|
|
83549
83824
|
anchorHintsStanding: hintUpgrade.standing,
|
|
83550
83825
|
anchorHintsUnresolvable: hintUpgrade.unresolvable,
|
|
@@ -83553,19 +83828,15 @@ B: ${b}`,
|
|
|
83553
83828
|
if (report.revisitsCleared > 0 || report.fixCandidatesSettled > 0 || report.designResolved > 0) {
|
|
83554
83829
|
refreshContextNow();
|
|
83555
83830
|
}
|
|
83556
|
-
|
|
83557
|
-
try {
|
|
83558
|
-
const t0 = Date.now();
|
|
83831
|
+
if (calibration) {
|
|
83559
83832
|
appendPassLedger(
|
|
83560
83833
|
paths.configDir,
|
|
83561
83834
|
"wm-calibration",
|
|
83562
|
-
|
|
83563
|
-
|
|
83835
|
+
calibrationMs,
|
|
83836
|
+
calibration
|
|
83564
83837
|
);
|
|
83565
|
-
} catch {
|
|
83566
83838
|
}
|
|
83567
|
-
await
|
|
83568
|
-
livenessWatch.maybeRun();
|
|
83839
|
+
await livenessWatch.maybeRun();
|
|
83569
83840
|
return report;
|
|
83570
83841
|
},
|
|
83571
83842
|
async nightly() {
|
|
@@ -84465,7 +84736,7 @@ function internalSymbolsFor(description, lexiconHas, publicIndex) {
|
|
|
84465
84736
|
|
|
84466
84737
|
// src/instance-ingest.ts
|
|
84467
84738
|
init_generalize_graph();
|
|
84468
|
-
var INSTANCE_LABELS = ["Problem", "Solution", "RootCause"];
|
|
84739
|
+
var INSTANCE_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
|
|
84469
84740
|
var INSTANCE_EDGES = ["CAUSED_BY", "SOLVED_BY"];
|
|
84470
84741
|
var ANCHOR_EDGES = ["OCCURS_IN", "DEPENDS_ON", "PERTAIN_TO", "CONCERNS"];
|
|
84471
84742
|
var ANCHOR_TARGET_LABELS = ["Language", "Package", "Domain", "Component"];
|
|
@@ -84475,7 +84746,7 @@ function stripCodebaseScope(scope) {
|
|
|
84475
84746
|
return s;
|
|
84476
84747
|
}
|
|
84477
84748
|
function compositionCounters(c) {
|
|
84478
|
-
const { sidecarDropReasons, ...
|
|
84749
|
+
const { sidecarDropReasons, ...scalars2 } = c;
|
|
84479
84750
|
const buckets = [
|
|
84480
84751
|
"empty",
|
|
84481
84752
|
"too_long",
|
|
@@ -84485,7 +84756,7 @@ function compositionCounters(c) {
|
|
|
84485
84756
|
"other"
|
|
84486
84757
|
];
|
|
84487
84758
|
return {
|
|
84488
|
-
...
|
|
84759
|
+
...scalars2,
|
|
84489
84760
|
...Object.fromEntries(buckets.map((b) => [`sidecarDrop_${b}`, sidecarDropReasons[b] ?? 0]))
|
|
84490
84761
|
};
|
|
84491
84762
|
}
|
|
@@ -84600,6 +84871,10 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
84600
84871
|
attrs: {
|
|
84601
84872
|
scope: stripCodebaseScope(n.attrs["scope"]),
|
|
84602
84873
|
...n.attrs["kind"] ? { kind: n.attrs["kind"] } : {},
|
|
84874
|
+
...n.attrs["privateFinding"] ? { privateFinding: true } : {},
|
|
84875
|
+
...n.attrs["assessment"] ? { assessment: n.attrs["assessment"] } : {},
|
|
84876
|
+
...n.attrs["sourceClass"] ? { sourceClass: n.attrs["sourceClass"] } : {},
|
|
84877
|
+
...n.attrs["resolutionWitnessed"] ? { resolutionWitnessed: true, resolvedAt: n.attrs["resolvedAt"] } : {},
|
|
84603
84878
|
...n.attrs["resolvedAs"] ? { resolvedAs: n.attrs["resolvedAs"] } : {},
|
|
84604
84879
|
...preserved.length > 0 ? { preservedSymbols: preserved } : {},
|
|
84605
84880
|
...internal.length > 0 ? { internalSymbols: internal } : {}
|
|
@@ -84614,6 +84889,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
84614
84889
|
const semanticEndpoints = /* @__PURE__ */ new Map();
|
|
84615
84890
|
const includedByLabel = /* @__PURE__ */ new Map();
|
|
84616
84891
|
const composition = {
|
|
84892
|
+
privateTargetMissing: 0,
|
|
84617
84893
|
candidates: 0,
|
|
84618
84894
|
shipped: 0,
|
|
84619
84895
|
cloudSourced: 0,
|
|
@@ -84659,11 +84935,15 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
84659
84935
|
if (walked.has(n.id)) continue;
|
|
84660
84936
|
walked.add(n.id);
|
|
84661
84937
|
composition.candidates++;
|
|
84938
|
+
if ((n.attrs["privateFinding"] || n.label === "Vulnerability") && !opts.project) {
|
|
84939
|
+
composition.privateTargetMissing++;
|
|
84940
|
+
continue;
|
|
84941
|
+
}
|
|
84662
84942
|
if (n.attrs["source"] === "cloud") {
|
|
84663
84943
|
composition.cloudSourced++;
|
|
84664
84944
|
continue;
|
|
84665
84945
|
}
|
|
84666
|
-
if (
|
|
84946
|
+
if (n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) {
|
|
84667
84947
|
composition.falsePositive++;
|
|
84668
84948
|
continue;
|
|
84669
84949
|
}
|
|
@@ -84686,7 +84966,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
84686
84966
|
composition.terminalRefused++;
|
|
84687
84967
|
continue;
|
|
84688
84968
|
}
|
|
84689
|
-
if (!noveltyAgainst(n, ref, noveltyOpts).ready) {
|
|
84969
|
+
if (!n.attrs["privateFinding"] && !noveltyAgainst(n, ref, noveltyOpts).ready) {
|
|
84690
84970
|
composition.notNovel++;
|
|
84691
84971
|
continue;
|
|
84692
84972
|
}
|
|
@@ -84729,7 +85009,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
84729
85009
|
}
|
|
84730
85010
|
if (targets.length === 0) continue;
|
|
84731
85011
|
const shipped = shippedById.get(sourceId);
|
|
84732
|
-
if (shipped) {
|
|
85012
|
+
if (shipped && !shipped.attrs["privateFinding"]) {
|
|
84733
85013
|
const anchors = (label) => targets.filter((x) => x.t.label === label).map(
|
|
84734
85014
|
(x) => label === "Language" ? langAnchor(x.t) : label === "Component" ? `component:${x.wireId}` : x.wireId
|
|
84735
85015
|
).filter((a) => a != null).sort();
|
|
@@ -85511,38 +85791,41 @@ function classifyAnchorVersion(cloudAttrs, localSymbol) {
|
|
|
85511
85791
|
if (typeof seen !== "string" || typeof have !== "string") return "unverified";
|
|
85512
85792
|
return seen === have ? "current" : "pre-change";
|
|
85513
85793
|
}
|
|
85514
|
-
function buildReverseSymbolMap(opts) {
|
|
85515
|
-
return
|
|
85794
|
+
async function buildReverseSymbolMap(opts) {
|
|
85795
|
+
return collectFirstWinsYielding(reverseSymbolEntries(opts));
|
|
85516
85796
|
}
|
|
85517
85797
|
function* reverseSymbolEntries(opts) {
|
|
85518
85798
|
const { store, salt, projectId } = opts;
|
|
85519
85799
|
for (const kind of ANCHOR_SYMBOL_KINDS2) {
|
|
85520
85800
|
for (const n of store.iterateNodeIdentitiesByLabel(kind)) {
|
|
85521
85801
|
const { relPath, qname } = n;
|
|
85522
|
-
if (relPath === null || qname === null)
|
|
85802
|
+
if (relPath === null || qname === null) {
|
|
85803
|
+
yield null;
|
|
85804
|
+
continue;
|
|
85805
|
+
}
|
|
85523
85806
|
const sym = projectSymbolId(salt, projectId, relPath, qname, kind);
|
|
85524
85807
|
yield [sym, n.id];
|
|
85525
85808
|
yield [projectSaltedNodeId(sym, salt), n.id];
|
|
85526
85809
|
}
|
|
85527
85810
|
}
|
|
85528
85811
|
for (const n of store.iterateNodeIdentitiesByLabel("File")) {
|
|
85529
|
-
if (n.relPath === null)
|
|
85812
|
+
if (n.relPath === null) {
|
|
85813
|
+
yield null;
|
|
85814
|
+
continue;
|
|
85815
|
+
}
|
|
85530
85816
|
const sym = projectSymbolId(salt, projectId, n.relPath, FILE_ANCHOR_QNAME, "File");
|
|
85531
85817
|
yield [sym, n.id];
|
|
85532
85818
|
yield [projectSaltedNodeId(sym, salt), n.id];
|
|
85533
85819
|
}
|
|
85534
85820
|
}
|
|
85535
|
-
function collectFirstWins(entries) {
|
|
85536
|
-
const m = /* @__PURE__ */ new Map();
|
|
85537
|
-
for (const [k, v] of entries) if (!m.has(k)) m.set(k, v);
|
|
85538
|
-
return m;
|
|
85539
|
-
}
|
|
85540
85821
|
var MAP_BUILD_BATCH = 2e3;
|
|
85541
85822
|
async function collectFirstWinsYielding(entries) {
|
|
85542
85823
|
const m = /* @__PURE__ */ new Map();
|
|
85543
85824
|
let i2 = 0;
|
|
85544
|
-
for (const
|
|
85825
|
+
for (const entry of entries) {
|
|
85545
85826
|
if (++i2 % MAP_BUILD_BATCH === 0) await new Promise((r) => setImmediate(r));
|
|
85827
|
+
if (entry === null) continue;
|
|
85828
|
+
const [k, v] = entry;
|
|
85546
85829
|
if (!m.has(k)) m.set(k, v);
|
|
85547
85830
|
}
|
|
85548
85831
|
return m;
|
|
@@ -85634,7 +85917,7 @@ async function reanchorProject(opts) {
|
|
|
85634
85917
|
if (!profile.projectId) return { reanchored: false, reason: "no-project" };
|
|
85635
85918
|
if (profile.projectReanchoredAt) return { reanchored: false, reason: "already-reanchored" };
|
|
85636
85919
|
if (!profile.projectHydratedAt) return { reanchored: false, reason: "not-hydrated" };
|
|
85637
|
-
const reverse = buildReverseSymbolMap({ store, salt, projectId: profile.projectId });
|
|
85920
|
+
const reverse = await buildReverseSymbolMap({ store, salt, projectId: profile.projectId });
|
|
85638
85921
|
if (reverse.size === 0) return { reanchored: false, reason: "no-local-symbols" };
|
|
85639
85922
|
try {
|
|
85640
85923
|
const res = await cloud.getProjectPriors(profile.projectId, opts.limit ?? DEFAULT_LIMIT);
|
|
@@ -85696,7 +85979,7 @@ async function syncProjectAnchors(opts) {
|
|
|
85696
85979
|
reverseCache,
|
|
85697
85980
|
store,
|
|
85698
85981
|
key,
|
|
85699
|
-
() =>
|
|
85982
|
+
() => buildReverseSymbolMap({ store, salt, projectId })
|
|
85700
85983
|
);
|
|
85701
85984
|
const own = cachedMap(ownCache, store, salt, () => collectLastWinsYielding(ownKnowledgeEntries({ store, salt })));
|
|
85702
85985
|
const limit = opts.limit ?? SYNC_PAGE;
|
|
@@ -85869,11 +86152,11 @@ async function syncHistoryRevisionPage(opts) {
|
|
|
85869
86152
|
const sweepCommit = after ? oldCursor.atCommit : atCommit;
|
|
85870
86153
|
const page = await cloud.getHistoryOccurrences(projectId, atCommit, after);
|
|
85871
86154
|
if (!Array.isArray(page.occurrences) || page.occurrences.length > 50 || page.occurrences.some((o, i2) => o.occurrenceId <= (page.occurrences[i2 - 1]?.occurrenceId ?? after ?? "")) || page.cursor !== null && page.cursor !== page.occurrences.at(-1)?.occurrenceId) throw new Error("invalid history occurrence page");
|
|
85872
|
-
const parents = (await git3(["rev-list", "--parents", "--max-count=8192", atCommit])).trim().split("\n").filter(Boolean).map((row) => {
|
|
86155
|
+
const parents = page.occurrences.length ? (await git3(["rev-list", "--parents", "--max-count=8192", atCommit])).trim().split("\n").filter(Boolean).map((row) => {
|
|
85873
86156
|
const [commit, ...parents2] = row.trim().split(/\s+/);
|
|
85874
86157
|
return { commit, parents: parents2 };
|
|
85875
|
-
});
|
|
85876
|
-
const reverse = buildReverseSymbolMap({ store, projectId, salt });
|
|
86158
|
+
}) : [];
|
|
86159
|
+
const reverse = page.occurrences.length ? await buildReverseSymbolMap({ store, projectId, salt }) : /* @__PURE__ */ new Map();
|
|
85877
86160
|
const ignore2 = loadRepoIgnore(root, profile.ignoreExtra ?? []);
|
|
85878
86161
|
const providers = defaultProviders();
|
|
85879
86162
|
const parsedFiles = /* @__PURE__ */ new Map();
|