@mcptoolshop/research-os 0.3.3 → 0.5.0
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/CHANGELOG.md +210 -0
- package/README.es.md +26 -1
- package/README.fr.md +30 -5
- package/README.hi.md +45 -5
- package/README.it.md +26 -1
- package/README.ja.md +30 -5
- package/README.md +39 -1
- package/README.pt-BR.md +26 -1
- package/README.zh.md +26 -1
- package/dist/calibration/aggregate-receipt-schema.d.ts +509 -0
- package/dist/calibration/aggregate-receipt-schema.js +143 -0
- package/dist/calibration/aggregate-receipt-schema.js.map +1 -0
- package/dist/calibration/aggregate.d.ts +35 -0
- package/dist/calibration/aggregate.js +454 -0
- package/dist/calibration/aggregate.js.map +1 -0
- package/dist/calibration/receipt-schema.d.ts +317 -0
- package/dist/calibration/receipt-schema.js +68 -0
- package/dist/calibration/receipt-schema.js.map +1 -0
- package/dist/calibration/receipt.d.ts +31 -0
- package/dist/calibration/receipt.js +151 -0
- package/dist/calibration/receipt.js.map +1 -0
- package/dist/cli.js +1957 -1253
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +140 -4
- package/dist/index.js +1499 -1168
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -999,17 +999,244 @@ var init_schema3 = __esm({
|
|
|
999
999
|
scope: z3.string().nullable(),
|
|
1000
1000
|
not: z3.string().nullable(),
|
|
1001
1001
|
extracted_by: ExtractorNameSchema,
|
|
1002
|
-
extracted_at: z3.string()
|
|
1002
|
+
extracted_at: z3.string(),
|
|
1003
|
+
/** Rule that classified the URL. Added by Component B (v0.4). Optional for back-compat with pre-v0.4 cards. */
|
|
1004
|
+
rule_hint: z3.string().optional(),
|
|
1005
|
+
/** Precedence level of the rule that fired (2–6). Optional for back-compat with pre-v0.4 cards. */
|
|
1006
|
+
precedence_level: z3.union([z3.literal(2), z3.literal(3), z3.literal(4), z3.literal(5), z3.literal(6)]).optional()
|
|
1003
1007
|
});
|
|
1004
1008
|
}
|
|
1005
1009
|
});
|
|
1006
1010
|
|
|
1011
|
+
// src/sources/canonical-vendors.ts
|
|
1012
|
+
var CANONICAL_VENDORS;
|
|
1013
|
+
var init_canonical_vendors = __esm({
|
|
1014
|
+
"src/sources/canonical-vendors.ts"() {
|
|
1015
|
+
"use strict";
|
|
1016
|
+
CANONICAL_VENDORS = [
|
|
1017
|
+
// ── Protocol-foundation vendors → primary ────────────────────────────────
|
|
1018
|
+
{
|
|
1019
|
+
slug: "xrpl-foundation",
|
|
1020
|
+
hosts: ["xrpl.org", "xls.xrpl.org"],
|
|
1021
|
+
github_orgs: ["XRPLF"],
|
|
1022
|
+
source_type: "primary",
|
|
1023
|
+
description: "XRPL Foundation \u2014 canonical authority for the XRPL protocol + XLS standards."
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
slug: "ipfs-foundation",
|
|
1027
|
+
hosts: ["docs.ipfs.tech", "ipfs.tech"],
|
|
1028
|
+
source_type: "primary",
|
|
1029
|
+
description: "IPFS protocol canonical surface."
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
slug: "arweave",
|
|
1033
|
+
hosts: ["docs.arweave.org", "arweave.org"],
|
|
1034
|
+
source_type: "primary",
|
|
1035
|
+
description: "Arweave protocol canonical surface."
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
slug: "anthropic",
|
|
1039
|
+
hosts: ["docs.anthropic.com", "anthropic.com", "claude.com"],
|
|
1040
|
+
source_type: "primary",
|
|
1041
|
+
description: "Claude API + Anthropic models \u2014 vendor owns the API surface. Resolves F-47: docs.anthropic.com is primary, not docs."
|
|
1042
|
+
},
|
|
1043
|
+
// ── Platform/engine vendors → docs ───────────────────────────────────────
|
|
1044
|
+
{
|
|
1045
|
+
slug: "godot-foundation",
|
|
1046
|
+
hosts: ["docs.godotengine.org", "godotengine.org"],
|
|
1047
|
+
github_orgs: ["godotengine"],
|
|
1048
|
+
source_type: "docs",
|
|
1049
|
+
description: "Godot engine docs. NB: api.github.com/repos/godotengine/godot/releases matches L4 as canonical-releases \u2192 primary."
|
|
1050
|
+
},
|
|
1051
|
+
{
|
|
1052
|
+
slug: "apple",
|
|
1053
|
+
hosts: ["developer.apple.com", "docs.developer.apple.com"],
|
|
1054
|
+
source_type: "docs",
|
|
1055
|
+
description: "Apple platform docs. developer.apple.com/documentation/* is JS-shell (F-42); docs.developer.apple.com/tutorials/data/*.md is the text-stable alternate."
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
slug: "microsoft",
|
|
1059
|
+
hosts: ["learn.microsoft.com"],
|
|
1060
|
+
github_orgs: ["MicrosoftDocs"],
|
|
1061
|
+
source_type: "docs",
|
|
1062
|
+
description: "MS Learn + MicrosoftDocs raw GitHub."
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
slug: "mozilla",
|
|
1066
|
+
hosts: ["developer.mozilla.org"],
|
|
1067
|
+
source_type: "docs",
|
|
1068
|
+
description: "MDN web platform docs."
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
slug: "google-android",
|
|
1072
|
+
hosts: ["developer.android.com"],
|
|
1073
|
+
source_type: "docs",
|
|
1074
|
+
description: "Android platform docs."
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
slug: "google-play",
|
|
1078
|
+
hosts: [],
|
|
1079
|
+
hostPaths: ["support.google.com/googleplay"],
|
|
1080
|
+
source_type: "docs",
|
|
1081
|
+
description: "Play Store policy/help docs. Matched on host+path-prefix to avoid classifying all of support.google.com as docs."
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
slug: "itch-io",
|
|
1085
|
+
hosts: [],
|
|
1086
|
+
hostPaths: ["itch.io/docs"],
|
|
1087
|
+
source_type: "docs",
|
|
1088
|
+
description: "itch.io creator docs (not storefront chrome). Matched on host+path-prefix so itch.io/<creator>/<game> does not match L3."
|
|
1089
|
+
}
|
|
1090
|
+
];
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
// src/sources/source-type-classifier.ts
|
|
1095
|
+
import { URL as URL4 } from "url";
|
|
1096
|
+
function classifySourceType(input) {
|
|
1097
|
+
let parsed;
|
|
1098
|
+
try {
|
|
1099
|
+
parsed = new URL4(input.url);
|
|
1100
|
+
} catch {
|
|
1101
|
+
return { source_type: "unknown", rule_hint: "no-rule-match", precedence_level: 6 };
|
|
1102
|
+
}
|
|
1103
|
+
const host = parsed.hostname.toLowerCase();
|
|
1104
|
+
const pathname = parsed.pathname;
|
|
1105
|
+
if (host === "github.com" && /^\/[^/]+\/[^/]+/.test(pathname)) {
|
|
1106
|
+
return { source_type: "unknown", rule_hint: "flagged:github-ui-html", precedence_level: 2 };
|
|
1107
|
+
}
|
|
1108
|
+
for (const vendor of CANONICAL_VENDORS) {
|
|
1109
|
+
if (vendor.hosts.includes(host)) {
|
|
1110
|
+
return {
|
|
1111
|
+
source_type: vendor.source_type,
|
|
1112
|
+
rule_hint: `canonical-vendor:${vendor.slug}`,
|
|
1113
|
+
precedence_level: 3
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
for (const hp of vendor.hostPaths ?? []) {
|
|
1117
|
+
const slashIdx = hp.indexOf("/");
|
|
1118
|
+
const hpHost = slashIdx === -1 ? hp : hp.slice(0, slashIdx);
|
|
1119
|
+
const hpPath = slashIdx === -1 ? "" : "/" + hp.slice(slashIdx + 1);
|
|
1120
|
+
if (host === hpHost && (hpPath === "" || pathname === hpPath || pathname.startsWith(hpPath + "/"))) {
|
|
1121
|
+
return {
|
|
1122
|
+
source_type: vendor.source_type,
|
|
1123
|
+
rule_hint: `canonical-vendor:${vendor.slug}`,
|
|
1124
|
+
precedence_level: 3
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
if (host === "api.github.com") {
|
|
1130
|
+
if (pathname.startsWith("/search/issues")) {
|
|
1131
|
+
return { source_type: "forum", rule_hint: "github-api:search-issues", precedence_level: 4 };
|
|
1132
|
+
}
|
|
1133
|
+
const releasesMatch = pathname.match(/^\/repos\/([^/]+)\/([^/]+)\/releases(?:\/|$|\?)/);
|
|
1134
|
+
if (releasesMatch) {
|
|
1135
|
+
const org = releasesMatch[1].toLowerCase();
|
|
1136
|
+
if (CANONICAL_GITHUB_ORGS.has(org)) {
|
|
1137
|
+
return {
|
|
1138
|
+
source_type: "primary",
|
|
1139
|
+
rule_hint: "github-api:canonical-releases",
|
|
1140
|
+
precedence_level: 4
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
return {
|
|
1144
|
+
source_type: "secondary",
|
|
1145
|
+
rule_hint: "github-api:releases-noncanonical",
|
|
1146
|
+
precedence_level: 4
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
if (pathname.match(/^\/repos\/[^/]+\/[^/]+\/issues\/\d+(?:\/|$|\?)/)) {
|
|
1150
|
+
return { source_type: "forum", rule_hint: "github-api:issue-thread", precedence_level: 4 };
|
|
1151
|
+
}
|
|
1152
|
+
if (pathname.match(/^\/repos\/[^/]+\/[^/]+\/issues(?:\/|$|\?)/)) {
|
|
1153
|
+
return { source_type: "forum", rule_hint: "github-api:issues-list", precedence_level: 4 };
|
|
1154
|
+
}
|
|
1155
|
+
if (pathname.match(/^\/repos\/[^/]+\/[^/]+\/tags(?:\/|$|\?)/)) {
|
|
1156
|
+
return { source_type: "secondary", rule_hint: "github-api:tags", precedence_level: 4 };
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
if (host === "raw.githubusercontent.com") {
|
|
1160
|
+
const rawMatch = pathname.match(/^\/([^/]+)\/([^/]+)\/([^/]+)\/(.*)/);
|
|
1161
|
+
if (rawMatch) {
|
|
1162
|
+
const [, org, repo, , filePath] = rawMatch;
|
|
1163
|
+
const isCanonicalOrg = CANONICAL_GITHUB_ORGS.has(org.toLowerCase());
|
|
1164
|
+
const isDocsShapedRepo = /-docs$/.test(repo) || /-documentation$/.test(repo);
|
|
1165
|
+
const isDocFile = /\.(rst|md)$/i.test(filePath);
|
|
1166
|
+
if (isDocFile && (isCanonicalOrg || isDocsShapedRepo)) {
|
|
1167
|
+
return {
|
|
1168
|
+
source_type: "docs",
|
|
1169
|
+
rule_hint: "raw-github:project-docs",
|
|
1170
|
+
precedence_level: 5
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
if (/(?:^|\/)README\.md$/i.test(filePath)) {
|
|
1174
|
+
return {
|
|
1175
|
+
source_type: "secondary",
|
|
1176
|
+
rule_hint: "raw-github:plugin-readme",
|
|
1177
|
+
precedence_level: 5
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
return { source_type: "secondary", rule_hint: "raw-github:other", precedence_level: 5 };
|
|
1181
|
+
}
|
|
1182
|
+
return { source_type: "secondary", rule_hint: "raw-github:other", precedence_level: 5 };
|
|
1183
|
+
}
|
|
1184
|
+
if (host.startsWith("docs.")) {
|
|
1185
|
+
return {
|
|
1186
|
+
source_type: "docs",
|
|
1187
|
+
rule_hint: "fallback:docs-host-prefix",
|
|
1188
|
+
precedence_level: 6
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
const KNOWN_FORUM_HOSTS = ["stackoverflow.com", "reddit.com", "news.ycombinator.com"];
|
|
1192
|
+
if (KNOWN_FORUM_HOSTS.some((fh) => host === fh || host.endsWith("." + fh))) {
|
|
1193
|
+
return { source_type: "forum", rule_hint: "fallback:known-forum", precedence_level: 6 };
|
|
1194
|
+
}
|
|
1195
|
+
return { source_type: "unknown", rule_hint: "no-rule-match", precedence_level: 6 };
|
|
1196
|
+
}
|
|
1197
|
+
var CANONICAL_GITHUB_ORGS;
|
|
1198
|
+
var init_source_type_classifier = __esm({
|
|
1199
|
+
"src/sources/source-type-classifier.ts"() {
|
|
1200
|
+
"use strict";
|
|
1201
|
+
init_canonical_vendors();
|
|
1202
|
+
CANONICAL_GITHUB_ORGS = new Set(
|
|
1203
|
+
CANONICAL_VENDORS.flatMap((v) => (v.github_orgs ?? []).map((o) => o.toLowerCase()))
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
// src/sources/effective-card.ts
|
|
1209
|
+
function getEffectiveSourceType(card, overrides) {
|
|
1210
|
+
const matched = overrides.filter((o) => o.source_id === card.source_id && o.new_source_type != null).sort((a, b) => a.created_at > b.created_at ? -1 : a.created_at < b.created_at ? 1 : 0);
|
|
1211
|
+
return matched.length > 0 ? matched[0].new_source_type : card.source_type;
|
|
1212
|
+
}
|
|
1213
|
+
function getEffectivePublisher(card, overrides) {
|
|
1214
|
+
const matched = overrides.filter((o) => o.source_id === card.source_id && o.new_publisher !== void 0).sort((a, b) => a.created_at > b.created_at ? -1 : a.created_at < b.created_at ? 1 : 0);
|
|
1215
|
+
if (matched.length === 0) return card.publisher;
|
|
1216
|
+
return matched[0].new_publisher ?? null;
|
|
1217
|
+
}
|
|
1218
|
+
var init_effective_card = __esm({
|
|
1219
|
+
"src/sources/effective-card.ts"() {
|
|
1220
|
+
"use strict";
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1007
1224
|
// src/sources/cards.ts
|
|
1008
1225
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
1009
1226
|
import { existsSync as existsSync3 } from "fs";
|
|
1010
1227
|
import { join as join4 } from "path";
|
|
1011
1228
|
function buildCard(args) {
|
|
1012
1229
|
const { receipt, extraction, extractedBy } = args;
|
|
1230
|
+
const overrides = args.overrides ?? [];
|
|
1231
|
+
const classification = classifySourceType({ url: receipt.requested_url });
|
|
1232
|
+
const classifiedSourceType = classification.rule_hint === "no-rule-match" ? extraction.source_type : classification.source_type;
|
|
1233
|
+
const baseForEffective = {
|
|
1234
|
+
source_id: receipt.source_id,
|
|
1235
|
+
source_type: classifiedSourceType,
|
|
1236
|
+
publisher: extraction.publisher
|
|
1237
|
+
};
|
|
1238
|
+
const resolvedSourceType = getEffectiveSourceType(baseForEffective, overrides);
|
|
1239
|
+
const resolvedPublisher = getEffectivePublisher(baseForEffective, overrides);
|
|
1013
1240
|
const card = SourceCardSchema.parse({
|
|
1014
1241
|
source_id: receipt.source_id,
|
|
1015
1242
|
receipt_id: receipt.receipt_id,
|
|
@@ -1017,10 +1244,10 @@ function buildCard(args) {
|
|
|
1017
1244
|
url: receipt.requested_url,
|
|
1018
1245
|
final_url: receipt.final_url,
|
|
1019
1246
|
fetched_at: receipt.fetched_at,
|
|
1020
|
-
publisher:
|
|
1247
|
+
publisher: resolvedPublisher,
|
|
1021
1248
|
published_at: extraction.published_at,
|
|
1022
1249
|
title: extraction.title,
|
|
1023
|
-
source_type:
|
|
1250
|
+
source_type: resolvedSourceType,
|
|
1024
1251
|
relevance: extraction.relevance,
|
|
1025
1252
|
key_points: extraction.key_points,
|
|
1026
1253
|
limitations: extraction.limitations,
|
|
@@ -1028,7 +1255,9 @@ function buildCard(args) {
|
|
|
1028
1255
|
scope: extraction.scope,
|
|
1029
1256
|
not: extraction.not,
|
|
1030
1257
|
extracted_by: extractedBy,
|
|
1031
|
-
extracted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1258
|
+
extracted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1259
|
+
rule_hint: classification.rule_hint,
|
|
1260
|
+
precedence_level: classification.precedence_level
|
|
1032
1261
|
});
|
|
1033
1262
|
return card;
|
|
1034
1263
|
}
|
|
@@ -1065,21 +1294,106 @@ var init_cards = __esm({
|
|
|
1065
1294
|
"src/sources/cards.ts"() {
|
|
1066
1295
|
"use strict";
|
|
1067
1296
|
init_schema3();
|
|
1297
|
+
init_source_type_classifier();
|
|
1298
|
+
init_effective_card();
|
|
1068
1299
|
}
|
|
1069
1300
|
});
|
|
1070
1301
|
|
|
1071
|
-
// src/sources/
|
|
1302
|
+
// src/sources/source-card-overrides-schema.ts
|
|
1303
|
+
import { z as z4 } from "zod";
|
|
1304
|
+
function validateSourceCardOverride(input) {
|
|
1305
|
+
return SourceCardOverrideSchema.parse(input);
|
|
1306
|
+
}
|
|
1307
|
+
var SourceCardOverrideSchema;
|
|
1308
|
+
var init_source_card_overrides_schema = __esm({
|
|
1309
|
+
"src/sources/source-card-overrides-schema.ts"() {
|
|
1310
|
+
"use strict";
|
|
1311
|
+
init_schema3();
|
|
1312
|
+
SourceCardOverrideSchema = z4.object({
|
|
1313
|
+
source_id: z4.string().min(1, "source_id must be non-empty"),
|
|
1314
|
+
url: z4.string().min(1, "url must be non-empty"),
|
|
1315
|
+
previous_source_type: z4.string().nullable().optional(),
|
|
1316
|
+
new_source_type: SourceTypeSchema.nullable().optional(),
|
|
1317
|
+
previous_publisher: z4.string().nullable().optional(),
|
|
1318
|
+
new_publisher: z4.string().nullable().optional(),
|
|
1319
|
+
reason: z4.string().refine((v) => v.trim().length > 0, { message: "reason must be non-empty after trim" }),
|
|
1320
|
+
operator: z4.string().min(1, "operator must be non-empty"),
|
|
1321
|
+
created_at: z4.string().refine((v) => isFinite(Date.parse(v)), {
|
|
1322
|
+
message: "created_at must be a valid ISO 8601 timestamp"
|
|
1323
|
+
}),
|
|
1324
|
+
rule_hint: z4.string().nullable().optional(),
|
|
1325
|
+
pack_version: z4.string().min(1, "pack_version must be non-empty")
|
|
1326
|
+
}).refine(
|
|
1327
|
+
(obj) => obj.new_source_type != null && obj.new_source_type !== void 0 || obj.new_publisher != null && obj.new_publisher !== void 0,
|
|
1328
|
+
{
|
|
1329
|
+
message: "At least one of new_source_type or new_publisher must be present and non-null"
|
|
1330
|
+
}
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
// src/sources/source-card-overrides.ts
|
|
1336
|
+
import { readFile as readFile5, appendFile as appendFile2, mkdir as mkdir5 } from "fs/promises";
|
|
1072
1337
|
import { existsSync as existsSync4 } from "fs";
|
|
1073
|
-
import { join as join5,
|
|
1338
|
+
import { join as join5, dirname as dirname2 } from "path";
|
|
1339
|
+
function overridesPath(packPath) {
|
|
1340
|
+
return join5(packPath, "evidence", OVERRIDES_FILE);
|
|
1341
|
+
}
|
|
1342
|
+
async function readOverrides(packPath) {
|
|
1343
|
+
const filePath = overridesPath(packPath);
|
|
1344
|
+
if (!existsSync4(filePath)) return [];
|
|
1345
|
+
const content = await readFile5(filePath, "utf8");
|
|
1346
|
+
const lines = content.split(/\r?\n/).filter(Boolean);
|
|
1347
|
+
return lines.map((line, idx) => {
|
|
1348
|
+
const lineNum = idx + 1;
|
|
1349
|
+
let parsed;
|
|
1350
|
+
try {
|
|
1351
|
+
parsed = JSON.parse(line);
|
|
1352
|
+
} catch {
|
|
1353
|
+
throw new Error(
|
|
1354
|
+
`source-card-overrides.jsonl: malformed JSON at line ${lineNum}: ${line.slice(0, 120)}`
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
try {
|
|
1358
|
+
return validateSourceCardOverride(parsed);
|
|
1359
|
+
} catch (err) {
|
|
1360
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1361
|
+
throw new Error(
|
|
1362
|
+
`source-card-overrides.jsonl: invalid override at line ${lineNum}: ${msg}
|
|
1363
|
+
Content: ${line.slice(0, 120)}`,
|
|
1364
|
+
{ cause: err }
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
async function appendOverride(packPath, override) {
|
|
1370
|
+
validateSourceCardOverride(override);
|
|
1371
|
+
const filePath = overridesPath(packPath);
|
|
1372
|
+
await mkdir5(dirname2(filePath), { recursive: true });
|
|
1373
|
+
await appendFile2(filePath, JSON.stringify(override) + "\n", "utf8");
|
|
1374
|
+
}
|
|
1375
|
+
var OVERRIDES_FILE;
|
|
1376
|
+
var init_source_card_overrides = __esm({
|
|
1377
|
+
"src/sources/source-card-overrides.ts"() {
|
|
1378
|
+
"use strict";
|
|
1379
|
+
init_source_card_overrides_schema();
|
|
1380
|
+
OVERRIDES_FILE = "source-card-overrides.jsonl";
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1384
|
+
// src/sources/gather.ts
|
|
1385
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1386
|
+
import { join as join6, resolve as resolve3 } from "path";
|
|
1074
1387
|
async function gather(options) {
|
|
1075
1388
|
const packPath = options.packPath ? resolve3(options.packPath) : process.cwd();
|
|
1076
|
-
if (!
|
|
1077
|
-
if (!
|
|
1389
|
+
if (!existsSync5(join6(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
1390
|
+
if (!existsSync5(join6(packPath, "sections", options.sectionId)))
|
|
1078
1391
|
throw new SectionNotFoundError(options.sectionId);
|
|
1079
1392
|
const { urls } = await collectUrls({ urls: options.urls, urlsFile: options.urlsFile });
|
|
1080
1393
|
if (urls.length === 0) throw new NoUrlsProvidedError();
|
|
1081
1394
|
const extractorList = options.extractors ?? defaultExtractors();
|
|
1082
1395
|
const extractor = await pickExtractor(extractorList);
|
|
1396
|
+
const overrides = await readOverrides(packPath);
|
|
1083
1397
|
const summary = {
|
|
1084
1398
|
sectionId: options.sectionId,
|
|
1085
1399
|
attempted: urls.length,
|
|
@@ -1114,7 +1428,7 @@ async function gather(options) {
|
|
|
1114
1428
|
extraction_extractor: extractor.name,
|
|
1115
1429
|
extraction_error: null
|
|
1116
1430
|
};
|
|
1117
|
-
const card = buildCard({ receipt: receiptToWrite, extraction: result, extractedBy: extractor.name });
|
|
1431
|
+
const card = buildCard({ receipt: receiptToWrite, extraction: result, extractedBy: extractor.name, overrides });
|
|
1118
1432
|
await writeSourceCard(packPath, card);
|
|
1119
1433
|
await appendSectionSourceId(packPath, options.sectionId, card.source_id);
|
|
1120
1434
|
summary.cardsWritten += 1;
|
|
@@ -1144,27 +1458,28 @@ var init_gather = __esm({
|
|
|
1144
1458
|
init_url_input();
|
|
1145
1459
|
init_extractors();
|
|
1146
1460
|
init_cards();
|
|
1461
|
+
init_source_card_overrides();
|
|
1147
1462
|
}
|
|
1148
1463
|
});
|
|
1149
1464
|
|
|
1150
1465
|
// src/sources/excerpts/schema.ts
|
|
1151
|
-
import { z as
|
|
1466
|
+
import { z as z5 } from "zod";
|
|
1152
1467
|
var EXCERPT_ID_PATTERN, ExcerptOriginSchema, ExcerptSchema;
|
|
1153
1468
|
var init_schema4 = __esm({
|
|
1154
1469
|
"src/sources/excerpts/schema.ts"() {
|
|
1155
1470
|
"use strict";
|
|
1156
1471
|
EXCERPT_ID_PATTERN = /^ex_[a-f0-9]{12}_\d{3,}$/;
|
|
1157
|
-
ExcerptOriginSchema =
|
|
1158
|
-
ExcerptSchema =
|
|
1159
|
-
excerpt_id:
|
|
1160
|
-
source_id:
|
|
1161
|
-
source_hash:
|
|
1162
|
-
text:
|
|
1163
|
-
location_hint:
|
|
1164
|
-
char_start:
|
|
1165
|
-
char_end:
|
|
1472
|
+
ExcerptOriginSchema = z5.enum(["raw_text", "key_point"]);
|
|
1473
|
+
ExcerptSchema = z5.object({
|
|
1474
|
+
excerpt_id: z5.string().regex(EXCERPT_ID_PATTERN),
|
|
1475
|
+
source_id: z5.string().regex(/^src_[a-f0-9]{12}$/),
|
|
1476
|
+
source_hash: z5.string().regex(/^[a-f0-9]{64}$/).nullable(),
|
|
1477
|
+
text: z5.string().min(1),
|
|
1478
|
+
location_hint: z5.string().nullable(),
|
|
1479
|
+
char_start: z5.number().int().nonnegative(),
|
|
1480
|
+
char_end: z5.number().int().nonnegative(),
|
|
1166
1481
|
origin: ExcerptOriginSchema,
|
|
1167
|
-
created_at:
|
|
1482
|
+
created_at: z5.string()
|
|
1168
1483
|
});
|
|
1169
1484
|
}
|
|
1170
1485
|
});
|
|
@@ -1293,11 +1608,11 @@ var init_chunk = __esm({
|
|
|
1293
1608
|
});
|
|
1294
1609
|
|
|
1295
1610
|
// src/sources/excerpts/ledger.ts
|
|
1296
|
-
import { existsSync as
|
|
1297
|
-
import { mkdir as
|
|
1298
|
-
import { dirname as
|
|
1611
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1612
|
+
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
1613
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
1299
1614
|
function ledgerPathFor(packPath, sourceId) {
|
|
1300
|
-
return
|
|
1615
|
+
return join7(packPath, "evidence", "excerpts", `${sourceId}.jsonl`);
|
|
1301
1616
|
}
|
|
1302
1617
|
function makeExcerptId(sourceId, index) {
|
|
1303
1618
|
const idx = String(index).padStart(3, "0");
|
|
@@ -1305,7 +1620,7 @@ function makeExcerptId(sourceId, index) {
|
|
|
1305
1620
|
return `ex_${hex}_${idx}`;
|
|
1306
1621
|
}
|
|
1307
1622
|
async function readLedger(path) {
|
|
1308
|
-
const text = await
|
|
1623
|
+
const text = await readFile6(path, "utf8");
|
|
1309
1624
|
const out = [];
|
|
1310
1625
|
for (const line of text.split(/\r?\n/)) {
|
|
1311
1626
|
if (!line.trim()) continue;
|
|
@@ -1317,7 +1632,7 @@ async function readLedger(path) {
|
|
|
1317
1632
|
return out;
|
|
1318
1633
|
}
|
|
1319
1634
|
async function writeLedger(path, excerpts) {
|
|
1320
|
-
await
|
|
1635
|
+
await mkdir6(dirname3(path), { recursive: true });
|
|
1321
1636
|
const body = excerpts.map((e) => JSON.stringify(e)).join("\n") + (excerpts.length > 0 ? "\n" : "");
|
|
1322
1637
|
await writeFile5(path, body, "utf8");
|
|
1323
1638
|
}
|
|
@@ -1325,7 +1640,7 @@ async function loadOrBuildLedger(args) {
|
|
|
1325
1640
|
const { packPath, sourceCard, sourceHash, rawText } = args;
|
|
1326
1641
|
const now = args.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
1327
1642
|
const path = ledgerPathFor(packPath, sourceCard.source_id);
|
|
1328
|
-
if (
|
|
1643
|
+
if (existsSync6(path)) {
|
|
1329
1644
|
const excerpts2 = await readLedger(path);
|
|
1330
1645
|
if (excerpts2.length > 0) {
|
|
1331
1646
|
const origins = new Set(excerpts2.map((e) => e.origin));
|
|
@@ -1394,6 +1709,9 @@ var init_sources = __esm({
|
|
|
1394
1709
|
init_extractors();
|
|
1395
1710
|
init_ollama_intern();
|
|
1396
1711
|
init_cards();
|
|
1712
|
+
init_source_card_overrides();
|
|
1713
|
+
init_source_card_overrides_schema();
|
|
1714
|
+
init_effective_card();
|
|
1397
1715
|
init_schema3();
|
|
1398
1716
|
init_excerpts();
|
|
1399
1717
|
}
|
|
@@ -1704,50 +2022,50 @@ var init_extractors2 = __esm({
|
|
|
1704
2022
|
});
|
|
1705
2023
|
|
|
1706
2024
|
// src/claims/schema.ts
|
|
1707
|
-
import { z as
|
|
2025
|
+
import { z as z6 } from "zod";
|
|
1708
2026
|
var ConfidenceSchema, ClaimExtractorSchema, ReviewStateSchema, ClaimSchema;
|
|
1709
2027
|
var init_schema5 = __esm({
|
|
1710
2028
|
"src/claims/schema.ts"() {
|
|
1711
2029
|
"use strict";
|
|
1712
2030
|
init_schema4();
|
|
1713
|
-
ConfidenceSchema =
|
|
1714
|
-
ClaimExtractorSchema =
|
|
1715
|
-
ReviewStateSchema =
|
|
2031
|
+
ConfidenceSchema = z6.enum(["low", "medium", "high"]);
|
|
2032
|
+
ClaimExtractorSchema = z6.enum(["heuristic", "ollama-intern"]);
|
|
2033
|
+
ReviewStateSchema = z6.enum([
|
|
1716
2034
|
"candidate",
|
|
1717
2035
|
"gated",
|
|
1718
2036
|
"reviewed",
|
|
1719
2037
|
"rejected",
|
|
1720
2038
|
"accepted"
|
|
1721
2039
|
]);
|
|
1722
|
-
ClaimSchema =
|
|
1723
|
-
claim_id:
|
|
1724
|
-
section_id:
|
|
1725
|
-
source_ids:
|
|
1726
|
-
source_hashes:
|
|
1727
|
-
asserts:
|
|
1728
|
-
scope:
|
|
1729
|
-
not:
|
|
2040
|
+
ClaimSchema = z6.object({
|
|
2041
|
+
claim_id: z6.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/),
|
|
2042
|
+
section_id: z6.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
2043
|
+
source_ids: z6.array(z6.string().regex(/^src_[a-f0-9]{12}$/)).min(1, "every claim must reference at least one source_id"),
|
|
2044
|
+
source_hashes: z6.array(z6.string().regex(/^[a-f0-9]{64}$/)),
|
|
2045
|
+
asserts: z6.string().min(1),
|
|
2046
|
+
scope: z6.string().nullable(),
|
|
2047
|
+
not: z6.string().nullable(),
|
|
1730
2048
|
// Span-first extraction: the model picks excerpt IDs from the deterministic
|
|
1731
2049
|
// ledger; research-os copies the literal text into evidence_excerpt. Models
|
|
1732
2050
|
// may interpret source spans; they may not author evidence spans.
|
|
1733
2051
|
// Allowed empty for legacy claims that pre-date span-first extraction —
|
|
1734
2052
|
// those should be re-extracted; new writes always populate at least one ID.
|
|
1735
|
-
evidence_excerpt_ids:
|
|
1736
|
-
evidence_excerpt:
|
|
1737
|
-
evidence_location:
|
|
2053
|
+
evidence_excerpt_ids: z6.array(z6.string().regex(EXCERPT_ID_PATTERN)).default([]),
|
|
2054
|
+
evidence_excerpt: z6.string().min(1),
|
|
2055
|
+
evidence_location: z6.string().nullable(),
|
|
1738
2056
|
confidence: ConfidenceSchema,
|
|
1739
2057
|
extractor: ClaimExtractorSchema,
|
|
1740
|
-
extraction_method:
|
|
1741
|
-
created_at:
|
|
2058
|
+
extraction_method: z6.string().min(1),
|
|
2059
|
+
created_at: z6.string(),
|
|
1742
2060
|
review_state: ReviewStateSchema
|
|
1743
2061
|
});
|
|
1744
2062
|
}
|
|
1745
2063
|
});
|
|
1746
2064
|
|
|
1747
2065
|
// src/claims/extract.ts
|
|
1748
|
-
import { existsSync as
|
|
1749
|
-
import { appendFile as
|
|
1750
|
-
import { join as
|
|
2066
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2067
|
+
import { appendFile as appendFile3, mkdir as mkdir7, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
2068
|
+
import { join as join8, resolve as resolve4 } from "path";
|
|
1751
2069
|
function normalize2(text) {
|
|
1752
2070
|
return text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").toLowerCase().trim();
|
|
1753
2071
|
}
|
|
@@ -1758,9 +2076,9 @@ function evidenceGrounded(excerpt, rawText) {
|
|
|
1758
2076
|
return normalize2(rawText).includes(e);
|
|
1759
2077
|
}
|
|
1760
2078
|
async function readSectionSourceIds(packPath, sectionId) {
|
|
1761
|
-
const path =
|
|
1762
|
-
if (!
|
|
1763
|
-
const text = await
|
|
2079
|
+
const path = join8(packPath, "sections", sectionId, "sources.jsonl");
|
|
2080
|
+
if (!existsSync7(path)) return [];
|
|
2081
|
+
const text = await readFile7(path, "utf8");
|
|
1764
2082
|
const ids = [];
|
|
1765
2083
|
for (const line of text.split(/\r?\n/)) {
|
|
1766
2084
|
if (!line.trim()) continue;
|
|
@@ -1773,15 +2091,15 @@ async function readSectionSourceIds(packPath, sectionId) {
|
|
|
1773
2091
|
return ids;
|
|
1774
2092
|
}
|
|
1775
2093
|
async function readSourceCard(packPath, sourceId) {
|
|
1776
|
-
const path =
|
|
1777
|
-
if (!
|
|
1778
|
-
const text = await
|
|
2094
|
+
const path = join8(packPath, "evidence", "source-cards", `${sourceId}.json`);
|
|
2095
|
+
if (!existsSync7(path)) return null;
|
|
2096
|
+
const text = await readFile7(path, "utf8");
|
|
1779
2097
|
return SourceCardSchema.parse(JSON.parse(text));
|
|
1780
2098
|
}
|
|
1781
2099
|
async function findLatestReceipt(packPath, sourceId) {
|
|
1782
|
-
const path =
|
|
1783
|
-
if (!
|
|
1784
|
-
const text = await
|
|
2100
|
+
const path = join8(packPath, "evidence", "fetch-log.jsonl");
|
|
2101
|
+
if (!existsSync7(path)) return null;
|
|
2102
|
+
const text = await readFile7(path, "utf8");
|
|
1785
2103
|
let latest = null;
|
|
1786
2104
|
for (const line of text.split(/\r?\n/)) {
|
|
1787
2105
|
if (!line.trim()) continue;
|
|
@@ -1796,9 +2114,9 @@ async function findLatestReceipt(packPath, sourceId) {
|
|
|
1796
2114
|
return latest;
|
|
1797
2115
|
}
|
|
1798
2116
|
async function readExistingClaimIds(packPath, sectionId) {
|
|
1799
|
-
const path =
|
|
1800
|
-
if (!
|
|
1801
|
-
const text = await
|
|
2117
|
+
const path = join8(packPath, "sections", sectionId, "claims.jsonl");
|
|
2118
|
+
if (!existsSync7(path)) return /* @__PURE__ */ new Set();
|
|
2119
|
+
const text = await readFile7(path, "utf8");
|
|
1802
2120
|
const set = /* @__PURE__ */ new Set();
|
|
1803
2121
|
for (const line of text.split(/\r?\n/)) {
|
|
1804
2122
|
if (!line.trim()) continue;
|
|
@@ -1873,14 +2191,14 @@ function buildClaim(args) {
|
|
|
1873
2191
|
}
|
|
1874
2192
|
async function extract(options) {
|
|
1875
2193
|
const packPath = options.packPath ? resolve4(options.packPath) : process.cwd();
|
|
1876
|
-
if (!
|
|
1877
|
-
if (!
|
|
2194
|
+
if (!existsSync7(join8(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
2195
|
+
if (!existsSync7(join8(packPath, "sections", options.sectionId)))
|
|
1878
2196
|
throw new SectionNotFoundError(options.sectionId);
|
|
1879
2197
|
const sourceIds = await readSectionSourceIds(packPath, options.sectionId);
|
|
1880
2198
|
if (sourceIds.length === 0) throw new NoSourcesGatheredError(options.sectionId);
|
|
1881
2199
|
const adapters = options.extractors ?? defaultClaimExtractors();
|
|
1882
2200
|
const extractor = await pickClaimExtractor(adapters);
|
|
1883
|
-
const claimsPath =
|
|
2201
|
+
const claimsPath = join8(packPath, "sections", options.sectionId, "claims.jsonl");
|
|
1884
2202
|
const existingIds = await readExistingClaimIds(packPath, options.sectionId);
|
|
1885
2203
|
const summary = {
|
|
1886
2204
|
sectionId: options.sectionId,
|
|
@@ -1909,9 +2227,9 @@ async function extract(options) {
|
|
|
1909
2227
|
const receipt2 = await findLatestReceipt(packPath, sourceId);
|
|
1910
2228
|
let rawText = null;
|
|
1911
2229
|
if (receipt2?.raw_text_path) {
|
|
1912
|
-
const raw =
|
|
1913
|
-
if (
|
|
1914
|
-
rawText = await
|
|
2230
|
+
const raw = join8(packPath, receipt2.raw_text_path);
|
|
2231
|
+
if (existsSync7(raw)) {
|
|
2232
|
+
rawText = await readFile7(raw, "utf8");
|
|
1915
2233
|
}
|
|
1916
2234
|
}
|
|
1917
2235
|
const ledger = await loadOrBuildLedger({
|
|
@@ -1967,7 +2285,7 @@ async function extract(options) {
|
|
|
1967
2285
|
summary.claimsDeduped += 1;
|
|
1968
2286
|
continue;
|
|
1969
2287
|
}
|
|
1970
|
-
await
|
|
2288
|
+
await appendFile3(claimsPath, JSON.stringify(claim) + "\n", "utf8");
|
|
1971
2289
|
existingIds.add(claim.claim_id);
|
|
1972
2290
|
summary.claimsAdded += 1;
|
|
1973
2291
|
summary.claimIds.push(claim.claim_id);
|
|
@@ -1996,10 +2314,10 @@ async function extract(options) {
|
|
|
1996
2314
|
kind: /not valid JSON/i.test(f.reason) ? "extractor_invalid_json" : /aborted|timeout/i.test(f.reason) ? "extractor_timeout" : /HTTP \d{3}/i.test(f.reason) ? "extractor_http_error" : "extractor_other"
|
|
1997
2315
|
}))
|
|
1998
2316
|
};
|
|
1999
|
-
const auditsDir =
|
|
2000
|
-
await
|
|
2317
|
+
const auditsDir = join8(packPath, "audits");
|
|
2318
|
+
await mkdir7(auditsDir, { recursive: true });
|
|
2001
2319
|
await writeFile6(
|
|
2002
|
-
|
|
2320
|
+
join8(auditsDir, `${options.sectionId}-claim-extract.json`),
|
|
2003
2321
|
JSON.stringify(receipt, null, 2),
|
|
2004
2322
|
"utf8"
|
|
2005
2323
|
);
|
|
@@ -2026,61 +2344,61 @@ var init_extract = __esm({
|
|
|
2026
2344
|
});
|
|
2027
2345
|
|
|
2028
2346
|
// src/claims/density/schema.ts
|
|
2029
|
-
import { z as
|
|
2347
|
+
import { z as z7 } from "zod";
|
|
2030
2348
|
var PerSourceDensitySchema, NearDuplicateClusterSchema, DensityFlagSchema, ClaimDensityAuditSchema;
|
|
2031
2349
|
var init_schema6 = __esm({
|
|
2032
2350
|
"src/claims/density/schema.ts"() {
|
|
2033
2351
|
"use strict";
|
|
2034
|
-
PerSourceDensitySchema =
|
|
2035
|
-
source_id:
|
|
2036
|
-
publisher:
|
|
2037
|
-
source_word_count:
|
|
2038
|
-
claim_count:
|
|
2039
|
-
claims_per_1k_words:
|
|
2040
|
-
share_of_section:
|
|
2352
|
+
PerSourceDensitySchema = z7.object({
|
|
2353
|
+
source_id: z7.string().regex(/^src_[a-f0-9]{12}$/),
|
|
2354
|
+
publisher: z7.string().nullable(),
|
|
2355
|
+
source_word_count: z7.number().int().nonnegative(),
|
|
2356
|
+
claim_count: z7.number().int().nonnegative(),
|
|
2357
|
+
claims_per_1k_words: z7.number(),
|
|
2358
|
+
share_of_section: z7.number(),
|
|
2041
2359
|
// 0..1
|
|
2042
|
-
weak_scope_count:
|
|
2043
|
-
generic_scope_count:
|
|
2360
|
+
weak_scope_count: z7.number().int().nonnegative(),
|
|
2361
|
+
generic_scope_count: z7.number().int().nonnegative()
|
|
2044
2362
|
});
|
|
2045
|
-
NearDuplicateClusterSchema =
|
|
2046
|
-
representative_assert:
|
|
2047
|
-
member_count:
|
|
2048
|
-
claim_ids:
|
|
2363
|
+
NearDuplicateClusterSchema = z7.object({
|
|
2364
|
+
representative_assert: z7.string(),
|
|
2365
|
+
member_count: z7.number().int().nonnegative(),
|
|
2366
|
+
claim_ids: z7.array(z7.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/))
|
|
2049
2367
|
});
|
|
2050
|
-
DensityFlagSchema =
|
|
2051
|
-
type:
|
|
2368
|
+
DensityFlagSchema = z7.object({
|
|
2369
|
+
type: z7.enum([
|
|
2052
2370
|
"source_dominance",
|
|
2053
2371
|
"high_per_word_density",
|
|
2054
2372
|
"large_near_duplicate_cluster",
|
|
2055
2373
|
"weak_scope_majority"
|
|
2056
2374
|
]),
|
|
2057
|
-
severity:
|
|
2058
|
-
message:
|
|
2059
|
-
affects_source_ids:
|
|
2060
|
-
affects_claim_ids:
|
|
2375
|
+
severity: z7.enum(["info", "warn", "block"]),
|
|
2376
|
+
message: z7.string(),
|
|
2377
|
+
affects_source_ids: z7.array(z7.string().regex(/^src_[a-f0-9]{12}$/)).default([]),
|
|
2378
|
+
affects_claim_ids: z7.array(z7.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/)).default([])
|
|
2061
2379
|
});
|
|
2062
|
-
ClaimDensityAuditSchema =
|
|
2063
|
-
audit_id:
|
|
2064
|
-
section_id:
|
|
2065
|
-
audited_at:
|
|
2066
|
-
research_os_version:
|
|
2067
|
-
candidate_claim_count:
|
|
2068
|
-
source_count:
|
|
2069
|
-
total_source_word_count:
|
|
2070
|
-
claims_per_1k_words:
|
|
2071
|
-
weak_scope_count:
|
|
2072
|
-
generic_scope_count:
|
|
2073
|
-
per_source:
|
|
2074
|
-
near_duplicate_clusters:
|
|
2075
|
-
flags:
|
|
2380
|
+
ClaimDensityAuditSchema = z7.object({
|
|
2381
|
+
audit_id: z7.string().regex(/^cda_[0-9]+_[a-z0-9-]+$/),
|
|
2382
|
+
section_id: z7.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
2383
|
+
audited_at: z7.string(),
|
|
2384
|
+
research_os_version: z7.string(),
|
|
2385
|
+
candidate_claim_count: z7.number().int().nonnegative(),
|
|
2386
|
+
source_count: z7.number().int().nonnegative(),
|
|
2387
|
+
total_source_word_count: z7.number().int().nonnegative(),
|
|
2388
|
+
claims_per_1k_words: z7.number(),
|
|
2389
|
+
weak_scope_count: z7.number().int().nonnegative(),
|
|
2390
|
+
generic_scope_count: z7.number().int().nonnegative(),
|
|
2391
|
+
per_source: z7.array(PerSourceDensitySchema),
|
|
2392
|
+
near_duplicate_clusters: z7.array(NearDuplicateClusterSchema),
|
|
2393
|
+
flags: z7.array(DensityFlagSchema)
|
|
2076
2394
|
});
|
|
2077
2395
|
}
|
|
2078
2396
|
});
|
|
2079
2397
|
|
|
2080
2398
|
// src/claims/density/run.ts
|
|
2081
|
-
import { existsSync as
|
|
2082
|
-
import { mkdir as
|
|
2083
|
-
import { join as
|
|
2399
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2400
|
+
import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile7 } from "fs/promises";
|
|
2401
|
+
import { join as join9, resolve as resolve5 } from "path";
|
|
2084
2402
|
function normalize3(s) {
|
|
2085
2403
|
return s.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").toLowerCase().replace(/[^a-z0-9 ]+/g, " ").replace(/\s+/g, " ").trim();
|
|
2086
2404
|
}
|
|
@@ -2089,9 +2407,9 @@ function countWords(text) {
|
|
|
2089
2407
|
return normalize3(text).split(" ").filter((w) => w.length > 0).length;
|
|
2090
2408
|
}
|
|
2091
2409
|
async function readClaims(packPath, sectionId) {
|
|
2092
|
-
const path =
|
|
2093
|
-
if (!
|
|
2094
|
-
const text = await
|
|
2410
|
+
const path = join9(packPath, "sections", sectionId, "claims.jsonl");
|
|
2411
|
+
if (!existsSync8(path)) return [];
|
|
2412
|
+
const text = await readFile8(path, "utf8");
|
|
2095
2413
|
const out = [];
|
|
2096
2414
|
for (const line of text.split(/\r?\n/)) {
|
|
2097
2415
|
if (!line.trim()) continue;
|
|
@@ -2105,10 +2423,10 @@ async function readClaims(packPath, sectionId) {
|
|
|
2105
2423
|
async function readSourceCards(packPath, sourceIds) {
|
|
2106
2424
|
const out = /* @__PURE__ */ new Map();
|
|
2107
2425
|
for (const sid of sourceIds) {
|
|
2108
|
-
const p =
|
|
2109
|
-
if (!
|
|
2426
|
+
const p = join9(packPath, "evidence", "source-cards", `${sid}.json`);
|
|
2427
|
+
if (!existsSync8(p)) continue;
|
|
2110
2428
|
try {
|
|
2111
|
-
out.set(sid, SourceCardSchema.parse(JSON.parse(await
|
|
2429
|
+
out.set(sid, SourceCardSchema.parse(JSON.parse(await readFile8(p, "utf8"))));
|
|
2112
2430
|
} catch {
|
|
2113
2431
|
}
|
|
2114
2432
|
}
|
|
@@ -2116,9 +2434,9 @@ async function readSourceCards(packPath, sourceIds) {
|
|
|
2116
2434
|
}
|
|
2117
2435
|
async function readLatestReceipts(packPath) {
|
|
2118
2436
|
const out = /* @__PURE__ */ new Map();
|
|
2119
|
-
const path =
|
|
2120
|
-
if (!
|
|
2121
|
-
const text = await
|
|
2437
|
+
const path = join9(packPath, "evidence", "fetch-log.jsonl");
|
|
2438
|
+
if (!existsSync8(path)) return out;
|
|
2439
|
+
const text = await readFile8(path, "utf8");
|
|
2122
2440
|
for (const line of text.split(/\r?\n/)) {
|
|
2123
2441
|
if (!line.trim()) continue;
|
|
2124
2442
|
try {
|
|
@@ -2133,9 +2451,9 @@ async function readLatestReceipts(packPath) {
|
|
|
2133
2451
|
}
|
|
2134
2452
|
async function readRawText(packPath, receipt) {
|
|
2135
2453
|
if (!receipt.raw_text_path) return null;
|
|
2136
|
-
const p =
|
|
2137
|
-
if (!
|
|
2138
|
-
return await
|
|
2454
|
+
const p = join9(packPath, receipt.raw_text_path);
|
|
2455
|
+
if (!existsSync8(p)) return null;
|
|
2456
|
+
return await readFile8(p, "utf8");
|
|
2139
2457
|
}
|
|
2140
2458
|
function isWeakScope(claim) {
|
|
2141
2459
|
return claim.scope === null && claim.not === null && claim.asserts.length > 40;
|
|
@@ -2268,8 +2586,8 @@ function buildMarkdown(audit2) {
|
|
|
2268
2586
|
}
|
|
2269
2587
|
async function auditDensity(options) {
|
|
2270
2588
|
const packPath = options.packPath ? resolve5(options.packPath) : process.cwd();
|
|
2271
|
-
if (!
|
|
2272
|
-
if (!
|
|
2589
|
+
if (!existsSync8(join9(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
2590
|
+
if (!existsSync8(join9(packPath, "sections", options.sectionId)))
|
|
2273
2591
|
throw new SectionNotFoundError(options.sectionId);
|
|
2274
2592
|
const claims = await readClaims(packPath, options.sectionId);
|
|
2275
2593
|
const allSourceIds = Array.from(
|
|
@@ -2342,10 +2660,10 @@ async function auditDensity(options) {
|
|
|
2342
2660
|
}));
|
|
2343
2661
|
const flags = [...buildFlags(partial), ...clusterFlags];
|
|
2344
2662
|
const audit2 = ClaimDensityAuditSchema.parse({ ...partial, flags });
|
|
2345
|
-
const auditsDir =
|
|
2346
|
-
await
|
|
2347
|
-
const jsonPath =
|
|
2348
|
-
const markdownPath =
|
|
2663
|
+
const auditsDir = join9(packPath, "audits");
|
|
2664
|
+
await mkdir8(auditsDir, { recursive: true });
|
|
2665
|
+
const jsonPath = join9(auditsDir, `${options.sectionId}-claim-density.json`);
|
|
2666
|
+
const markdownPath = join9(auditsDir, `${options.sectionId}-claim-density.md`);
|
|
2349
2667
|
await writeFile7(jsonPath, JSON.stringify(audit2, null, 2), "utf8");
|
|
2350
2668
|
await writeFile7(markdownPath, buildMarkdown(audit2), "utf8");
|
|
2351
2669
|
return { audit: audit2, jsonPath, markdownPath };
|
|
@@ -2389,12 +2707,12 @@ var init_claims = __esm({
|
|
|
2389
2707
|
});
|
|
2390
2708
|
|
|
2391
2709
|
// src/contradictions/schema.ts
|
|
2392
|
-
import { z as
|
|
2710
|
+
import { z as z8 } from "zod";
|
|
2393
2711
|
var ContradictionTypeSchema, SeveritySchema, OverlapAssessmentSchema, ContradictionDetectorSchema, ContradictionStatusSchema, ContradictionConfidenceSchema, ContradictionSchema;
|
|
2394
2712
|
var init_schema7 = __esm({
|
|
2395
2713
|
"src/contradictions/schema.ts"() {
|
|
2396
2714
|
"use strict";
|
|
2397
|
-
ContradictionTypeSchema =
|
|
2715
|
+
ContradictionTypeSchema = z8.enum([
|
|
2398
2716
|
"direct_conflict",
|
|
2399
2717
|
"scope_conflict",
|
|
2400
2718
|
"temporal_conflict",
|
|
@@ -2402,37 +2720,37 @@ var init_schema7 = __esm({
|
|
|
2402
2720
|
"evidence_conflict",
|
|
2403
2721
|
"overgeneralization_risk"
|
|
2404
2722
|
]);
|
|
2405
|
-
SeveritySchema =
|
|
2406
|
-
OverlapAssessmentSchema =
|
|
2723
|
+
SeveritySchema = z8.enum(["low", "medium", "high", "blocking"]);
|
|
2724
|
+
OverlapAssessmentSchema = z8.enum([
|
|
2407
2725
|
"fully_overlapping",
|
|
2408
2726
|
"partially_overlapping",
|
|
2409
2727
|
"non_overlapping",
|
|
2410
2728
|
"unknown"
|
|
2411
2729
|
]);
|
|
2412
|
-
ContradictionDetectorSchema =
|
|
2413
|
-
ContradictionStatusSchema =
|
|
2730
|
+
ContradictionDetectorSchema = z8.enum(["heuristic", "ollama-intern"]);
|
|
2731
|
+
ContradictionStatusSchema = z8.enum([
|
|
2414
2732
|
"unresolved",
|
|
2415
2733
|
"reconciled",
|
|
2416
2734
|
"preserved_deliberately",
|
|
2417
2735
|
"rejected"
|
|
2418
2736
|
]);
|
|
2419
|
-
ContradictionConfidenceSchema =
|
|
2420
|
-
ContradictionSchema =
|
|
2421
|
-
contradiction_id:
|
|
2422
|
-
section_id:
|
|
2423
|
-
claim_ids:
|
|
2424
|
-
source_ids:
|
|
2737
|
+
ContradictionConfidenceSchema = z8.enum(["low", "medium", "high"]);
|
|
2738
|
+
ContradictionSchema = z8.object({
|
|
2739
|
+
contradiction_id: z8.string().regex(/^cnt_[a-f0-9]{12}_(heuristic|ollama_intern)$/),
|
|
2740
|
+
section_id: z8.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
2741
|
+
claim_ids: z8.array(z8.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/)).length(2, "contradictions are pair-wise in v0.1"),
|
|
2742
|
+
source_ids: z8.array(z8.string().regex(/^src_[a-f0-9]{12}$/)).min(1),
|
|
2425
2743
|
type: ContradictionTypeSchema,
|
|
2426
|
-
summary:
|
|
2427
|
-
scope_analysis:
|
|
2744
|
+
summary: z8.string().min(1),
|
|
2745
|
+
scope_analysis: z8.string(),
|
|
2428
2746
|
overlap_assessment: OverlapAssessmentSchema,
|
|
2429
2747
|
severity: SeveritySchema,
|
|
2430
2748
|
confidence: ContradictionConfidenceSchema,
|
|
2431
2749
|
detector: ContradictionDetectorSchema,
|
|
2432
|
-
detection_method:
|
|
2433
|
-
evidence:
|
|
2750
|
+
detection_method: z8.string().min(1),
|
|
2751
|
+
evidence: z8.string(),
|
|
2434
2752
|
status: ContradictionStatusSchema,
|
|
2435
|
-
created_at:
|
|
2753
|
+
created_at: z8.string()
|
|
2436
2754
|
});
|
|
2437
2755
|
}
|
|
2438
2756
|
});
|
|
@@ -2877,12 +3195,12 @@ var init_markdown = __esm({
|
|
|
2877
3195
|
});
|
|
2878
3196
|
|
|
2879
3197
|
// src/triage/schema.ts
|
|
2880
|
-
import { z as
|
|
3198
|
+
import { z as z9 } from "zod";
|
|
2881
3199
|
var TriageDecisionSchema, ClaimTriageSchema, TriageSummarySchema;
|
|
2882
3200
|
var init_schema8 = __esm({
|
|
2883
3201
|
"src/triage/schema.ts"() {
|
|
2884
3202
|
"use strict";
|
|
2885
|
-
TriageDecisionSchema =
|
|
3203
|
+
TriageDecisionSchema = z9.enum([
|
|
2886
3204
|
// Passes triage and is forwarded to review.
|
|
2887
3205
|
"selected_for_review",
|
|
2888
3206
|
// Parked: kept on the canonical ledger as research truth, but not advanced.
|
|
@@ -2894,36 +3212,36 @@ var init_schema8 = __esm({
|
|
|
2894
3212
|
"needs_scope_repair",
|
|
2895
3213
|
"needs_human_review"
|
|
2896
3214
|
]);
|
|
2897
|
-
ClaimTriageSchema =
|
|
2898
|
-
triage_id:
|
|
2899
|
-
claim_id:
|
|
2900
|
-
section_id:
|
|
3215
|
+
ClaimTriageSchema = z9.object({
|
|
3216
|
+
triage_id: z9.string().regex(/^tri_[a-f0-9]{12}$/),
|
|
3217
|
+
claim_id: z9.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/),
|
|
3218
|
+
section_id: z9.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
2901
3219
|
decision: TriageDecisionSchema,
|
|
2902
|
-
reason:
|
|
3220
|
+
reason: z9.string().min(1),
|
|
2903
3221
|
// Rank among selected_for_review claims (1 = highest priority). null for
|
|
2904
3222
|
// any non-selected decision.
|
|
2905
|
-
rank:
|
|
3223
|
+
rank: z9.number().int().positive().nullable(),
|
|
2906
3224
|
// Quality score [0..1] used to sort. Stable. Higher = better.
|
|
2907
|
-
quality_score:
|
|
2908
|
-
triage_method:
|
|
2909
|
-
created_at:
|
|
2910
|
-
});
|
|
2911
|
-
TriageSummarySchema =
|
|
2912
|
-
summary_id:
|
|
2913
|
-
section_id:
|
|
2914
|
-
triaged_at:
|
|
2915
|
-
research_os_version:
|
|
2916
|
-
triage_method:
|
|
2917
|
-
candidate_claims:
|
|
2918
|
-
decisions:
|
|
2919
|
-
per_source_cap:
|
|
2920
|
-
duplicate_clusters_collapsed:
|
|
2921
|
-
selected_count:
|
|
2922
|
-
selected_per_source:
|
|
2923
|
-
|
|
2924
|
-
source_id:
|
|
2925
|
-
selected:
|
|
2926
|
-
total:
|
|
3225
|
+
quality_score: z9.number().min(0).max(1),
|
|
3226
|
+
triage_method: z9.string().min(1),
|
|
3227
|
+
created_at: z9.string()
|
|
3228
|
+
});
|
|
3229
|
+
TriageSummarySchema = z9.object({
|
|
3230
|
+
summary_id: z9.string().regex(/^tris_[0-9]+_[a-z0-9-]+$/),
|
|
3231
|
+
section_id: z9.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
3232
|
+
triaged_at: z9.string(),
|
|
3233
|
+
research_os_version: z9.string(),
|
|
3234
|
+
triage_method: z9.string(),
|
|
3235
|
+
candidate_claims: z9.number().int().nonnegative(),
|
|
3236
|
+
decisions: z9.record(TriageDecisionSchema, z9.number().int().nonnegative()),
|
|
3237
|
+
per_source_cap: z9.number().int().positive(),
|
|
3238
|
+
duplicate_clusters_collapsed: z9.number().int().nonnegative(),
|
|
3239
|
+
selected_count: z9.number().int().nonnegative(),
|
|
3240
|
+
selected_per_source: z9.array(
|
|
3241
|
+
z9.object({
|
|
3242
|
+
source_id: z9.string().regex(/^src_[a-f0-9]{12}$/),
|
|
3243
|
+
selected: z9.number().int().nonnegative(),
|
|
3244
|
+
total: z9.number().int().nonnegative()
|
|
2927
3245
|
})
|
|
2928
3246
|
)
|
|
2929
3247
|
});
|
|
@@ -2936,10 +3254,10 @@ __export(run_exports, {
|
|
|
2936
3254
|
readTriagedClaimIds: () => readTriagedClaimIds,
|
|
2937
3255
|
triage: () => triage
|
|
2938
3256
|
});
|
|
2939
|
-
import { existsSync as
|
|
3257
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2940
3258
|
import { createHash as createHash2 } from "crypto";
|
|
2941
|
-
import { mkdir as
|
|
2942
|
-
import { join as
|
|
3259
|
+
import { mkdir as mkdir9, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
3260
|
+
import { join as join10, resolve as resolve6 } from "path";
|
|
2943
3261
|
function normaliseAssert(s) {
|
|
2944
3262
|
return s.toLowerCase().replace(/[^a-z0-9 ]+/g, " ").replace(/\s+/g, " ").trim();
|
|
2945
3263
|
}
|
|
@@ -2959,9 +3277,9 @@ function makeTriageId(claimId) {
|
|
|
2959
3277
|
return "tri_" + createHash2("sha256").update(claimId).digest("hex").slice(0, 12);
|
|
2960
3278
|
}
|
|
2961
3279
|
async function readClaims2(packPath, sectionId) {
|
|
2962
|
-
const path =
|
|
2963
|
-
if (!
|
|
2964
|
-
const text = await
|
|
3280
|
+
const path = join10(packPath, "sections", sectionId, "claims.jsonl");
|
|
3281
|
+
if (!existsSync9(path)) return [];
|
|
3282
|
+
const text = await readFile9(path, "utf8");
|
|
2965
3283
|
const out = [];
|
|
2966
3284
|
for (const line of text.split(/\r?\n/)) {
|
|
2967
3285
|
if (!line.trim()) continue;
|
|
@@ -2974,8 +3292,8 @@ async function readClaims2(packPath, sectionId) {
|
|
|
2974
3292
|
}
|
|
2975
3293
|
async function triage(options) {
|
|
2976
3294
|
const packPath = options.packPath ? resolve6(options.packPath) : process.cwd();
|
|
2977
|
-
if (!
|
|
2978
|
-
if (!
|
|
3295
|
+
if (!existsSync9(join10(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
3296
|
+
if (!existsSync9(join10(packPath, "sections", options.sectionId)))
|
|
2979
3297
|
throw new SectionNotFoundError(options.sectionId);
|
|
2980
3298
|
const perSourceCap = options.perSourceCap ?? DEFAULT_PER_SOURCE_CAP;
|
|
2981
3299
|
const minAssertChars = options.minAssertChars ?? DEFAULT_MIN_ASSERT_CHARS;
|
|
@@ -3109,13 +3427,13 @@ async function triage(options) {
|
|
|
3109
3427
|
total
|
|
3110
3428
|
})).sort((a, b) => b.total - a.total)
|
|
3111
3429
|
});
|
|
3112
|
-
const sectionDir =
|
|
3113
|
-
const auditsDir =
|
|
3114
|
-
await
|
|
3115
|
-
await
|
|
3116
|
-
const triageJsonlPath =
|
|
3117
|
-
const triageMarkdownPath =
|
|
3118
|
-
const summaryJsonPath =
|
|
3430
|
+
const sectionDir = join10(packPath, "sections", options.sectionId);
|
|
3431
|
+
const auditsDir = join10(packPath, "audits");
|
|
3432
|
+
await mkdir9(sectionDir, { recursive: true });
|
|
3433
|
+
await mkdir9(auditsDir, { recursive: true });
|
|
3434
|
+
const triageJsonlPath = join10(sectionDir, "claim-triage.jsonl");
|
|
3435
|
+
const triageMarkdownPath = join10(sectionDir, "claim-triage.md");
|
|
3436
|
+
const summaryJsonPath = join10(auditsDir, `${options.sectionId}-claim-triage.json`);
|
|
3119
3437
|
await writeFile8(triageJsonlPath, records.map((r) => JSON.stringify(r)).join("\n") + "\n", "utf8");
|
|
3120
3438
|
await writeFile8(triageMarkdownPath, buildMarkdown2(records, summary), "utf8");
|
|
3121
3439
|
await writeFile8(summaryJsonPath, JSON.stringify(summary, null, 2), "utf8");
|
|
@@ -3135,10 +3453,10 @@ async function triage(options) {
|
|
|
3135
3453
|
};
|
|
3136
3454
|
}
|
|
3137
3455
|
async function readTriagedClaimIds(packPath, sectionId) {
|
|
3138
|
-
const path =
|
|
3456
|
+
const path = join10(packPath, "sections", sectionId, "claim-triage.jsonl");
|
|
3139
3457
|
const out = /* @__PURE__ */ new Set();
|
|
3140
|
-
if (!
|
|
3141
|
-
const text = await
|
|
3458
|
+
if (!existsSync9(path)) return out;
|
|
3459
|
+
const text = await readFile9(path, "utf8");
|
|
3142
3460
|
for (const line of text.split(/\r?\n/)) {
|
|
3143
3461
|
if (!line.trim()) continue;
|
|
3144
3462
|
try {
|
|
@@ -3212,13 +3530,13 @@ var init_run2 = __esm({
|
|
|
3212
3530
|
|
|
3213
3531
|
// src/contradictions/map.ts
|
|
3214
3532
|
import { createHash as createHash3 } from "crypto";
|
|
3215
|
-
import { existsSync as
|
|
3216
|
-
import { appendFile as
|
|
3217
|
-
import { join as
|
|
3533
|
+
import { existsSync as existsSync10 } from "fs";
|
|
3534
|
+
import { appendFile as appendFile4, readFile as readFile10, writeFile as writeFile9 } from "fs/promises";
|
|
3535
|
+
import { join as join11, resolve as resolve7 } from "path";
|
|
3218
3536
|
async function readCandidateClaims(packPath, sectionId) {
|
|
3219
|
-
const path =
|
|
3220
|
-
if (!
|
|
3221
|
-
const text = await
|
|
3537
|
+
const path = join11(packPath, "sections", sectionId, "claims.jsonl");
|
|
3538
|
+
if (!existsSync10(path)) return [];
|
|
3539
|
+
const text = await readFile10(path, "utf8");
|
|
3222
3540
|
const claims = [];
|
|
3223
3541
|
for (const line of text.split(/\r?\n/)) {
|
|
3224
3542
|
if (!line.trim()) continue;
|
|
@@ -3229,9 +3547,9 @@ async function readCandidateClaims(packPath, sectionId) {
|
|
|
3229
3547
|
return claims;
|
|
3230
3548
|
}
|
|
3231
3549
|
async function readExistingContradictions(packPath, sectionId) {
|
|
3232
|
-
const path =
|
|
3233
|
-
if (!
|
|
3234
|
-
const text = await
|
|
3550
|
+
const path = join11(packPath, "sections", sectionId, "contradictions.jsonl");
|
|
3551
|
+
if (!existsSync10(path)) return [];
|
|
3552
|
+
const text = await readFile10(path, "utf8");
|
|
3235
3553
|
const list = [];
|
|
3236
3554
|
for (const line of text.split(/\r?\n/)) {
|
|
3237
3555
|
if (!line.trim()) continue;
|
|
@@ -3316,9 +3634,9 @@ async function resolveDetector(options) {
|
|
|
3316
3634
|
}
|
|
3317
3635
|
async function map(options) {
|
|
3318
3636
|
const packPath = options.packPath ? resolve7(options.packPath) : process.cwd();
|
|
3319
|
-
if (!
|
|
3320
|
-
const sectionDir =
|
|
3321
|
-
if (!
|
|
3637
|
+
if (!existsSync10(join11(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
3638
|
+
const sectionDir = join11(packPath, "sections", options.sectionId);
|
|
3639
|
+
if (!existsSync10(sectionDir)) throw new SectionNotFoundError(options.sectionId);
|
|
3322
3640
|
let candidateClaims = await readCandidateClaims(packPath, options.sectionId);
|
|
3323
3641
|
if (options.triagedOnly) {
|
|
3324
3642
|
const { readTriagedClaimIds: readTriagedClaimIds2 } = await Promise.resolve().then(() => (init_run2(), run_exports));
|
|
@@ -3338,8 +3656,8 @@ async function map(options) {
|
|
|
3338
3656
|
detectorError: null,
|
|
3339
3657
|
detectorAnnouncement: announcement
|
|
3340
3658
|
};
|
|
3341
|
-
const ledgerPath =
|
|
3342
|
-
const mdPath =
|
|
3659
|
+
const ledgerPath = join11(sectionDir, "contradictions.jsonl");
|
|
3660
|
+
const mdPath = join11(sectionDir, "contradictions.md");
|
|
3343
3661
|
const existingContradictions = await readExistingContradictions(
|
|
3344
3662
|
packPath,
|
|
3345
3663
|
options.sectionId
|
|
@@ -3384,7 +3702,7 @@ async function map(options) {
|
|
|
3384
3702
|
summary.contradictionsDeduped += 1;
|
|
3385
3703
|
continue;
|
|
3386
3704
|
}
|
|
3387
|
-
await
|
|
3705
|
+
await appendFile4(ledgerPath, JSON.stringify(c) + "\n", "utf8");
|
|
3388
3706
|
existingIds.add(c.contradiction_id);
|
|
3389
3707
|
existingContradictions.push(c);
|
|
3390
3708
|
summary.contradictionsAdded += 1;
|
|
@@ -3420,31 +3738,31 @@ var init_map = __esm({
|
|
|
3420
3738
|
});
|
|
3421
3739
|
|
|
3422
3740
|
// src/contradictions/resolution-schema.ts
|
|
3423
|
-
import { z as
|
|
3741
|
+
import { z as z10 } from "zod";
|
|
3424
3742
|
var ResolutionStatusSchema, ContradictionResolutionSchema;
|
|
3425
3743
|
var init_resolution_schema = __esm({
|
|
3426
3744
|
"src/contradictions/resolution-schema.ts"() {
|
|
3427
3745
|
"use strict";
|
|
3428
|
-
ResolutionStatusSchema =
|
|
3746
|
+
ResolutionStatusSchema = z10.enum([
|
|
3429
3747
|
"unresolved",
|
|
3430
3748
|
"resolved",
|
|
3431
3749
|
"preserved",
|
|
3432
3750
|
"rejected"
|
|
3433
3751
|
]);
|
|
3434
|
-
ContradictionResolutionSchema =
|
|
3435
|
-
contradiction_id:
|
|
3752
|
+
ContradictionResolutionSchema = z10.object({
|
|
3753
|
+
contradiction_id: z10.string().min(1),
|
|
3436
3754
|
status: ResolutionStatusSchema,
|
|
3437
|
-
reason:
|
|
3438
|
-
resolved_at:
|
|
3439
|
-
resolved_by:
|
|
3755
|
+
reason: z10.string().min(4),
|
|
3756
|
+
resolved_at: z10.string().min(1),
|
|
3757
|
+
resolved_by: z10.string().min(1)
|
|
3440
3758
|
});
|
|
3441
3759
|
}
|
|
3442
3760
|
});
|
|
3443
3761
|
|
|
3444
3762
|
// src/contradictions/resolve.ts
|
|
3445
|
-
import { appendFile as
|
|
3446
|
-
import { existsSync as
|
|
3447
|
-
import { join as
|
|
3763
|
+
import { appendFile as appendFile5, readFile as readFile11 } from "fs/promises";
|
|
3764
|
+
import { existsSync as existsSync11 } from "fs";
|
|
3765
|
+
import { join as join12 } from "path";
|
|
3448
3766
|
function latestEffectiveStatuses(ledgerPath, text) {
|
|
3449
3767
|
const entries = [];
|
|
3450
3768
|
for (const line of text.split(/\r?\n/)) {
|
|
@@ -3471,15 +3789,15 @@ async function resolve8(options) {
|
|
|
3471
3789
|
if (reason.length < 4) {
|
|
3472
3790
|
throw new Error("reason must be at least 4 characters");
|
|
3473
3791
|
}
|
|
3474
|
-
const sectionDir =
|
|
3475
|
-
if (!
|
|
3792
|
+
const sectionDir = join12(packPath, "sections", sectionId);
|
|
3793
|
+
if (!existsSync11(sectionDir)) {
|
|
3476
3794
|
throw new SectionNotFoundError(sectionId);
|
|
3477
3795
|
}
|
|
3478
|
-
const candidatesPath2 =
|
|
3479
|
-
const ledgerPath =
|
|
3796
|
+
const candidatesPath2 = join12(sectionDir, "contradictions.jsonl");
|
|
3797
|
+
const ledgerPath = join12(sectionDir, "contradiction-resolutions.jsonl");
|
|
3480
3798
|
const candidates = [];
|
|
3481
|
-
if (
|
|
3482
|
-
const text = await
|
|
3799
|
+
if (existsSync11(candidatesPath2)) {
|
|
3800
|
+
const text = await readFile11(candidatesPath2, "utf8");
|
|
3483
3801
|
for (const line of text.split(/\r?\n/)) {
|
|
3484
3802
|
if (!line.trim()) continue;
|
|
3485
3803
|
try {
|
|
@@ -3494,7 +3812,7 @@ async function resolve8(options) {
|
|
|
3494
3812
|
}
|
|
3495
3813
|
}
|
|
3496
3814
|
}
|
|
3497
|
-
const existingResolutions =
|
|
3815
|
+
const existingResolutions = existsSync11(ledgerPath) ? latestEffectiveStatuses(ledgerPath, await readFile11(ledgerPath, "utf8")) : /* @__PURE__ */ new Map();
|
|
3498
3816
|
const knownIds = new Set(candidates.map((c) => c.contradiction_id));
|
|
3499
3817
|
let targetIds;
|
|
3500
3818
|
if (all) {
|
|
@@ -3526,7 +3844,7 @@ async function resolve8(options) {
|
|
|
3526
3844
|
applied++;
|
|
3527
3845
|
}
|
|
3528
3846
|
if (lines.length > 0) {
|
|
3529
|
-
await
|
|
3847
|
+
await appendFile5(ledgerPath, lines.join("\n") + "\n", "utf8");
|
|
3530
3848
|
}
|
|
3531
3849
|
return { sectionId, applied, skipped, ledgerPath };
|
|
3532
3850
|
}
|
|
@@ -3553,12 +3871,12 @@ var init_contradictions = __esm({
|
|
|
3553
3871
|
});
|
|
3554
3872
|
|
|
3555
3873
|
// src/review/schema.ts
|
|
3556
|
-
import { z as
|
|
3874
|
+
import { z as z11 } from "zod";
|
|
3557
3875
|
var FindingCategorySchema, FindingSeveritySchema, ReviewerNameSchema, ReviewDecisionSchema, ReviewConfidenceSchema, ReviewFindingSchema, ClaimReviewSchema, ReviewSnapshotSchema;
|
|
3558
3876
|
var init_schema9 = __esm({
|
|
3559
3877
|
"src/review/schema.ts"() {
|
|
3560
3878
|
"use strict";
|
|
3561
|
-
FindingCategorySchema =
|
|
3879
|
+
FindingCategorySchema = z11.enum([
|
|
3562
3880
|
"unsupported_claim",
|
|
3563
3881
|
"ungrounded_excerpt",
|
|
3564
3882
|
"stale_claim",
|
|
@@ -3585,9 +3903,9 @@ var init_schema9 = __esm({
|
|
|
3585
3903
|
// a low-value claim can appear in a perfectly-sized section.
|
|
3586
3904
|
"valid_but_low_value"
|
|
3587
3905
|
]);
|
|
3588
|
-
FindingSeveritySchema =
|
|
3589
|
-
ReviewerNameSchema =
|
|
3590
|
-
ReviewDecisionSchema =
|
|
3906
|
+
FindingSeveritySchema = z11.enum(["info", "warn", "block"]);
|
|
3907
|
+
ReviewerNameSchema = z11.enum(["heuristic", "ollama-intern"]);
|
|
3908
|
+
ReviewDecisionSchema = z11.enum([
|
|
3591
3909
|
"accepted_for_synthesis",
|
|
3592
3910
|
"rejected",
|
|
3593
3911
|
"needs_scope_repair",
|
|
@@ -3595,43 +3913,47 @@ var init_schema9 = __esm({
|
|
|
3595
3913
|
"needs_contradiction_mapping",
|
|
3596
3914
|
"needs_human_review"
|
|
3597
3915
|
]);
|
|
3598
|
-
ReviewConfidenceSchema =
|
|
3599
|
-
ReviewFindingSchema =
|
|
3600
|
-
finding_id:
|
|
3601
|
-
section_id:
|
|
3602
|
-
claim_ids:
|
|
3603
|
-
source_ids:
|
|
3916
|
+
ReviewConfidenceSchema = z11.enum(["low", "medium", "high"]);
|
|
3917
|
+
ReviewFindingSchema = z11.object({
|
|
3918
|
+
finding_id: z11.string().regex(/^fnd_[a-f0-9]{12}$/),
|
|
3919
|
+
section_id: z11.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
3920
|
+
claim_ids: z11.array(z11.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/)),
|
|
3921
|
+
source_ids: z11.array(z11.string().regex(/^src_[a-f0-9]{12}$/)),
|
|
3604
3922
|
category: FindingCategorySchema,
|
|
3605
3923
|
severity: FindingSeveritySchema,
|
|
3606
|
-
summary:
|
|
3607
|
-
evidence:
|
|
3608
|
-
required_action:
|
|
3924
|
+
summary: z11.string().min(1),
|
|
3925
|
+
evidence: z11.string(),
|
|
3926
|
+
required_action: z11.string(),
|
|
3609
3927
|
reviewer: ReviewerNameSchema,
|
|
3610
|
-
review_method:
|
|
3928
|
+
review_method: z11.string().min(1),
|
|
3611
3929
|
confidence: ReviewConfidenceSchema,
|
|
3612
|
-
created_at:
|
|
3930
|
+
created_at: z11.string()
|
|
3613
3931
|
});
|
|
3614
|
-
ClaimReviewSchema =
|
|
3615
|
-
claim_id:
|
|
3932
|
+
ClaimReviewSchema = z11.object({
|
|
3933
|
+
claim_id: z11.string().regex(/^clm_[a-f0-9]{12}_(heuristic|ollama_intern)_\d+$/),
|
|
3616
3934
|
decision: ReviewDecisionSchema,
|
|
3617
|
-
reason:
|
|
3618
|
-
finding_ids:
|
|
3935
|
+
reason: z11.string().min(1),
|
|
3936
|
+
finding_ids: z11.array(z11.string()),
|
|
3619
3937
|
reviewer: ReviewerNameSchema,
|
|
3620
|
-
review_method:
|
|
3621
|
-
created_at:
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3938
|
+
review_method: z11.string().min(1),
|
|
3939
|
+
created_at: z11.string(),
|
|
3940
|
+
// v0.5: optional profile lineage. Additive-optional — pre-v0.5 records
|
|
3941
|
+
// without this field parse cleanly. Frozen packs unaffected (Zod .optional()
|
|
3942
|
+
// with no .default() leaves absent keys absent on round-trip).
|
|
3943
|
+
profile: z11.string().optional()
|
|
3944
|
+
});
|
|
3945
|
+
ReviewSnapshotSchema = z11.object({
|
|
3946
|
+
section_id: z11.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
3625
3947
|
reviewer: ReviewerNameSchema,
|
|
3626
|
-
review_method:
|
|
3627
|
-
reviewed_at:
|
|
3628
|
-
candidate_claims:
|
|
3629
|
-
findings:
|
|
3630
|
-
claim_reviews:
|
|
3631
|
-
decision_counts:
|
|
3632
|
-
severity_counts:
|
|
3633
|
-
llm_findings_rejected_ungrounded:
|
|
3634
|
-
promoted_to_reviewed:
|
|
3948
|
+
review_method: z11.string(),
|
|
3949
|
+
reviewed_at: z11.string(),
|
|
3950
|
+
candidate_claims: z11.number().int().nonnegative(),
|
|
3951
|
+
findings: z11.array(ReviewFindingSchema),
|
|
3952
|
+
claim_reviews: z11.array(ClaimReviewSchema),
|
|
3953
|
+
decision_counts: z11.record(ReviewDecisionSchema, z11.number().int().nonnegative()),
|
|
3954
|
+
severity_counts: z11.record(FindingSeveritySchema, z11.number().int().nonnegative()),
|
|
3955
|
+
llm_findings_rejected_ungrounded: z11.number().int().nonnegative(),
|
|
3956
|
+
promoted_to_reviewed: z11.boolean()
|
|
3635
3957
|
});
|
|
3636
3958
|
}
|
|
3637
3959
|
});
|
|
@@ -4519,12 +4841,12 @@ var init_markdown2 = __esm({
|
|
|
4519
4841
|
});
|
|
4520
4842
|
|
|
4521
4843
|
// src/gates/schema.ts
|
|
4522
|
-
import { z as
|
|
4844
|
+
import { z as z12 } from "zod";
|
|
4523
4845
|
var GateFamilySchema, GateCheckStatusSchema, VerdictSchema, GateCheckResultSchema, WaiverApplicationSchema, SectionGateResultSchema;
|
|
4524
4846
|
var init_schema10 = __esm({
|
|
4525
4847
|
"src/gates/schema.ts"() {
|
|
4526
4848
|
"use strict";
|
|
4527
|
-
GateFamilySchema =
|
|
4849
|
+
GateFamilySchema = z12.enum([
|
|
4528
4850
|
"source_floor",
|
|
4529
4851
|
"claim_integrity",
|
|
4530
4852
|
"scope_integrity",
|
|
@@ -4534,98 +4856,98 @@ var init_schema10 = __esm({
|
|
|
4534
4856
|
"waivers",
|
|
4535
4857
|
"accepted_claim_floor"
|
|
4536
4858
|
]);
|
|
4537
|
-
GateCheckStatusSchema =
|
|
4859
|
+
GateCheckStatusSchema = z12.enum([
|
|
4538
4860
|
"pass",
|
|
4539
4861
|
"warn",
|
|
4540
4862
|
"fail",
|
|
4541
4863
|
"pass_with_waiver",
|
|
4542
4864
|
"warn_with_waiver"
|
|
4543
4865
|
]);
|
|
4544
|
-
VerdictSchema =
|
|
4545
|
-
GateCheckResultSchema =
|
|
4866
|
+
VerdictSchema = z12.enum(["pass", "warn", "fail", "blocked"]);
|
|
4867
|
+
GateCheckResultSchema = z12.object({
|
|
4546
4868
|
family: GateFamilySchema,
|
|
4547
|
-
check:
|
|
4869
|
+
check: z12.string().min(1),
|
|
4548
4870
|
status: GateCheckStatusSchema,
|
|
4549
|
-
detail:
|
|
4550
|
-
evidence:
|
|
4551
|
-
blocks_synthesis:
|
|
4871
|
+
detail: z12.string(),
|
|
4872
|
+
evidence: z12.array(z12.string()),
|
|
4873
|
+
blocks_synthesis: z12.boolean()
|
|
4552
4874
|
});
|
|
4553
|
-
WaiverApplicationSchema =
|
|
4875
|
+
WaiverApplicationSchema = z12.object({
|
|
4554
4876
|
family: GateFamilySchema,
|
|
4555
|
-
check:
|
|
4556
|
-
reason:
|
|
4557
|
-
compensating_controls:
|
|
4877
|
+
check: z12.string().min(1),
|
|
4878
|
+
reason: z12.string().min(1),
|
|
4879
|
+
compensating_controls: z12.array(z12.string()),
|
|
4558
4880
|
original_status: GateCheckStatusSchema,
|
|
4559
4881
|
new_status: GateCheckStatusSchema
|
|
4560
4882
|
});
|
|
4561
|
-
SectionGateResultSchema =
|
|
4562
|
-
section_id:
|
|
4883
|
+
SectionGateResultSchema = z12.object({
|
|
4884
|
+
section_id: z12.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
4563
4885
|
verdict: VerdictSchema,
|
|
4564
|
-
summary:
|
|
4565
|
-
checked_at:
|
|
4566
|
-
synthesis_eligible:
|
|
4567
|
-
gate_results:
|
|
4568
|
-
failures:
|
|
4569
|
-
warnings:
|
|
4570
|
-
waivers_applied:
|
|
4571
|
-
blocking_reasons:
|
|
4572
|
-
claim_counts:
|
|
4573
|
-
total:
|
|
4574
|
-
candidate:
|
|
4575
|
-
with_evidence_excerpt:
|
|
4576
|
-
with_source_hashes:
|
|
4577
|
-
with_scope:
|
|
4578
|
-
with_not:
|
|
4579
|
-
universal_scope_null:
|
|
4580
|
-
orphans:
|
|
4886
|
+
summary: z12.string(),
|
|
4887
|
+
checked_at: z12.string(),
|
|
4888
|
+
synthesis_eligible: z12.boolean(),
|
|
4889
|
+
gate_results: z12.array(GateCheckResultSchema),
|
|
4890
|
+
failures: z12.array(GateCheckResultSchema),
|
|
4891
|
+
warnings: z12.array(GateCheckResultSchema),
|
|
4892
|
+
waivers_applied: z12.array(WaiverApplicationSchema),
|
|
4893
|
+
blocking_reasons: z12.array(z12.string()),
|
|
4894
|
+
claim_counts: z12.object({
|
|
4895
|
+
total: z12.number().int().nonnegative(),
|
|
4896
|
+
candidate: z12.number().int().nonnegative(),
|
|
4897
|
+
with_evidence_excerpt: z12.number().int().nonnegative(),
|
|
4898
|
+
with_source_hashes: z12.number().int().nonnegative(),
|
|
4899
|
+
with_scope: z12.number().int().nonnegative(),
|
|
4900
|
+
with_not: z12.number().int().nonnegative(),
|
|
4901
|
+
universal_scope_null: z12.number().int().nonnegative(),
|
|
4902
|
+
orphans: z12.number().int().nonnegative()
|
|
4581
4903
|
}),
|
|
4582
|
-
source_counts:
|
|
4583
|
-
total:
|
|
4584
|
-
primary:
|
|
4585
|
-
secondary:
|
|
4586
|
-
forum:
|
|
4587
|
-
benchmark:
|
|
4588
|
-
docs:
|
|
4589
|
-
unknown:
|
|
4590
|
-
independent_publishers:
|
|
4591
|
-
failed_fetches:
|
|
4592
|
-
section_primary:
|
|
4593
|
-
section_independent_publishers:
|
|
4904
|
+
source_counts: z12.object({
|
|
4905
|
+
total: z12.number().int().nonnegative(),
|
|
4906
|
+
primary: z12.number().int().nonnegative(),
|
|
4907
|
+
secondary: z12.number().int().nonnegative(),
|
|
4908
|
+
forum: z12.number().int().nonnegative(),
|
|
4909
|
+
benchmark: z12.number().int().nonnegative(),
|
|
4910
|
+
docs: z12.number().int().nonnegative(),
|
|
4911
|
+
unknown: z12.number().int().nonnegative(),
|
|
4912
|
+
independent_publishers: z12.number().int().nonnegative(),
|
|
4913
|
+
failed_fetches: z12.number().int().nonnegative(),
|
|
4914
|
+
section_primary: z12.number().int().nonnegative(),
|
|
4915
|
+
section_independent_publishers: z12.number().int().nonnegative()
|
|
4594
4916
|
}),
|
|
4595
|
-
contradiction_counts:
|
|
4596
|
-
total:
|
|
4597
|
-
unresolved:
|
|
4598
|
-
blocking:
|
|
4599
|
-
by_type:
|
|
4917
|
+
contradiction_counts: z12.object({
|
|
4918
|
+
total: z12.number().int().nonnegative(),
|
|
4919
|
+
unresolved: z12.number().int().nonnegative(),
|
|
4920
|
+
blocking: z12.number().int().nonnegative(),
|
|
4921
|
+
by_type: z12.record(z12.string(), z12.number().int().nonnegative())
|
|
4600
4922
|
}),
|
|
4601
|
-
freshness_summary:
|
|
4602
|
-
policy_required:
|
|
4603
|
-
max_source_age_months:
|
|
4604
|
-
stale_source_policy:
|
|
4605
|
-
stale_count:
|
|
4606
|
-
unknown_date_count:
|
|
4923
|
+
freshness_summary: z12.object({
|
|
4924
|
+
policy_required: z12.boolean(),
|
|
4925
|
+
max_source_age_months: z12.number().int().nullable(),
|
|
4926
|
+
stale_source_policy: z12.enum(["warn", "fail"]),
|
|
4927
|
+
stale_count: z12.number().int().nonnegative(),
|
|
4928
|
+
unknown_date_count: z12.number().int().nonnegative()
|
|
4607
4929
|
}),
|
|
4608
|
-
scope_integrity_summary:
|
|
4609
|
-
universal_claims:
|
|
4610
|
-
scoped_claims:
|
|
4611
|
-
with_not_constraint:
|
|
4612
|
-
overgen_risks_total:
|
|
4613
|
-
overgen_risks_blocking:
|
|
4930
|
+
scope_integrity_summary: z12.object({
|
|
4931
|
+
universal_claims: z12.number().int().nonnegative(),
|
|
4932
|
+
scoped_claims: z12.number().int().nonnegative(),
|
|
4933
|
+
with_not_constraint: z12.number().int().nonnegative(),
|
|
4934
|
+
overgen_risks_total: z12.number().int().nonnegative(),
|
|
4935
|
+
overgen_risks_blocking: z12.number().int().nonnegative()
|
|
4614
4936
|
}),
|
|
4615
|
-
next_actions:
|
|
4937
|
+
next_actions: z12.array(z12.string())
|
|
4616
4938
|
});
|
|
4617
4939
|
}
|
|
4618
4940
|
});
|
|
4619
4941
|
|
|
4620
4942
|
// src/gates/run.ts
|
|
4621
|
-
import { existsSync as
|
|
4622
|
-
import { mkdir as
|
|
4623
|
-
import { join as
|
|
4943
|
+
import { existsSync as existsSync12 } from "fs";
|
|
4944
|
+
import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
4945
|
+
import { join as join13, resolve as resolve9 } from "path";
|
|
4624
4946
|
import { parse as yamlParse2, stringify as yamlStringify3 } from "yaml";
|
|
4625
4947
|
async function readJsonl(packPath, rel, parse) {
|
|
4626
|
-
const path =
|
|
4627
|
-
if (!
|
|
4628
|
-
const text = await
|
|
4948
|
+
const path = join13(packPath, rel);
|
|
4949
|
+
if (!existsSync12(path)) return [];
|
|
4950
|
+
const text = await readFile12(path, "utf8");
|
|
4629
4951
|
const out = [];
|
|
4630
4952
|
for (const line of text.split(/\r?\n/)) {
|
|
4631
4953
|
if (!line.trim()) continue;
|
|
@@ -4634,14 +4956,14 @@ async function readJsonl(packPath, rel, parse) {
|
|
|
4634
4956
|
return out;
|
|
4635
4957
|
}
|
|
4636
4958
|
async function readSourceCards2(packPath) {
|
|
4637
|
-
const dir =
|
|
4638
|
-
if (!
|
|
4959
|
+
const dir = join13(packPath, "evidence", "source-cards");
|
|
4960
|
+
if (!existsSync12(dir)) return [];
|
|
4639
4961
|
const { readdir: readdir4 } = await import("fs/promises");
|
|
4640
4962
|
const entries = await readdir4(dir);
|
|
4641
4963
|
const cards = [];
|
|
4642
4964
|
for (const entry of entries) {
|
|
4643
4965
|
if (!entry.endsWith(".json")) continue;
|
|
4644
|
-
const text = await
|
|
4966
|
+
const text = await readFile12(join13(dir, entry), "utf8");
|
|
4645
4967
|
cards.push(SourceCardSchema.parse(JSON.parse(text)));
|
|
4646
4968
|
}
|
|
4647
4969
|
return cards;
|
|
@@ -4816,14 +5138,14 @@ function buildNextActions(results) {
|
|
|
4816
5138
|
return Array.from(new Set(actions));
|
|
4817
5139
|
}
|
|
4818
5140
|
async function loadResearchYaml2(packPath) {
|
|
4819
|
-
const yamlPath =
|
|
4820
|
-
if (!
|
|
4821
|
-
const text = await
|
|
5141
|
+
const yamlPath = join13(packPath, "research.yaml");
|
|
5142
|
+
if (!existsSync12(yamlPath)) throw new PackNotFoundError(packPath);
|
|
5143
|
+
const text = await readFile12(yamlPath, "utf8");
|
|
4822
5144
|
return ResearchYamlSchema.parse(yamlParse2(text));
|
|
4823
5145
|
}
|
|
4824
5146
|
async function updateSectionStatus(packPath, sectionId, synthesisEligible) {
|
|
4825
|
-
const yamlPath =
|
|
4826
|
-
const text = await
|
|
5147
|
+
const yamlPath = join13(packPath, "research.yaml");
|
|
5148
|
+
const text = await readFile12(yamlPath, "utf8");
|
|
4827
5149
|
const research = ResearchYamlSchema.parse(yamlParse2(text));
|
|
4828
5150
|
const idx = research.sections.findIndex((s) => s.id === sectionId);
|
|
4829
5151
|
if (idx < 0) return;
|
|
@@ -4840,9 +5162,9 @@ async function updateSectionStatus(packPath, sectionId, synthesisEligible) {
|
|
|
4840
5162
|
}
|
|
4841
5163
|
async function gate(options) {
|
|
4842
5164
|
const packPath = options.packPath ? resolve9(options.packPath) : process.cwd();
|
|
4843
|
-
if (!
|
|
4844
|
-
const sectionDir =
|
|
4845
|
-
if (!
|
|
5165
|
+
if (!existsSync12(join13(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
5166
|
+
const sectionDir = join13(packPath, "sections", options.sectionId);
|
|
5167
|
+
if (!existsSync12(sectionDir)) throw new SectionNotFoundError(options.sectionId);
|
|
4846
5168
|
const research = await loadResearchYaml2(packPath);
|
|
4847
5169
|
const section = research.sections.find((s) => s.id === options.sectionId);
|
|
4848
5170
|
if (!section) throw new SectionNotFoundError(options.sectionId);
|
|
@@ -4896,15 +5218,15 @@ async function gate(options) {
|
|
|
4896
5218
|
scope_integrity_summary: summarizeScopeIntegrity(input),
|
|
4897
5219
|
next_actions: buildNextActions(finalResults)
|
|
4898
5220
|
});
|
|
4899
|
-
const auditsDir =
|
|
4900
|
-
await
|
|
5221
|
+
const auditsDir = join13(packPath, "audits");
|
|
5222
|
+
await mkdir10(auditsDir, { recursive: true });
|
|
4901
5223
|
await writeFile10(
|
|
4902
|
-
|
|
5224
|
+
join13(auditsDir, `${options.sectionId}-gate.json`),
|
|
4903
5225
|
JSON.stringify(result, null, 2),
|
|
4904
5226
|
"utf8"
|
|
4905
5227
|
);
|
|
4906
5228
|
await writeFile10(
|
|
4907
|
-
|
|
5229
|
+
join13(auditsDir, `${options.sectionId}-gate.md`),
|
|
4908
5230
|
renderGateMarkdown(result),
|
|
4909
5231
|
"utf8"
|
|
4910
5232
|
);
|
|
@@ -4946,21 +5268,21 @@ var init_gates = __esm({
|
|
|
4946
5268
|
});
|
|
4947
5269
|
|
|
4948
5270
|
// src/review/profiles.ts
|
|
4949
|
-
import { existsSync as
|
|
4950
|
-
import { mkdir as
|
|
4951
|
-
import { join as
|
|
4952
|
-
import { z as
|
|
5271
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5272
|
+
import { mkdir as mkdir11, readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
|
|
5273
|
+
import { join as join14 } from "path";
|
|
5274
|
+
import { z as z13 } from "zod";
|
|
4953
5275
|
function reviewActivePath(packPath, sectionId) {
|
|
4954
|
-
return
|
|
5276
|
+
return join14(packPath, "sections", sectionId, "review-active.json");
|
|
4955
5277
|
}
|
|
4956
5278
|
function profileDir(packPath, sectionId, profile) {
|
|
4957
|
-
return
|
|
5279
|
+
return join14(packPath, "sections", sectionId, "reviews", profile);
|
|
4958
5280
|
}
|
|
4959
5281
|
async function readActiveProfile(packPath, sectionId) {
|
|
4960
5282
|
const path = reviewActivePath(packPath, sectionId);
|
|
4961
|
-
if (!
|
|
5283
|
+
if (!existsSync13(path)) return DEFAULT_PROFILE;
|
|
4962
5284
|
try {
|
|
4963
|
-
const parsed = ReviewActiveSchema.parse(JSON.parse(await
|
|
5285
|
+
const parsed = ReviewActiveSchema.parse(JSON.parse(await readFile13(path, "utf8")));
|
|
4964
5286
|
return parsed.active_profile;
|
|
4965
5287
|
} catch {
|
|
4966
5288
|
return DEFAULT_PROFILE;
|
|
@@ -4968,7 +5290,7 @@ async function readActiveProfile(packPath, sectionId) {
|
|
|
4968
5290
|
}
|
|
4969
5291
|
async function writeActiveProfile(packPath, sectionId, active) {
|
|
4970
5292
|
const path = reviewActivePath(packPath, sectionId);
|
|
4971
|
-
await
|
|
5293
|
+
await mkdir11(join14(packPath, "sections", sectionId), { recursive: true });
|
|
4972
5294
|
await writeFile11(path, JSON.stringify(ReviewActiveSchema.parse(active), null, 2), "utf8");
|
|
4973
5295
|
}
|
|
4974
5296
|
function isValidProfileName(name) {
|
|
@@ -4979,22 +5301,22 @@ var init_profiles = __esm({
|
|
|
4979
5301
|
"src/review/profiles.ts"() {
|
|
4980
5302
|
"use strict";
|
|
4981
5303
|
DEFAULT_PROFILE = "default";
|
|
4982
|
-
PromotionCalibrationSummarySchema =
|
|
4983
|
-
fixture:
|
|
4984
|
-
good_false_positive_rate:
|
|
4985
|
-
bad_any_flag_recall:
|
|
4986
|
-
strict_category_recall:
|
|
4987
|
-
unsupported_claim_recall:
|
|
4988
|
-
notes:
|
|
4989
|
-
});
|
|
4990
|
-
ReviewActiveSchema =
|
|
4991
|
-
active_profile:
|
|
4992
|
-
promoted_at:
|
|
4993
|
-
promoted_method:
|
|
4994
|
-
promoted_reviewer:
|
|
5304
|
+
PromotionCalibrationSummarySchema = z13.object({
|
|
5305
|
+
fixture: z13.string().nullable().default(null),
|
|
5306
|
+
good_false_positive_rate: z13.string().nullable().default(null),
|
|
5307
|
+
bad_any_flag_recall: z13.string().nullable().default(null),
|
|
5308
|
+
strict_category_recall: z13.string().nullable().default(null),
|
|
5309
|
+
unsupported_claim_recall: z13.string().nullable().default(null),
|
|
5310
|
+
notes: z13.string().nullable().default(null)
|
|
5311
|
+
});
|
|
5312
|
+
ReviewActiveSchema = z13.object({
|
|
5313
|
+
active_profile: z13.string().min(1),
|
|
5314
|
+
promoted_at: z13.string(),
|
|
5315
|
+
promoted_method: z13.string(),
|
|
5316
|
+
promoted_reviewer: z13.string(),
|
|
4995
5317
|
// Free-text reason the profile was promoted. Recorded once at promotion
|
|
4996
5318
|
// time; not derived from artifacts. Required.
|
|
4997
|
-
promotion_reason:
|
|
5319
|
+
promotion_reason: z13.string().min(8).default("promoted via review-promote without an explicit reason"),
|
|
4998
5320
|
// Optional calibration evidence captured at promotion time so downstream
|
|
4999
5321
|
// consumers can see WHY the reviewer was trusted.
|
|
5000
5322
|
calibration_summary: PromotionCalibrationSummarySchema.nullable().default(null)
|
|
@@ -5621,7 +5943,7 @@ function pickHighestPriority(decisions) {
|
|
|
5621
5943
|
return "accepted_for_synthesis";
|
|
5622
5944
|
}
|
|
5623
5945
|
function deriveClaimReviews(args) {
|
|
5624
|
-
const { claims, findings, reviewer, reviewMethod, activeSectionWaivers } = args;
|
|
5946
|
+
const { claims, findings, reviewer, reviewMethod, activeSectionWaivers, profile } = args;
|
|
5625
5947
|
const reviews = [];
|
|
5626
5948
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5627
5949
|
const monopolyWaived = Array.isArray(activeSectionWaivers) && activeSectionWaivers.some((w) => w.scope === "min_independent_publishers");
|
|
@@ -5636,7 +5958,8 @@ function deriveClaimReviews(args) {
|
|
|
5636
5958
|
finding_ids: [],
|
|
5637
5959
|
reviewer,
|
|
5638
5960
|
review_method: reviewMethod,
|
|
5639
|
-
created_at: now
|
|
5961
|
+
created_at: now,
|
|
5962
|
+
...profile !== void 0 ? { profile } : {}
|
|
5640
5963
|
});
|
|
5641
5964
|
continue;
|
|
5642
5965
|
}
|
|
@@ -5670,7 +5993,8 @@ function deriveClaimReviews(args) {
|
|
|
5670
5993
|
finding_ids: claimFindings.map((f) => f.finding_id),
|
|
5671
5994
|
reviewer,
|
|
5672
5995
|
review_method: reviewMethod,
|
|
5673
|
-
created_at: now
|
|
5996
|
+
created_at: now,
|
|
5997
|
+
...profile !== void 0 ? { profile } : {}
|
|
5674
5998
|
});
|
|
5675
5999
|
}
|
|
5676
6000
|
return reviews;
|
|
@@ -5815,14 +6139,14 @@ var init_markdown3 = __esm({
|
|
|
5815
6139
|
|
|
5816
6140
|
// src/review/run.ts
|
|
5817
6141
|
import { createHash as createHash4 } from "crypto";
|
|
5818
|
-
import { existsSync as
|
|
5819
|
-
import { appendFile as
|
|
5820
|
-
import { join as
|
|
6142
|
+
import { existsSync as existsSync14 } from "fs";
|
|
6143
|
+
import { appendFile as appendFile6, mkdir as mkdir12, readFile as readFile14, writeFile as writeFile12 } from "fs/promises";
|
|
6144
|
+
import { join as join15, resolve as resolve10 } from "path";
|
|
5821
6145
|
import { parse as yamlParse3, stringify as yamlStringify4 } from "yaml";
|
|
5822
6146
|
async function readJsonl2(packPath, rel, parse) {
|
|
5823
|
-
const path =
|
|
5824
|
-
if (!
|
|
5825
|
-
const text = await
|
|
6147
|
+
const path = join15(packPath, rel);
|
|
6148
|
+
if (!existsSync14(path)) return [];
|
|
6149
|
+
const text = await readFile14(path, "utf8");
|
|
5826
6150
|
const out = [];
|
|
5827
6151
|
for (const line of text.split(/\r?\n/)) {
|
|
5828
6152
|
if (!line.trim()) continue;
|
|
@@ -5831,37 +6155,37 @@ async function readJsonl2(packPath, rel, parse) {
|
|
|
5831
6155
|
return out;
|
|
5832
6156
|
}
|
|
5833
6157
|
async function readSourceCards3(packPath) {
|
|
5834
|
-
const dir =
|
|
5835
|
-
if (!
|
|
6158
|
+
const dir = join15(packPath, "evidence", "source-cards");
|
|
6159
|
+
if (!existsSync14(dir)) return [];
|
|
5836
6160
|
const { readdir: readdir4 } = await import("fs/promises");
|
|
5837
6161
|
const entries = await readdir4(dir);
|
|
5838
6162
|
const cards = [];
|
|
5839
6163
|
for (const entry of entries) {
|
|
5840
6164
|
if (!entry.endsWith(".json")) continue;
|
|
5841
|
-
const text = await
|
|
6165
|
+
const text = await readFile14(join15(dir, entry), "utf8");
|
|
5842
6166
|
cards.push(SourceCardSchema.parse(JSON.parse(text)));
|
|
5843
6167
|
}
|
|
5844
6168
|
return cards;
|
|
5845
6169
|
}
|
|
5846
6170
|
async function readGateResult(packPath, sectionId) {
|
|
5847
|
-
const path =
|
|
5848
|
-
if (!
|
|
5849
|
-
const text = await
|
|
6171
|
+
const path = join15(packPath, "audits", `${sectionId}-gate.json`);
|
|
6172
|
+
if (!existsSync14(path)) return null;
|
|
6173
|
+
const text = await readFile14(path, "utf8");
|
|
5850
6174
|
return SectionGateResultSchema.parse(JSON.parse(text));
|
|
5851
6175
|
}
|
|
5852
6176
|
async function readBriefText(packPath, sectionId) {
|
|
5853
|
-
const path =
|
|
5854
|
-
if (!
|
|
5855
|
-
return
|
|
6177
|
+
const path = join15(packPath, "sections", sectionId, "brief.md");
|
|
6178
|
+
if (!existsSync14(path)) return null;
|
|
6179
|
+
return readFile14(path, "utf8");
|
|
5856
6180
|
}
|
|
5857
6181
|
async function readRawTextBySource(packPath, receipts) {
|
|
5858
6182
|
const map2 = /* @__PURE__ */ new Map();
|
|
5859
6183
|
for (const r of receipts) {
|
|
5860
6184
|
if (r.fetch_outcome !== "ok" || !r.raw_text_path) continue;
|
|
5861
|
-
const path =
|
|
5862
|
-
if (!
|
|
6185
|
+
const path = join15(packPath, r.raw_text_path);
|
|
6186
|
+
if (!existsSync14(path)) continue;
|
|
5863
6187
|
if (map2.has(r.source_id)) continue;
|
|
5864
|
-
map2.set(r.source_id, await
|
|
6188
|
+
map2.set(r.source_id, await readFile14(path, "utf8"));
|
|
5865
6189
|
}
|
|
5866
6190
|
return map2;
|
|
5867
6191
|
}
|
|
@@ -5871,8 +6195,8 @@ async function readExcerptsBySource(packPath, claims) {
|
|
|
5871
6195
|
for (const c of claims) for (const sid of c.source_ids) sourceIds.add(sid);
|
|
5872
6196
|
for (const sid of sourceIds) {
|
|
5873
6197
|
const path = ledgerPathFor(packPath, sid);
|
|
5874
|
-
if (!
|
|
5875
|
-
const text = await
|
|
6198
|
+
if (!existsSync14(path)) continue;
|
|
6199
|
+
const text = await readFile14(path, "utf8");
|
|
5876
6200
|
const index = /* @__PURE__ */ new Map();
|
|
5877
6201
|
for (const line of text.split(/\r?\n/)) {
|
|
5878
6202
|
if (!line.trim()) continue;
|
|
@@ -5925,15 +6249,15 @@ function buildFinding(args) {
|
|
|
5925
6249
|
});
|
|
5926
6250
|
}
|
|
5927
6251
|
async function loadResearchYaml3(packPath) {
|
|
5928
|
-
const yamlPath =
|
|
5929
|
-
if (!
|
|
5930
|
-
const text = await
|
|
6252
|
+
const yamlPath = join15(packPath, "research.yaml");
|
|
6253
|
+
if (!existsSync14(yamlPath)) throw new PackNotFoundError(packPath);
|
|
6254
|
+
const text = await readFile14(yamlPath, "utf8");
|
|
5931
6255
|
return ResearchYamlSchema.parse(yamlParse3(text));
|
|
5932
6256
|
}
|
|
5933
6257
|
async function maybePromoteToReviewed(packPath, sectionId, allAccepted) {
|
|
5934
6258
|
if (!allAccepted) return false;
|
|
5935
|
-
const yamlPath =
|
|
5936
|
-
const text = await
|
|
6259
|
+
const yamlPath = join15(packPath, "research.yaml");
|
|
6260
|
+
const text = await readFile14(yamlPath, "utf8");
|
|
5937
6261
|
const research = ResearchYamlSchema.parse(yamlParse3(text));
|
|
5938
6262
|
const idx = research.sections.findIndex((s) => s.id === sectionId);
|
|
5939
6263
|
if (idx < 0) return false;
|
|
@@ -5945,9 +6269,9 @@ async function maybePromoteToReviewed(packPath, sectionId, allAccepted) {
|
|
|
5945
6269
|
}
|
|
5946
6270
|
async function review(options) {
|
|
5947
6271
|
const packPath = options.packPath ? resolve10(options.packPath) : process.cwd();
|
|
5948
|
-
if (!
|
|
5949
|
-
const sectionDir =
|
|
5950
|
-
if (!
|
|
6272
|
+
if (!existsSync14(join15(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
6273
|
+
const sectionDir = join15(packPath, "sections", options.sectionId);
|
|
6274
|
+
if (!existsSync14(sectionDir)) throw new SectionNotFoundError(options.sectionId);
|
|
5951
6275
|
const research = await loadResearchYaml3(packPath);
|
|
5952
6276
|
const section = research.sections.find((s) => s.id === options.sectionId);
|
|
5953
6277
|
if (!section) throw new SectionNotFoundError(options.sectionId);
|
|
@@ -6166,7 +6490,8 @@ async function finalizeReview(args) {
|
|
|
6166
6490
|
findings: dedupedFindings,
|
|
6167
6491
|
reviewer: args.reviewer,
|
|
6168
6492
|
reviewMethod: args.reviewMethod,
|
|
6169
|
-
activeSectionWaivers
|
|
6493
|
+
activeSectionWaivers,
|
|
6494
|
+
profile: args.profile !== DEFAULT_PROFILE ? args.profile : void 0
|
|
6170
6495
|
});
|
|
6171
6496
|
const decisionCounts = {
|
|
6172
6497
|
accepted_for_synthesis: 0,
|
|
@@ -6197,39 +6522,39 @@ async function finalizeReview(args) {
|
|
|
6197
6522
|
promoted_to_reviewed: promoted
|
|
6198
6523
|
});
|
|
6199
6524
|
const profDir = profileDir(args.packPath, args.sectionId, args.profile);
|
|
6200
|
-
await
|
|
6201
|
-
await writeFile12(
|
|
6202
|
-
await writeFile12(
|
|
6203
|
-
const profileFindingsPath =
|
|
6525
|
+
await mkdir12(profDir, { recursive: true });
|
|
6526
|
+
await writeFile12(join15(profDir, "review.json"), JSON.stringify(snapshot, null, 2), "utf8");
|
|
6527
|
+
await writeFile12(join15(profDir, "review.md"), renderReviewMarkdown(snapshot), "utf8");
|
|
6528
|
+
const profileFindingsPath = join15(profDir, "findings.jsonl");
|
|
6204
6529
|
for (const f of dedupedFindings) {
|
|
6205
|
-
await
|
|
6530
|
+
await appendFile6(profileFindingsPath, JSON.stringify(f) + "\n", "utf8");
|
|
6206
6531
|
}
|
|
6207
|
-
const profileReviewsPath =
|
|
6532
|
+
const profileReviewsPath = join15(profDir, "claim-reviews.jsonl");
|
|
6208
6533
|
for (const r of claimReviews) {
|
|
6209
|
-
await
|
|
6534
|
+
await appendFile6(profileReviewsPath, JSON.stringify(ClaimReviewSchema.parse(r)) + "\n", "utf8");
|
|
6210
6535
|
}
|
|
6211
6536
|
const activeProfile = await readActiveProfile(args.packPath, args.sectionId);
|
|
6212
6537
|
const isActive = args.profile === activeProfile || activeProfile === DEFAULT_PROFILE && args.profile === DEFAULT_PROFILE;
|
|
6213
6538
|
if (isActive) {
|
|
6214
|
-
const auditsDir =
|
|
6215
|
-
await
|
|
6539
|
+
const auditsDir = join15(args.packPath, "audits");
|
|
6540
|
+
await mkdir12(auditsDir, { recursive: true });
|
|
6216
6541
|
await writeFile12(
|
|
6217
|
-
|
|
6542
|
+
join15(auditsDir, `${args.sectionId}-review.json`),
|
|
6218
6543
|
JSON.stringify(snapshot, null, 2),
|
|
6219
6544
|
"utf8"
|
|
6220
6545
|
);
|
|
6221
6546
|
await writeFile12(
|
|
6222
|
-
|
|
6547
|
+
join15(auditsDir, `${args.sectionId}-review.md`),
|
|
6223
6548
|
renderReviewMarkdown(snapshot),
|
|
6224
6549
|
"utf8"
|
|
6225
6550
|
);
|
|
6226
|
-
const findingsPath =
|
|
6551
|
+
const findingsPath = join15(auditsDir, `${args.sectionId}-findings.jsonl`);
|
|
6227
6552
|
for (const f of dedupedFindings) {
|
|
6228
|
-
await
|
|
6553
|
+
await appendFile6(findingsPath, JSON.stringify(f) + "\n", "utf8");
|
|
6229
6554
|
}
|
|
6230
|
-
const reviewsPath =
|
|
6555
|
+
const reviewsPath = join15(args.packPath, "sections", args.sectionId, "claim-reviews.jsonl");
|
|
6231
6556
|
for (const r of claimReviews) {
|
|
6232
|
-
await
|
|
6557
|
+
await appendFile6(reviewsPath, JSON.stringify(ClaimReviewSchema.parse(r)) + "\n", "utf8");
|
|
6233
6558
|
}
|
|
6234
6559
|
}
|
|
6235
6560
|
return {
|
|
@@ -6266,14 +6591,14 @@ var init_run4 = __esm({
|
|
|
6266
6591
|
});
|
|
6267
6592
|
|
|
6268
6593
|
// src/review/promote.ts
|
|
6269
|
-
import { existsSync as
|
|
6270
|
-
import { copyFile, mkdir as
|
|
6271
|
-
import { join as
|
|
6594
|
+
import { existsSync as existsSync15 } from "fs";
|
|
6595
|
+
import { copyFile, mkdir as mkdir13, readFile as readFile15, writeFile as writeFile13, appendFile as appendFile7 } from "fs/promises";
|
|
6596
|
+
import { join as join16, resolve as resolve11 } from "path";
|
|
6272
6597
|
import { parse as yamlParse4, stringify as yamlStringify5 } from "yaml";
|
|
6273
6598
|
async function promote(options) {
|
|
6274
6599
|
const packPath = options.packPath ? resolve11(options.packPath) : process.cwd();
|
|
6275
|
-
if (!
|
|
6276
|
-
if (!
|
|
6600
|
+
if (!existsSync15(join16(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
6601
|
+
if (!existsSync15(join16(packPath, "sections", options.sectionId)))
|
|
6277
6602
|
throw new SectionNotFoundError(options.sectionId);
|
|
6278
6603
|
if (!isValidProfileName(options.profile)) {
|
|
6279
6604
|
throw new Error(
|
|
@@ -6281,39 +6606,39 @@ async function promote(options) {
|
|
|
6281
6606
|
);
|
|
6282
6607
|
}
|
|
6283
6608
|
const dir = profileDir(packPath, options.sectionId, options.profile);
|
|
6284
|
-
const reviewJsonPath =
|
|
6285
|
-
if (!
|
|
6609
|
+
const reviewJsonPath = join16(dir, "review.json");
|
|
6610
|
+
if (!existsSync15(reviewJsonPath)) {
|
|
6286
6611
|
throw new Error(
|
|
6287
6612
|
`Profile "${options.profile}" not found at ${dir}. Run \`research-os review --profile ${options.profile}\` first.`
|
|
6288
6613
|
);
|
|
6289
6614
|
}
|
|
6290
6615
|
const snapshot = ReviewSnapshotSchema.parse(
|
|
6291
|
-
JSON.parse(await
|
|
6616
|
+
JSON.parse(await readFile15(reviewJsonPath, "utf8"))
|
|
6292
6617
|
);
|
|
6293
|
-
const auditsDir =
|
|
6294
|
-
await
|
|
6295
|
-
const canonicalReviewJson =
|
|
6296
|
-
const canonicalReviewMd =
|
|
6618
|
+
const auditsDir = join16(packPath, "audits");
|
|
6619
|
+
await mkdir13(auditsDir, { recursive: true });
|
|
6620
|
+
const canonicalReviewJson = join16(auditsDir, `${options.sectionId}-review.json`);
|
|
6621
|
+
const canonicalReviewMd = join16(auditsDir, `${options.sectionId}-review.md`);
|
|
6297
6622
|
await copyFile(reviewJsonPath, canonicalReviewJson);
|
|
6298
6623
|
await writeFile13(canonicalReviewMd, renderReviewMarkdown(snapshot), "utf8");
|
|
6299
|
-
const canonicalFindings =
|
|
6300
|
-
const profileFindings =
|
|
6624
|
+
const canonicalFindings = join16(auditsDir, `${options.sectionId}-findings.jsonl`);
|
|
6625
|
+
const profileFindings = join16(dir, "findings.jsonl");
|
|
6301
6626
|
const writtenFindings = [];
|
|
6302
|
-
if (
|
|
6303
|
-
const text = await
|
|
6627
|
+
if (existsSync15(profileFindings)) {
|
|
6628
|
+
const text = await readFile15(profileFindings, "utf8");
|
|
6304
6629
|
for (const line of text.split(/\r?\n/)) {
|
|
6305
6630
|
if (!line.trim()) continue;
|
|
6306
|
-
await
|
|
6631
|
+
await appendFile7(canonicalFindings, line + "\n", "utf8");
|
|
6307
6632
|
writtenFindings.push(line);
|
|
6308
6633
|
}
|
|
6309
6634
|
}
|
|
6310
|
-
const canonicalReviews =
|
|
6311
|
-
const profileReviews =
|
|
6312
|
-
if (
|
|
6313
|
-
const text = await
|
|
6635
|
+
const canonicalReviews = join16(packPath, "sections", options.sectionId, "claim-reviews.jsonl");
|
|
6636
|
+
const profileReviews = join16(dir, "claim-reviews.jsonl");
|
|
6637
|
+
if (existsSync15(profileReviews)) {
|
|
6638
|
+
const text = await readFile15(profileReviews, "utf8");
|
|
6314
6639
|
for (const line of text.split(/\r?\n/)) {
|
|
6315
6640
|
if (!line.trim()) continue;
|
|
6316
|
-
await
|
|
6641
|
+
await appendFile7(canonicalReviews, line + "\n", "utf8");
|
|
6317
6642
|
}
|
|
6318
6643
|
}
|
|
6319
6644
|
const stamp = (options.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
@@ -6327,8 +6652,8 @@ async function promote(options) {
|
|
|
6327
6652
|
});
|
|
6328
6653
|
let sectionStatusBumped = false;
|
|
6329
6654
|
if (options.promoteSectionStatus) {
|
|
6330
|
-
const yamlPath =
|
|
6331
|
-
const research = ResearchYamlSchema.parse(yamlParse4(await
|
|
6655
|
+
const yamlPath = join16(packPath, "research.yaml");
|
|
6656
|
+
const research = ResearchYamlSchema.parse(yamlParse4(await readFile15(yamlPath, "utf8")));
|
|
6332
6657
|
const idx = research.sections.findIndex((s) => s.id === options.sectionId);
|
|
6333
6658
|
if (idx >= 0 && research.sections[idx].status === "gated") {
|
|
6334
6659
|
const allAccepted = snapshot.candidate_claims > 0 && snapshot.claim_reviews.every((r) => r.decision === "accepted_for_synthesis");
|
|
@@ -6533,16 +6858,16 @@ var init_schema11 = __esm({
|
|
|
6533
6858
|
});
|
|
6534
6859
|
|
|
6535
6860
|
// src/indexer/db.ts
|
|
6536
|
-
import { mkdirSync, writeFileSync, existsSync as
|
|
6537
|
-
import { dirname as
|
|
6861
|
+
import { mkdirSync, writeFileSync, existsSync as existsSync16 } from "fs";
|
|
6862
|
+
import { dirname as dirname4, join as join17 } from "path";
|
|
6538
6863
|
import Database from "better-sqlite3";
|
|
6539
6864
|
function indexDbPath(packPath) {
|
|
6540
|
-
return
|
|
6865
|
+
return join17(packPath, ".research-os", "index.sqlite");
|
|
6541
6866
|
}
|
|
6542
6867
|
function ensureGitIgnore(packPath) {
|
|
6543
|
-
const dir =
|
|
6544
|
-
const gi =
|
|
6545
|
-
if (!
|
|
6868
|
+
const dir = join17(packPath, ".research-os");
|
|
6869
|
+
const gi = join17(dir, ".gitignore");
|
|
6870
|
+
if (!existsSync16(gi)) {
|
|
6546
6871
|
mkdirSync(dir, { recursive: true });
|
|
6547
6872
|
writeFileSync(gi, "*\n", "utf8");
|
|
6548
6873
|
}
|
|
@@ -6550,7 +6875,7 @@ function ensureGitIgnore(packPath) {
|
|
|
6550
6875
|
function openIndexDb(opts) {
|
|
6551
6876
|
const dbPath = indexDbPath(opts.packPath);
|
|
6552
6877
|
if (!opts.readonly) {
|
|
6553
|
-
mkdirSync(
|
|
6878
|
+
mkdirSync(dirname4(dbPath), { recursive: true });
|
|
6554
6879
|
ensureGitIgnore(opts.packPath);
|
|
6555
6880
|
}
|
|
6556
6881
|
const db = new Database(dbPath, { readonly: opts.readonly ?? false, fileMustExist: opts.readonly ?? false });
|
|
@@ -6565,18 +6890,18 @@ var init_db = __esm({
|
|
|
6565
6890
|
});
|
|
6566
6891
|
|
|
6567
6892
|
// src/indexer/build.ts
|
|
6568
|
-
import { existsSync as
|
|
6569
|
-
import { readFile as
|
|
6570
|
-
import { join as
|
|
6893
|
+
import { existsSync as existsSync17 } from "fs";
|
|
6894
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
6895
|
+
import { join as join18, resolve as resolve12, relative as relative2 } from "path";
|
|
6571
6896
|
import { createHash as createHash5 } from "crypto";
|
|
6572
6897
|
import { parse as yamlParse5 } from "yaml";
|
|
6573
6898
|
function relPath(packPath, abs) {
|
|
6574
6899
|
return relative2(packPath, abs).split("\\").join("/");
|
|
6575
6900
|
}
|
|
6576
6901
|
async function tryReadJsonl(packPath, rel, parse) {
|
|
6577
|
-
const path =
|
|
6578
|
-
if (!
|
|
6579
|
-
const text = await
|
|
6902
|
+
const path = join18(packPath, rel);
|
|
6903
|
+
if (!existsSync17(path)) return [];
|
|
6904
|
+
const text = await readFile16(path, "utf8");
|
|
6580
6905
|
const out = [];
|
|
6581
6906
|
for (const line of text.split(/\r?\n/)) {
|
|
6582
6907
|
if (!line.trim()) continue;
|
|
@@ -6585,22 +6910,22 @@ async function tryReadJsonl(packPath, rel, parse) {
|
|
|
6585
6910
|
return out;
|
|
6586
6911
|
}
|
|
6587
6912
|
async function readSourceCards4(packPath) {
|
|
6588
|
-
const dir =
|
|
6589
|
-
if (!
|
|
6913
|
+
const dir = join18(packPath, "evidence", "source-cards");
|
|
6914
|
+
if (!existsSync17(dir)) return [];
|
|
6590
6915
|
const { readdir: readdir4 } = await import("fs/promises");
|
|
6591
6916
|
const entries = await readdir4(dir);
|
|
6592
6917
|
const cards = [];
|
|
6593
6918
|
for (const entry of entries) {
|
|
6594
6919
|
if (!entry.endsWith(".json")) continue;
|
|
6595
|
-
const text = await
|
|
6920
|
+
const text = await readFile16(join18(dir, entry), "utf8");
|
|
6596
6921
|
cards.push(SourceCardSchema.parse(JSON.parse(text)));
|
|
6597
6922
|
}
|
|
6598
6923
|
return cards;
|
|
6599
6924
|
}
|
|
6600
6925
|
async function readGateResult2(packPath, sectionId) {
|
|
6601
|
-
const path =
|
|
6602
|
-
if (!
|
|
6603
|
-
const text = await
|
|
6926
|
+
const path = join18(packPath, "audits", `${sectionId}-gate.json`);
|
|
6927
|
+
if (!existsSync17(path)) return null;
|
|
6928
|
+
const text = await readFile16(path, "utf8");
|
|
6604
6929
|
return SectionGateResultSchema.parse(JSON.parse(text));
|
|
6605
6930
|
}
|
|
6606
6931
|
function fileSha256(text) {
|
|
@@ -6610,8 +6935,8 @@ async function indexSection(args) {
|
|
|
6610
6935
|
const { db, packPath, research, sectionId, now, counts } = args;
|
|
6611
6936
|
const section = research.sections.find((s) => s.id === sectionId);
|
|
6612
6937
|
if (!section) throw new SectionNotFoundError(sectionId);
|
|
6613
|
-
const sectionDir =
|
|
6614
|
-
if (!
|
|
6938
|
+
const sectionDir = join18(packPath, "sections", sectionId);
|
|
6939
|
+
if (!existsSync17(sectionDir)) throw new SectionNotFoundError(sectionId);
|
|
6615
6940
|
db.prepare("DELETE FROM sources WHERE section_id = ?").run(sectionId);
|
|
6616
6941
|
db.prepare("DELETE FROM claims WHERE section_id = ?").run(sectionId);
|
|
6617
6942
|
db.prepare("DELETE FROM contradictions WHERE section_id = ?").run(sectionId);
|
|
@@ -6650,9 +6975,9 @@ async function indexSection(args) {
|
|
|
6650
6975
|
};
|
|
6651
6976
|
const allCards = await readSourceCards4(packPath);
|
|
6652
6977
|
const sectionSourceIds = /* @__PURE__ */ new Set();
|
|
6653
|
-
const sourcesJsonlPath =
|
|
6654
|
-
if (
|
|
6655
|
-
const text = await
|
|
6978
|
+
const sourcesJsonlPath = join18(sectionDir, "sources.jsonl");
|
|
6979
|
+
if (existsSync17(sourcesJsonlPath)) {
|
|
6980
|
+
const text = await readFile16(sourcesJsonlPath, "utf8");
|
|
6656
6981
|
recordArtifact("sources_jsonl", relPath(packPath, sourcesJsonlPath), text);
|
|
6657
6982
|
for (const line of text.split(/\r?\n/)) {
|
|
6658
6983
|
if (!line.trim()) continue;
|
|
@@ -6662,7 +6987,7 @@ async function indexSection(args) {
|
|
|
6662
6987
|
}
|
|
6663
6988
|
for (const card of allCards) {
|
|
6664
6989
|
if (!sectionSourceIds.has(card.source_id) && card.section_id !== sectionId) continue;
|
|
6665
|
-
const cardPath = relPath(packPath,
|
|
6990
|
+
const cardPath = relPath(packPath, join18(packPath, "evidence", "source-cards", `${card.source_id}.json`));
|
|
6666
6991
|
db.prepare(
|
|
6667
6992
|
`INSERT OR REPLACE INTO sources(
|
|
6668
6993
|
source_id, section_id, url, publisher, source_type, relevance,
|
|
@@ -6696,9 +7021,9 @@ ${card.key_points.join("\n")}`;
|
|
|
6696
7021
|
`sections/${sectionId}/claims.jsonl`,
|
|
6697
7022
|
(r) => ClaimSchema.parse(r)
|
|
6698
7023
|
);
|
|
6699
|
-
const claimsArtifact = relPath(packPath,
|
|
6700
|
-
if (
|
|
6701
|
-
const text = await
|
|
7024
|
+
const claimsArtifact = relPath(packPath, join18(sectionDir, "claims.jsonl"));
|
|
7025
|
+
if (existsSync17(join18(sectionDir, "claims.jsonl"))) {
|
|
7026
|
+
const text = await readFile16(join18(sectionDir, "claims.jsonl"), "utf8");
|
|
6702
7027
|
recordArtifact("claims_jsonl", claimsArtifact, text);
|
|
6703
7028
|
}
|
|
6704
7029
|
for (const claim of claims) {
|
|
@@ -6735,9 +7060,9 @@ ${claim.evidence_excerpt}`;
|
|
|
6735
7060
|
`sections/${sectionId}/contradictions.jsonl`,
|
|
6736
7061
|
(r) => ContradictionSchema.parse(r)
|
|
6737
7062
|
);
|
|
6738
|
-
const contradictionsArtifact = relPath(packPath,
|
|
6739
|
-
if (
|
|
6740
|
-
const text = await
|
|
7063
|
+
const contradictionsArtifact = relPath(packPath, join18(sectionDir, "contradictions.jsonl"));
|
|
7064
|
+
if (existsSync17(join18(sectionDir, "contradictions.jsonl"))) {
|
|
7065
|
+
const text = await readFile16(join18(sectionDir, "contradictions.jsonl"), "utf8");
|
|
6741
7066
|
recordArtifact("contradictions_jsonl", contradictionsArtifact, text);
|
|
6742
7067
|
}
|
|
6743
7068
|
for (const c of contradictions) {
|
|
@@ -6773,10 +7098,10 @@ ${c.severity}`;
|
|
|
6773
7098
|
`audits/${sectionId}-findings.jsonl`,
|
|
6774
7099
|
(r) => ReviewFindingSchema.parse(r)
|
|
6775
7100
|
);
|
|
6776
|
-
const findingsArtifact = relPath(packPath,
|
|
6777
|
-
const findingsAbs =
|
|
6778
|
-
if (
|
|
6779
|
-
const text = await
|
|
7101
|
+
const findingsArtifact = relPath(packPath, join18(packPath, "audits", `${sectionId}-findings.jsonl`));
|
|
7102
|
+
const findingsAbs = join18(packPath, "audits", `${sectionId}-findings.jsonl`);
|
|
7103
|
+
if (existsSync17(findingsAbs)) {
|
|
7104
|
+
const text = await readFile16(findingsAbs, "utf8");
|
|
6780
7105
|
recordArtifact("findings_jsonl", findingsArtifact, text);
|
|
6781
7106
|
}
|
|
6782
7107
|
const findingById = /* @__PURE__ */ new Map();
|
|
@@ -6813,10 +7138,10 @@ ${f.evidence}`;
|
|
|
6813
7138
|
`sections/${sectionId}/claim-reviews.jsonl`,
|
|
6814
7139
|
(r) => ClaimReviewSchema.parse(r)
|
|
6815
7140
|
);
|
|
6816
|
-
const reviewsArtifact = relPath(packPath,
|
|
6817
|
-
const reviewsAbs =
|
|
6818
|
-
if (
|
|
6819
|
-
const text = await
|
|
7141
|
+
const reviewsArtifact = relPath(packPath, join18(sectionDir, "claim-reviews.jsonl"));
|
|
7142
|
+
const reviewsAbs = join18(sectionDir, "claim-reviews.jsonl");
|
|
7143
|
+
if (existsSync17(reviewsAbs)) {
|
|
7144
|
+
const text = await readFile16(reviewsAbs, "utf8");
|
|
6820
7145
|
recordArtifact("claim_reviews_jsonl", reviewsArtifact, text);
|
|
6821
7146
|
}
|
|
6822
7147
|
for (const r of reviews) {
|
|
@@ -6841,8 +7166,8 @@ ${r.reason}`;
|
|
|
6841
7166
|
}
|
|
6842
7167
|
const gate2 = await readGateResult2(packPath, sectionId);
|
|
6843
7168
|
if (gate2) {
|
|
6844
|
-
const gateArtifact = relPath(packPath,
|
|
6845
|
-
const gateText = await
|
|
7169
|
+
const gateArtifact = relPath(packPath, join18(packPath, "audits", `${sectionId}-gate.json`));
|
|
7170
|
+
const gateText = await readFile16(join18(packPath, "audits", `${sectionId}-gate.json`), "utf8");
|
|
6846
7171
|
recordArtifact("gate_json", gateArtifact, gateText);
|
|
6847
7172
|
db.prepare(
|
|
6848
7173
|
`INSERT OR REPLACE INTO gate_results(
|
|
@@ -6875,9 +7200,9 @@ ${gate2.next_actions.join("\n")}`;
|
|
|
6875
7200
|
"evidence/fetch-log.jsonl",
|
|
6876
7201
|
(r) => FetchReceiptSchema.parse(r)
|
|
6877
7202
|
);
|
|
6878
|
-
const fetchLogAbs =
|
|
6879
|
-
if (
|
|
6880
|
-
const text = await
|
|
7203
|
+
const fetchLogAbs = join18(packPath, "evidence", "fetch-log.jsonl");
|
|
7204
|
+
if (existsSync17(fetchLogAbs)) {
|
|
7205
|
+
const text = await readFile16(fetchLogAbs, "utf8");
|
|
6881
7206
|
recordArtifact("fetch_log_jsonl", relPath(packPath, fetchLogAbs), text);
|
|
6882
7207
|
}
|
|
6883
7208
|
for (const receipt of allReceipts.filter((r) => r.section_id === sectionId)) {
|
|
@@ -6913,9 +7238,9 @@ async function indexPackAuditRollups(db, packPath, _now) {
|
|
|
6913
7238
|
db.prepare(`DELETE FROM facts_fts WHERE record_type = ? AND record_id = ?`).run(f.recordType, f.recordId);
|
|
6914
7239
|
}
|
|
6915
7240
|
for (const f of ROLLUP_FILES) {
|
|
6916
|
-
const abs =
|
|
6917
|
-
if (!
|
|
6918
|
-
const text = await
|
|
7241
|
+
const abs = join18(packPath, "audits", f.filename);
|
|
7242
|
+
if (!existsSync17(abs)) continue;
|
|
7243
|
+
const text = await readFile16(abs, "utf8");
|
|
6919
7244
|
insertFts.run(
|
|
6920
7245
|
f.recordType,
|
|
6921
7246
|
f.recordId,
|
|
@@ -6927,8 +7252,8 @@ async function indexPackAuditRollups(db, packPath, _now) {
|
|
|
6927
7252
|
}
|
|
6928
7253
|
async function build(options) {
|
|
6929
7254
|
const packPath = options.packPath ? resolve12(options.packPath) : process.cwd();
|
|
6930
|
-
if (!
|
|
6931
|
-
const research = ResearchYamlSchema.parse(yamlParse5(await
|
|
7255
|
+
if (!existsSync17(join18(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
7256
|
+
const research = ResearchYamlSchema.parse(yamlParse5(await readFile16(join18(packPath, "research.yaml"), "utf8")));
|
|
6932
7257
|
const targets = options.sectionId ? [options.sectionId] : options.all ? research.sections.map((s) => s.id) : research.sections.map((s) => s.id);
|
|
6933
7258
|
if (targets.length === 0) {
|
|
6934
7259
|
throw new Error("No sections to index. Add at least one section to the pack.");
|
|
@@ -6985,7 +7310,7 @@ var init_build = __esm({
|
|
|
6985
7310
|
});
|
|
6986
7311
|
|
|
6987
7312
|
// src/indexer/query.ts
|
|
6988
|
-
import { existsSync as
|
|
7313
|
+
import { existsSync as existsSync18 } from "fs";
|
|
6989
7314
|
import { resolve as resolve13 } from "path";
|
|
6990
7315
|
function escapeFtsTerm(term) {
|
|
6991
7316
|
const trimmed = term.trim();
|
|
@@ -6996,8 +7321,8 @@ function escapeFtsTerm(term) {
|
|
|
6996
7321
|
function query(options) {
|
|
6997
7322
|
const packPath = options.packPath ? resolve13(options.packPath) : process.cwd();
|
|
6998
7323
|
const dbPath = indexDbPath(packPath);
|
|
6999
|
-
if (!
|
|
7000
|
-
if (!
|
|
7324
|
+
if (!existsSync18(packPath)) throw new PackNotFoundError(packPath);
|
|
7325
|
+
if (!existsSync18(dbPath)) throw new IndexNotBuiltError(dbPath);
|
|
7001
7326
|
const db = openIndexDb({ packPath, readonly: true });
|
|
7002
7327
|
const limit = options.limit ?? 25;
|
|
7003
7328
|
const ftsTerm = escapeFtsTerm(options.term);
|
|
@@ -7071,16 +7396,16 @@ var init_query = __esm({
|
|
|
7071
7396
|
});
|
|
7072
7397
|
|
|
7073
7398
|
// src/indexer/export.ts
|
|
7074
|
-
import { existsSync as
|
|
7075
|
-
import { mkdir as
|
|
7076
|
-
import { dirname as
|
|
7399
|
+
import { existsSync as existsSync19 } from "fs";
|
|
7400
|
+
import { mkdir as mkdir14, writeFile as writeFile14 } from "fs/promises";
|
|
7401
|
+
import { dirname as dirname5, join as join19, resolve as resolve14 } from "path";
|
|
7077
7402
|
async function exportRepoKnowledge(options) {
|
|
7078
7403
|
const packPath = options.packPath ? resolve14(options.packPath) : process.cwd();
|
|
7079
|
-
if (!
|
|
7404
|
+
if (!existsSync19(packPath)) throw new PackNotFoundError(packPath);
|
|
7080
7405
|
const dbPath = indexDbPath(packPath);
|
|
7081
|
-
if (!
|
|
7082
|
-
const outPath = options.outPath ? resolve14(options.outPath) :
|
|
7083
|
-
await
|
|
7406
|
+
if (!existsSync19(dbPath)) throw new IndexNotBuiltError(dbPath);
|
|
7407
|
+
const outPath = options.outPath ? resolve14(options.outPath) : join19(packPath, "evidence", "repo-knowledge", "research-os-facts.jsonl");
|
|
7408
|
+
await mkdir14(dirname5(outPath), { recursive: true });
|
|
7084
7409
|
const db = openIndexDb({ packPath, readonly: true });
|
|
7085
7410
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7086
7411
|
const facts = [];
|
|
@@ -7239,8 +7564,8 @@ async function syncRepoKnowledge(options) {
|
|
|
7239
7564
|
};
|
|
7240
7565
|
}
|
|
7241
7566
|
const exportResult = await exportRepoKnowledge({ packPath });
|
|
7242
|
-
const { readFile:
|
|
7243
|
-
const text = await
|
|
7567
|
+
const { readFile: readFile25 } = await import("fs/promises");
|
|
7568
|
+
const text = await readFile25(exportResult.outPath, "utf8");
|
|
7244
7569
|
const facts = text.split(/\r?\n/).filter((l) => l.trim().length > 0).map((l) => JSON.parse(l));
|
|
7245
7570
|
try {
|
|
7246
7571
|
const r = await rk.ingestFacts({ facts, namespace: "research-os" });
|
|
@@ -7280,26 +7605,26 @@ var init_indexer = __esm({
|
|
|
7280
7605
|
});
|
|
7281
7606
|
|
|
7282
7607
|
// src/dispositions/schema.ts
|
|
7283
|
-
import { z as
|
|
7608
|
+
import { z as z14 } from "zod";
|
|
7284
7609
|
var ClaimSynthesisDispositionStatusSchema, ClaimSynthesisDispositionSchema;
|
|
7285
7610
|
var init_schema12 = __esm({
|
|
7286
7611
|
"src/dispositions/schema.ts"() {
|
|
7287
7612
|
"use strict";
|
|
7288
|
-
ClaimSynthesisDispositionStatusSchema =
|
|
7613
|
+
ClaimSynthesisDispositionStatusSchema = z14.enum([
|
|
7289
7614
|
"parked_not_for_synthesis",
|
|
7290
7615
|
"preserved_for_human_note",
|
|
7291
7616
|
"needs_human_review_excluded",
|
|
7292
7617
|
"out_of_bounds_regression_fixture"
|
|
7293
7618
|
]);
|
|
7294
|
-
ClaimSynthesisDispositionSchema =
|
|
7295
|
-
claim_id:
|
|
7296
|
-
section_id:
|
|
7619
|
+
ClaimSynthesisDispositionSchema = z14.object({
|
|
7620
|
+
claim_id: z14.string().min(1),
|
|
7621
|
+
section_id: z14.string().min(1),
|
|
7297
7622
|
status: ClaimSynthesisDispositionStatusSchema,
|
|
7298
|
-
reason:
|
|
7299
|
-
decided_by:
|
|
7300
|
-
authorized_by:
|
|
7301
|
-
source:
|
|
7302
|
-
created_at:
|
|
7623
|
+
reason: z14.string().min(4),
|
|
7624
|
+
decided_by: z14.string().min(1),
|
|
7625
|
+
authorized_by: z14.string().min(1),
|
|
7626
|
+
source: z14.string().min(1),
|
|
7627
|
+
created_at: z14.string().min(1)
|
|
7303
7628
|
});
|
|
7304
7629
|
}
|
|
7305
7630
|
});
|
|
@@ -7630,91 +7955,91 @@ var init_derive = __esm({
|
|
|
7630
7955
|
});
|
|
7631
7956
|
|
|
7632
7957
|
// src/cowork/schema.ts
|
|
7633
|
-
import { z as
|
|
7958
|
+
import { z as z15 } from "zod";
|
|
7634
7959
|
var HandoffModeSchema, IndexStatusSchema, ProvenanceSummarySchema, SectionStateSchema, WaiverEntrySchema, GateVerdictEntrySchema, ReviewDecisionCountSchema, CoworkHandoffPayloadSchema;
|
|
7635
7960
|
var init_schema13 = __esm({
|
|
7636
7961
|
"src/cowork/schema.ts"() {
|
|
7637
7962
|
"use strict";
|
|
7638
|
-
HandoffModeSchema =
|
|
7963
|
+
HandoffModeSchema = z15.enum([
|
|
7639
7964
|
"repair_required",
|
|
7640
7965
|
"synthesis_ready",
|
|
7641
7966
|
"human_review_required"
|
|
7642
7967
|
]);
|
|
7643
|
-
IndexStatusSchema =
|
|
7644
|
-
ProvenanceSummarySchema =
|
|
7645
|
-
accepted_count:
|
|
7646
|
-
rejected_count:
|
|
7647
|
-
triage_parked_count:
|
|
7648
|
-
needs_review_undispositioned_count:
|
|
7649
|
-
dispositioned_count:
|
|
7650
|
-
dispositioned_breakdown:
|
|
7651
|
-
parked_not_for_synthesis:
|
|
7652
|
-
preserved_for_human_note:
|
|
7653
|
-
needs_human_review_excluded:
|
|
7654
|
-
out_of_bounds_regression_fixture:
|
|
7968
|
+
IndexStatusSchema = z15.enum(["present", "missing"]);
|
|
7969
|
+
ProvenanceSummarySchema = z15.object({
|
|
7970
|
+
accepted_count: z15.number().int().nonnegative(),
|
|
7971
|
+
rejected_count: z15.number().int().nonnegative(),
|
|
7972
|
+
triage_parked_count: z15.number().int().nonnegative(),
|
|
7973
|
+
needs_review_undispositioned_count: z15.number().int().nonnegative(),
|
|
7974
|
+
dispositioned_count: z15.number().int().nonnegative(),
|
|
7975
|
+
dispositioned_breakdown: z15.object({
|
|
7976
|
+
parked_not_for_synthesis: z15.number().int().nonnegative(),
|
|
7977
|
+
preserved_for_human_note: z15.number().int().nonnegative(),
|
|
7978
|
+
needs_human_review_excluded: z15.number().int().nonnegative(),
|
|
7979
|
+
out_of_bounds_regression_fixture: z15.number().int().nonnegative()
|
|
7655
7980
|
}),
|
|
7656
|
-
active_repair_blockers:
|
|
7657
|
-
active_unresolved_contradictions:
|
|
7658
|
-
waivers_active:
|
|
7659
|
-
overrides_applied_count:
|
|
7660
|
-
});
|
|
7661
|
-
SectionStateSchema =
|
|
7662
|
-
section_id:
|
|
7663
|
-
purpose:
|
|
7664
|
-
status:
|
|
7665
|
-
has_gate_run:
|
|
7666
|
-
has_review_run:
|
|
7667
|
-
gate_verdict:
|
|
7668
|
-
synthesis_eligible:
|
|
7669
|
-
accepted_claim_ids:
|
|
7670
|
-
repair_claim_ids:
|
|
7671
|
-
rejected_claim_ids:
|
|
7672
|
-
dispositioned_claim_ids:
|
|
7673
|
-
candidate_claims_total:
|
|
7674
|
-
unresolved_contradiction_ids:
|
|
7675
|
-
blocking_reasons:
|
|
7676
|
-
active_blockers:
|
|
7677
|
-
blocking_contradictions_unresolved:
|
|
7981
|
+
active_repair_blockers: z15.number().int().nonnegative(),
|
|
7982
|
+
active_unresolved_contradictions: z15.number().int().nonnegative(),
|
|
7983
|
+
waivers_active: z15.array(z15.string()),
|
|
7984
|
+
overrides_applied_count: z15.number().int().nonnegative()
|
|
7985
|
+
});
|
|
7986
|
+
SectionStateSchema = z15.object({
|
|
7987
|
+
section_id: z15.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
7988
|
+
purpose: z15.string(),
|
|
7989
|
+
status: z15.string(),
|
|
7990
|
+
has_gate_run: z15.boolean(),
|
|
7991
|
+
has_review_run: z15.boolean(),
|
|
7992
|
+
gate_verdict: z15.string().nullable(),
|
|
7993
|
+
synthesis_eligible: z15.boolean(),
|
|
7994
|
+
accepted_claim_ids: z15.array(z15.string()),
|
|
7995
|
+
repair_claim_ids: z15.array(z15.string()),
|
|
7996
|
+
rejected_claim_ids: z15.array(z15.string()),
|
|
7997
|
+
dispositioned_claim_ids: z15.array(z15.string()).default([]),
|
|
7998
|
+
candidate_claims_total: z15.number().int().nonnegative(),
|
|
7999
|
+
unresolved_contradiction_ids: z15.array(z15.string()),
|
|
8000
|
+
blocking_reasons: z15.array(z15.string()),
|
|
8001
|
+
active_blockers: z15.array(z15.string()).default([]),
|
|
8002
|
+
blocking_contradictions_unresolved: z15.number().int().nonnegative(),
|
|
7678
8003
|
provenance_summary: ProvenanceSummarySchema.optional()
|
|
7679
8004
|
});
|
|
7680
|
-
WaiverEntrySchema =
|
|
7681
|
-
scope:
|
|
7682
|
-
family:
|
|
7683
|
-
reason:
|
|
7684
|
-
compensating_controls:
|
|
7685
|
-
applied_to:
|
|
7686
|
-
});
|
|
7687
|
-
GateVerdictEntrySchema =
|
|
7688
|
-
section_id:
|
|
7689
|
-
verdict:
|
|
7690
|
-
synthesis_eligible:
|
|
7691
|
-
});
|
|
7692
|
-
ReviewDecisionCountSchema =
|
|
7693
|
-
section_id:
|
|
7694
|
-
decision:
|
|
7695
|
-
count:
|
|
7696
|
-
});
|
|
7697
|
-
CoworkHandoffPayloadSchema =
|
|
7698
|
-
pack_id:
|
|
7699
|
-
pack_topic:
|
|
7700
|
-
generated_at:
|
|
8005
|
+
WaiverEntrySchema = z15.object({
|
|
8006
|
+
scope: z15.enum(["pack", "gate"]),
|
|
8007
|
+
family: z15.string(),
|
|
8008
|
+
reason: z15.string(),
|
|
8009
|
+
compensating_controls: z15.array(z15.string()),
|
|
8010
|
+
applied_to: z15.string()
|
|
8011
|
+
});
|
|
8012
|
+
GateVerdictEntrySchema = z15.object({
|
|
8013
|
+
section_id: z15.string(),
|
|
8014
|
+
verdict: z15.string(),
|
|
8015
|
+
synthesis_eligible: z15.boolean()
|
|
8016
|
+
});
|
|
8017
|
+
ReviewDecisionCountSchema = z15.object({
|
|
8018
|
+
section_id: z15.string(),
|
|
8019
|
+
decision: z15.string(),
|
|
8020
|
+
count: z15.number().int().nonnegative()
|
|
8021
|
+
});
|
|
8022
|
+
CoworkHandoffPayloadSchema = z15.object({
|
|
8023
|
+
pack_id: z15.string(),
|
|
8024
|
+
pack_topic: z15.string(),
|
|
8025
|
+
generated_at: z15.string(),
|
|
7701
8026
|
mode: HandoffModeSchema,
|
|
7702
|
-
synthesis_allowed:
|
|
7703
|
-
summary:
|
|
7704
|
-
sections:
|
|
7705
|
-
accepted_claim_ids:
|
|
7706
|
-
repair_claim_ids:
|
|
7707
|
-
blocked_claim_ids:
|
|
7708
|
-
dispositioned_claim_ids:
|
|
7709
|
-
unresolved_contradiction_ids:
|
|
7710
|
-
waivers:
|
|
7711
|
-
gate_verdicts:
|
|
7712
|
-
review_decisions:
|
|
7713
|
-
recommended_next_actions:
|
|
7714
|
-
allowed_write_paths:
|
|
7715
|
-
forbidden_actions:
|
|
8027
|
+
synthesis_allowed: z15.boolean(),
|
|
8028
|
+
summary: z15.string(),
|
|
8029
|
+
sections: z15.array(SectionStateSchema),
|
|
8030
|
+
accepted_claim_ids: z15.array(z15.string()),
|
|
8031
|
+
repair_claim_ids: z15.array(z15.string()),
|
|
8032
|
+
blocked_claim_ids: z15.array(z15.string()),
|
|
8033
|
+
dispositioned_claim_ids: z15.array(z15.string()).default([]),
|
|
8034
|
+
unresolved_contradiction_ids: z15.array(z15.string()),
|
|
8035
|
+
waivers: z15.array(WaiverEntrySchema),
|
|
8036
|
+
gate_verdicts: z15.array(GateVerdictEntrySchema),
|
|
8037
|
+
review_decisions: z15.array(ReviewDecisionCountSchema),
|
|
8038
|
+
recommended_next_actions: z15.array(z15.string()),
|
|
8039
|
+
allowed_write_paths: z15.array(z15.string()),
|
|
8040
|
+
forbidden_actions: z15.array(z15.string()),
|
|
7716
8041
|
index_status: IndexStatusSchema,
|
|
7717
|
-
warnings:
|
|
8042
|
+
warnings: z15.array(z15.string())
|
|
7718
8043
|
});
|
|
7719
8044
|
}
|
|
7720
8045
|
});
|
|
@@ -7893,19 +8218,19 @@ var init_markdown4 = __esm({
|
|
|
7893
8218
|
});
|
|
7894
8219
|
|
|
7895
8220
|
// src/cowork/run.ts
|
|
7896
|
-
import { existsSync as
|
|
7897
|
-
import { mkdir as
|
|
7898
|
-
import { join as
|
|
8221
|
+
import { existsSync as existsSync20 } from "fs";
|
|
8222
|
+
import { mkdir as mkdir15, readFile as readFile17, writeFile as writeFile15 } from "fs/promises";
|
|
8223
|
+
import { join as join20, resolve as resolve16 } from "path";
|
|
7899
8224
|
import { parse as yamlParse6 } from "yaml";
|
|
7900
8225
|
async function loadResearchYaml4(packPath) {
|
|
7901
|
-
const yamlPath =
|
|
7902
|
-
if (!
|
|
7903
|
-
const text = await
|
|
8226
|
+
const yamlPath = join20(packPath, "research.yaml");
|
|
8227
|
+
if (!existsSync20(yamlPath)) throw new PackNotFoundError(packPath);
|
|
8228
|
+
const text = await readFile17(yamlPath, "utf8");
|
|
7904
8229
|
return ResearchYamlSchema.parse(yamlParse6(text));
|
|
7905
8230
|
}
|
|
7906
8231
|
async function readJsonl3(path, parse, warnings) {
|
|
7907
|
-
if (!
|
|
7908
|
-
const text = await
|
|
8232
|
+
if (!existsSync20(path)) return [];
|
|
8233
|
+
const text = await readFile17(path, "utf8");
|
|
7909
8234
|
const out = [];
|
|
7910
8235
|
for (const line of text.split(/\r?\n/)) {
|
|
7911
8236
|
if (!line.trim()) continue;
|
|
@@ -7919,10 +8244,10 @@ async function readJsonl3(path, parse, warnings) {
|
|
|
7919
8244
|
return out;
|
|
7920
8245
|
}
|
|
7921
8246
|
async function readGate(packPath, sectionId, warnings) {
|
|
7922
|
-
const path =
|
|
7923
|
-
if (!
|
|
8247
|
+
const path = join20(packPath, "audits", `${sectionId}-gate.json`);
|
|
8248
|
+
if (!existsSync20(path)) return null;
|
|
7924
8249
|
try {
|
|
7925
|
-
const text = await
|
|
8250
|
+
const text = await readFile17(path, "utf8");
|
|
7926
8251
|
return SectionGateResultSchema.parse(JSON.parse(text));
|
|
7927
8252
|
} catch (err) {
|
|
7928
8253
|
warnings.push(`malformed gate result at audits/${sectionId}-gate.json: ${err instanceof Error ? err.message : err}`);
|
|
@@ -7937,35 +8262,35 @@ async function handoff(options) {
|
|
|
7937
8262
|
for (const section of research.sections) {
|
|
7938
8263
|
const sid = section.id;
|
|
7939
8264
|
const claims = await readJsonl3(
|
|
7940
|
-
|
|
8265
|
+
join20(packPath, "sections", sid, "claims.jsonl"),
|
|
7941
8266
|
(r) => ClaimSchema.parse(r),
|
|
7942
8267
|
warnings
|
|
7943
8268
|
);
|
|
7944
8269
|
const candidateClaims = claims.filter((c) => c.review_state === "candidate");
|
|
7945
8270
|
const claimReviews = await readJsonl3(
|
|
7946
|
-
|
|
8271
|
+
join20(packPath, "sections", sid, "claim-reviews.jsonl"),
|
|
7947
8272
|
(r) => ClaimReviewSchema.parse(r),
|
|
7948
8273
|
warnings
|
|
7949
8274
|
);
|
|
7950
8275
|
const contradictions = await readJsonl3(
|
|
7951
|
-
|
|
8276
|
+
join20(packPath, "sections", sid, "contradictions.jsonl"),
|
|
7952
8277
|
(r) => ContradictionSchema.parse(r),
|
|
7953
8278
|
warnings
|
|
7954
8279
|
);
|
|
7955
8280
|
const resolutions = await readJsonl3(
|
|
7956
|
-
|
|
8281
|
+
join20(packPath, "sections", sid, "contradiction-resolutions.jsonl"),
|
|
7957
8282
|
(r) => ContradictionResolutionSchema.parse(r),
|
|
7958
8283
|
warnings
|
|
7959
8284
|
);
|
|
7960
8285
|
const dispositions = await readJsonl3(
|
|
7961
|
-
|
|
8286
|
+
join20(packPath, "sections", sid, "claim-synthesis-dispositions.jsonl"),
|
|
7962
8287
|
(r) => ClaimSynthesisDispositionSchema.parse(r),
|
|
7963
8288
|
warnings
|
|
7964
8289
|
);
|
|
7965
8290
|
const gate2 = await readGate(packPath, sid, warnings);
|
|
7966
8291
|
perSection.set(sid, { gate: gate2, candidateClaims, claimReviews, contradictions, resolutions, dispositions });
|
|
7967
8292
|
}
|
|
7968
|
-
const indexExists =
|
|
8293
|
+
const indexExists = existsSync20(indexDbPath(packPath));
|
|
7969
8294
|
if (!indexExists) {
|
|
7970
8295
|
warnings.push(
|
|
7971
8296
|
"Pack-local index missing at .research-os/index.sqlite \u2014 Cowork can still operate from canonical artifacts, but `research-os query` will refuse until you run `research-os index build --all`."
|
|
@@ -7981,10 +8306,10 @@ async function handoff(options) {
|
|
|
7981
8306
|
warnings
|
|
7982
8307
|
})
|
|
7983
8308
|
);
|
|
7984
|
-
const handoffsDir =
|
|
7985
|
-
await
|
|
7986
|
-
const jsonPath =
|
|
7987
|
-
const mdPath =
|
|
8309
|
+
const handoffsDir = join20(packPath, "handoffs");
|
|
8310
|
+
await mkdir15(handoffsDir, { recursive: true });
|
|
8311
|
+
const jsonPath = join20(handoffsDir, "cowork-handoff.json");
|
|
8312
|
+
const mdPath = join20(handoffsDir, "cowork-master.md");
|
|
7988
8313
|
await writeFile15(jsonPath, JSON.stringify(payload, null, 2), "utf8");
|
|
7989
8314
|
await writeFile15(mdPath, renderCoworkMaster(payload), "utf8");
|
|
7990
8315
|
return {
|
|
@@ -8264,86 +8589,86 @@ var init_derive2 = __esm({
|
|
|
8264
8589
|
});
|
|
8265
8590
|
|
|
8266
8591
|
// src/synth/schema.ts
|
|
8267
|
-
import { z as
|
|
8592
|
+
import { z as z16 } from "zod";
|
|
8268
8593
|
var SectionAcceptedSummarySchema, ClaimClusterSchema, SharedSourceSchema, ScopeOverlapSchema, CrossSectionContradictionRefSchema, WaiverDependencySchema, AllowedSynthesisInputSchema, ForbiddenInputSchema, CrossSectionMapSchema;
|
|
8269
8594
|
var init_schema14 = __esm({
|
|
8270
8595
|
"src/synth/schema.ts"() {
|
|
8271
8596
|
"use strict";
|
|
8272
|
-
SectionAcceptedSummarySchema =
|
|
8273
|
-
section_id:
|
|
8274
|
-
purpose:
|
|
8275
|
-
status:
|
|
8276
|
-
accepted_claim_ids:
|
|
8277
|
-
excluded_reason:
|
|
8278
|
-
});
|
|
8279
|
-
ClaimClusterSchema = z15.object({
|
|
8280
|
-
cluster_id: z15.string(),
|
|
8281
|
-
shared_source_ids: z15.array(z15.string()),
|
|
8282
|
-
member_claim_ids: z15.array(z15.string()).min(1),
|
|
8283
|
-
spans_sections: z15.array(z15.string())
|
|
8284
|
-
});
|
|
8285
|
-
SharedSourceSchema = z15.object({
|
|
8286
|
-
source_id: z15.string(),
|
|
8287
|
-
publisher: z15.string().nullable(),
|
|
8288
|
-
source_type: z15.string(),
|
|
8289
|
-
used_by_claim_ids: z15.array(z15.string()),
|
|
8290
|
-
spans_sections: z15.array(z15.string())
|
|
8291
|
-
});
|
|
8292
|
-
ScopeOverlapSchema = z15.object({
|
|
8293
|
-
claim_a: z15.string(),
|
|
8294
|
-
claim_b: z15.string(),
|
|
8295
|
-
scope_a: z15.string().nullable(),
|
|
8296
|
-
scope_b: z15.string().nullable(),
|
|
8297
|
-
jaccard: z15.number().min(0).max(1),
|
|
8298
|
-
cross_section: z15.boolean(),
|
|
8299
|
-
warning: z15.string()
|
|
8300
|
-
});
|
|
8301
|
-
CrossSectionContradictionRefSchema = z15.object({
|
|
8302
|
-
contradiction_id: z15.string(),
|
|
8303
|
-
claim_ids: z15.array(z15.string()),
|
|
8304
|
-
sections: z15.array(z15.string()),
|
|
8305
|
-
type: z15.string(),
|
|
8306
|
-
severity: z15.string(),
|
|
8307
|
-
status: z15.string()
|
|
8308
|
-
});
|
|
8309
|
-
WaiverDependencySchema = z15.object({
|
|
8310
|
-
scope: z15.enum(["pack", "gate"]),
|
|
8311
|
-
family: z15.string(),
|
|
8312
|
-
reason: z15.string(),
|
|
8313
|
-
compensating_controls: z15.array(z15.string()),
|
|
8314
|
-
applied_to: z15.string(),
|
|
8315
|
-
must_disclose_in: z15.enum(["decision-brief.md", "final-report.md", "both"])
|
|
8597
|
+
SectionAcceptedSummarySchema = z16.object({
|
|
8598
|
+
section_id: z16.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
8599
|
+
purpose: z16.string(),
|
|
8600
|
+
status: z16.string(),
|
|
8601
|
+
accepted_claim_ids: z16.array(z16.string()),
|
|
8602
|
+
excluded_reason: z16.string().nullable()
|
|
8316
8603
|
});
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
scope: z15.string().nullable(),
|
|
8323
|
-
not: z15.string().nullable(),
|
|
8324
|
-
source_ids: z15.array(z15.string())
|
|
8325
|
-
});
|
|
8326
|
-
ForbiddenInputSchema = z15.object({
|
|
8327
|
-
claim_id: z15.string(),
|
|
8328
|
-
section_id: z15.string(),
|
|
8329
|
-
decision: z15.string(),
|
|
8330
|
-
reason: z15.string()
|
|
8604
|
+
ClaimClusterSchema = z16.object({
|
|
8605
|
+
cluster_id: z16.string(),
|
|
8606
|
+
shared_source_ids: z16.array(z16.string()),
|
|
8607
|
+
member_claim_ids: z16.array(z16.string()).min(1),
|
|
8608
|
+
spans_sections: z16.array(z16.string())
|
|
8331
8609
|
});
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8610
|
+
SharedSourceSchema = z16.object({
|
|
8611
|
+
source_id: z16.string(),
|
|
8612
|
+
publisher: z16.string().nullable(),
|
|
8613
|
+
source_type: z16.string(),
|
|
8614
|
+
used_by_claim_ids: z16.array(z16.string()),
|
|
8615
|
+
spans_sections: z16.array(z16.string())
|
|
8616
|
+
});
|
|
8617
|
+
ScopeOverlapSchema = z16.object({
|
|
8618
|
+
claim_a: z16.string(),
|
|
8619
|
+
claim_b: z16.string(),
|
|
8620
|
+
scope_a: z16.string().nullable(),
|
|
8621
|
+
scope_b: z16.string().nullable(),
|
|
8622
|
+
jaccard: z16.number().min(0).max(1),
|
|
8623
|
+
cross_section: z16.boolean(),
|
|
8624
|
+
warning: z16.string()
|
|
8625
|
+
});
|
|
8626
|
+
CrossSectionContradictionRefSchema = z16.object({
|
|
8627
|
+
contradiction_id: z16.string(),
|
|
8628
|
+
claim_ids: z16.array(z16.string()),
|
|
8629
|
+
sections: z16.array(z16.string()),
|
|
8630
|
+
type: z16.string(),
|
|
8631
|
+
severity: z16.string(),
|
|
8632
|
+
status: z16.string()
|
|
8633
|
+
});
|
|
8634
|
+
WaiverDependencySchema = z16.object({
|
|
8635
|
+
scope: z16.enum(["pack", "gate"]),
|
|
8636
|
+
family: z16.string(),
|
|
8637
|
+
reason: z16.string(),
|
|
8638
|
+
compensating_controls: z16.array(z16.string()),
|
|
8639
|
+
applied_to: z16.string(),
|
|
8640
|
+
must_disclose_in: z16.enum(["decision-brief.md", "final-report.md", "both"])
|
|
8641
|
+
});
|
|
8642
|
+
AllowedSynthesisInputSchema = z16.object({
|
|
8643
|
+
claim_id: z16.string(),
|
|
8644
|
+
section_id: z16.string(),
|
|
8645
|
+
artifact_path: z16.string(),
|
|
8646
|
+
asserts: z16.string(),
|
|
8647
|
+
scope: z16.string().nullable(),
|
|
8648
|
+
not: z16.string().nullable(),
|
|
8649
|
+
source_ids: z16.array(z16.string())
|
|
8650
|
+
});
|
|
8651
|
+
ForbiddenInputSchema = z16.object({
|
|
8652
|
+
claim_id: z16.string(),
|
|
8653
|
+
section_id: z16.string(),
|
|
8654
|
+
decision: z16.string(),
|
|
8655
|
+
reason: z16.string()
|
|
8656
|
+
});
|
|
8657
|
+
CrossSectionMapSchema = z16.object({
|
|
8658
|
+
pack_id: z16.string(),
|
|
8659
|
+
pack_topic: z16.string(),
|
|
8660
|
+
pack_decision: z16.string(),
|
|
8661
|
+
generated_at: z16.string(),
|
|
8662
|
+
accepted_claim_ids: z16.array(z16.string()),
|
|
8663
|
+
sections: z16.array(SectionAcceptedSummarySchema),
|
|
8664
|
+
claim_clusters: z16.array(ClaimClusterSchema),
|
|
8665
|
+
shared_sources: z16.array(SharedSourceSchema),
|
|
8666
|
+
scope_overlaps: z16.array(ScopeOverlapSchema),
|
|
8667
|
+
cross_section_contradictions: z16.array(CrossSectionContradictionRefSchema),
|
|
8668
|
+
waiver_dependencies: z16.array(WaiverDependencySchema),
|
|
8669
|
+
open_questions: z16.array(z16.string()),
|
|
8670
|
+
allowed_synthesis_inputs: z16.array(AllowedSynthesisInputSchema),
|
|
8671
|
+
forbidden_inputs: z16.array(ForbiddenInputSchema)
|
|
8347
8672
|
});
|
|
8348
8673
|
}
|
|
8349
8674
|
});
|
|
@@ -8603,13 +8928,13 @@ var init_markdown5 = __esm({
|
|
|
8603
8928
|
});
|
|
8604
8929
|
|
|
8605
8930
|
// src/synth/run.ts
|
|
8606
|
-
import { existsSync as
|
|
8607
|
-
import { mkdir as
|
|
8608
|
-
import { join as
|
|
8931
|
+
import { existsSync as existsSync21 } from "fs";
|
|
8932
|
+
import { mkdir as mkdir16, readFile as readFile18, writeFile as writeFile16 } from "fs/promises";
|
|
8933
|
+
import { join as join21, resolve as resolve17 } from "path";
|
|
8609
8934
|
import { parse as yamlParse7 } from "yaml";
|
|
8610
8935
|
async function readJsonl4(path, parse) {
|
|
8611
|
-
if (!
|
|
8612
|
-
const text = await
|
|
8936
|
+
if (!existsSync21(path)) return [];
|
|
8937
|
+
const text = await readFile18(path, "utf8");
|
|
8613
8938
|
const out = [];
|
|
8614
8939
|
for (const line of text.split(/\r?\n/)) {
|
|
8615
8940
|
if (!line.trim()) continue;
|
|
@@ -8618,27 +8943,27 @@ async function readJsonl4(path, parse) {
|
|
|
8618
8943
|
return out;
|
|
8619
8944
|
}
|
|
8620
8945
|
async function readSourceCards5(packPath) {
|
|
8621
|
-
const dir =
|
|
8622
|
-
if (!
|
|
8946
|
+
const dir = join21(packPath, "evidence", "source-cards");
|
|
8947
|
+
if (!existsSync21(dir)) return [];
|
|
8623
8948
|
const { readdir: readdir4 } = await import("fs/promises");
|
|
8624
8949
|
const entries = await readdir4(dir);
|
|
8625
8950
|
const cards = [];
|
|
8626
8951
|
for (const entry of entries) {
|
|
8627
8952
|
if (!entry.endsWith(".json")) continue;
|
|
8628
|
-
const text = await
|
|
8953
|
+
const text = await readFile18(join21(dir, entry), "utf8");
|
|
8629
8954
|
cards.push(SourceCardSchema.parse(JSON.parse(text)));
|
|
8630
8955
|
}
|
|
8631
8956
|
return cards;
|
|
8632
8957
|
}
|
|
8633
8958
|
async function workspace(options) {
|
|
8634
8959
|
const packPath = options.packPath ? resolve17(options.packPath) : process.cwd();
|
|
8635
|
-
const yamlPath =
|
|
8636
|
-
if (!
|
|
8637
|
-
const research = ResearchYamlSchema.parse(yamlParse7(await
|
|
8638
|
-
const handoffPath =
|
|
8639
|
-
if (!
|
|
8960
|
+
const yamlPath = join21(packPath, "research.yaml");
|
|
8961
|
+
if (!existsSync21(yamlPath)) throw new PackNotFoundError(packPath);
|
|
8962
|
+
const research = ResearchYamlSchema.parse(yamlParse7(await readFile18(yamlPath, "utf8")));
|
|
8963
|
+
const handoffPath = join21(packPath, "handoffs", "cowork-handoff.json");
|
|
8964
|
+
if (!existsSync21(handoffPath)) throw new HandoffNotFoundError();
|
|
8640
8965
|
const handoff2 = CoworkHandoffPayloadSchema.parse(
|
|
8641
|
-
JSON.parse(await
|
|
8966
|
+
JSON.parse(await readFile18(handoffPath, "utf8"))
|
|
8642
8967
|
);
|
|
8643
8968
|
if (handoff2.mode !== "synthesis_ready") {
|
|
8644
8969
|
return {
|
|
@@ -8660,21 +8985,21 @@ async function workspace(options) {
|
|
|
8660
8985
|
claimsBySection.set(
|
|
8661
8986
|
section.id,
|
|
8662
8987
|
await readJsonl4(
|
|
8663
|
-
|
|
8988
|
+
join21(packPath, "sections", section.id, "claims.jsonl"),
|
|
8664
8989
|
(r) => ClaimSchema.parse(r)
|
|
8665
8990
|
)
|
|
8666
8991
|
);
|
|
8667
8992
|
reviewsBySection.set(
|
|
8668
8993
|
section.id,
|
|
8669
8994
|
await readJsonl4(
|
|
8670
|
-
|
|
8995
|
+
join21(packPath, "sections", section.id, "claim-reviews.jsonl"),
|
|
8671
8996
|
(r) => ClaimReviewSchema.parse(r)
|
|
8672
8997
|
)
|
|
8673
8998
|
);
|
|
8674
8999
|
contradictionsBySection.set(
|
|
8675
9000
|
section.id,
|
|
8676
9001
|
await readJsonl4(
|
|
8677
|
-
|
|
9002
|
+
join21(packPath, "sections", section.id, "contradictions.jsonl"),
|
|
8678
9003
|
(r) => ContradictionSchema.parse(r)
|
|
8679
9004
|
)
|
|
8680
9005
|
);
|
|
@@ -8691,17 +9016,17 @@ async function workspace(options) {
|
|
|
8691
9016
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8692
9017
|
})
|
|
8693
9018
|
);
|
|
8694
|
-
const synthDir =
|
|
8695
|
-
await
|
|
9019
|
+
const synthDir = join21(packPath, "synthesis");
|
|
9020
|
+
await mkdir16(synthDir, { recursive: true });
|
|
8696
9021
|
const filesWritten = [];
|
|
8697
9022
|
const writeIfAbsent = async (relPath2, content) => {
|
|
8698
|
-
const abs =
|
|
8699
|
-
if (
|
|
9023
|
+
const abs = join21(synthDir, relPath2);
|
|
9024
|
+
if (existsSync21(abs)) return;
|
|
8700
9025
|
await writeFile16(abs, content, "utf8");
|
|
8701
9026
|
filesWritten.push(abs);
|
|
8702
9027
|
};
|
|
8703
9028
|
const writeAlways = async (relPath2, content) => {
|
|
8704
|
-
const abs =
|
|
9029
|
+
const abs = join21(synthDir, relPath2);
|
|
8705
9030
|
await writeFile16(abs, content, "utf8");
|
|
8706
9031
|
filesWritten.push(abs);
|
|
8707
9032
|
};
|
|
@@ -9511,179 +9836,179 @@ var init_aggregate = __esm({
|
|
|
9511
9836
|
});
|
|
9512
9837
|
|
|
9513
9838
|
// src/audit/schema.ts
|
|
9514
|
-
import { z as
|
|
9839
|
+
import { z as z17 } from "zod";
|
|
9515
9840
|
var PackVerdictSchema, HandoffModeSchema2, OrphanClaimRowSchema, StaleSourceRowSchema, WeakSourceRowSchema, UnresolvedContradictionRowSchema, ScopeWideningRiskRowSchema, SourceDiversityGapRowSchema, SynthesisReadinessRowSchema, PackAuditPayloadSchema;
|
|
9516
9841
|
var init_schema15 = __esm({
|
|
9517
9842
|
"src/audit/schema.ts"() {
|
|
9518
9843
|
"use strict";
|
|
9519
|
-
PackVerdictSchema =
|
|
9844
|
+
PackVerdictSchema = z17.enum([
|
|
9520
9845
|
"ready_for_synthesis",
|
|
9521
9846
|
"repair_required",
|
|
9522
9847
|
"human_review_required",
|
|
9523
9848
|
"blocked"
|
|
9524
9849
|
]);
|
|
9525
|
-
HandoffModeSchema2 =
|
|
9850
|
+
HandoffModeSchema2 = z17.enum([
|
|
9526
9851
|
"repair_required",
|
|
9527
9852
|
"synthesis_ready",
|
|
9528
9853
|
"human_review_required",
|
|
9529
9854
|
"unknown"
|
|
9530
9855
|
]);
|
|
9531
|
-
OrphanClaimRowSchema =
|
|
9532
|
-
claim_id:
|
|
9533
|
-
section_id:
|
|
9534
|
-
reason:
|
|
9856
|
+
OrphanClaimRowSchema = z17.object({
|
|
9857
|
+
claim_id: z17.string(),
|
|
9858
|
+
section_id: z17.string(),
|
|
9859
|
+
reason: z17.enum([
|
|
9535
9860
|
"missing_source_card",
|
|
9536
9861
|
"missing_source_hash",
|
|
9537
9862
|
"missing_evidence_excerpt",
|
|
9538
9863
|
"unresolvable_source_id"
|
|
9539
9864
|
]),
|
|
9540
|
-
details:
|
|
9541
|
-
artifact_path:
|
|
9542
|
-
});
|
|
9543
|
-
StaleSourceRowSchema =
|
|
9544
|
-
source_id:
|
|
9545
|
-
section_id:
|
|
9546
|
-
publisher:
|
|
9547
|
-
reason:
|
|
9548
|
-
details:
|
|
9549
|
-
artifact_path:
|
|
9550
|
-
policy:
|
|
9551
|
-
required:
|
|
9552
|
-
max_source_age_months:
|
|
9553
|
-
stale_source_policy:
|
|
9865
|
+
details: z17.string(),
|
|
9866
|
+
artifact_path: z17.string()
|
|
9867
|
+
});
|
|
9868
|
+
StaleSourceRowSchema = z17.object({
|
|
9869
|
+
source_id: z17.string(),
|
|
9870
|
+
section_id: z17.string(),
|
|
9871
|
+
publisher: z17.string().nullable(),
|
|
9872
|
+
reason: z17.enum(["too_old", "missing_date", "unparseable_date"]),
|
|
9873
|
+
details: z17.string(),
|
|
9874
|
+
artifact_path: z17.string(),
|
|
9875
|
+
policy: z17.object({
|
|
9876
|
+
required: z17.boolean(),
|
|
9877
|
+
max_source_age_months: z17.number().int().nullable(),
|
|
9878
|
+
stale_source_policy: z17.enum(["warn", "fail"])
|
|
9554
9879
|
})
|
|
9555
9880
|
});
|
|
9556
|
-
WeakSourceRowSchema =
|
|
9557
|
-
reason:
|
|
9881
|
+
WeakSourceRowSchema = z17.object({
|
|
9882
|
+
reason: z17.enum([
|
|
9558
9883
|
"source_cluster_monopoly",
|
|
9559
9884
|
"low_independent_publishers",
|
|
9560
9885
|
"missing_primary_source",
|
|
9561
9886
|
"excessive_type_imbalance",
|
|
9562
9887
|
"failed_fetches_reducing_floor"
|
|
9563
9888
|
]),
|
|
9564
|
-
section_id:
|
|
9565
|
-
details:
|
|
9566
|
-
evidence_ids:
|
|
9567
|
-
artifact_path:
|
|
9568
|
-
});
|
|
9569
|
-
UnresolvedContradictionRowSchema =
|
|
9570
|
-
contradiction_id:
|
|
9571
|
-
section_id:
|
|
9572
|
-
type:
|
|
9573
|
-
severity:
|
|
9574
|
-
status:
|
|
9575
|
-
claim_ids:
|
|
9576
|
-
artifact_path:
|
|
9577
|
-
});
|
|
9578
|
-
ScopeWideningRiskRowSchema =
|
|
9579
|
-
reason:
|
|
9889
|
+
section_id: z17.string(),
|
|
9890
|
+
details: z17.string(),
|
|
9891
|
+
evidence_ids: z17.array(z17.string()),
|
|
9892
|
+
artifact_path: z17.string()
|
|
9893
|
+
});
|
|
9894
|
+
UnresolvedContradictionRowSchema = z17.object({
|
|
9895
|
+
contradiction_id: z17.string(),
|
|
9896
|
+
section_id: z17.string(),
|
|
9897
|
+
type: z17.string(),
|
|
9898
|
+
severity: z17.string(),
|
|
9899
|
+
status: z17.string(),
|
|
9900
|
+
claim_ids: z17.array(z17.string()),
|
|
9901
|
+
artifact_path: z17.string()
|
|
9902
|
+
});
|
|
9903
|
+
ScopeWideningRiskRowSchema = z17.object({
|
|
9904
|
+
reason: z17.enum([
|
|
9580
9905
|
"overgeneralization_finding",
|
|
9581
9906
|
"scope_null_in_use",
|
|
9582
9907
|
"missing_not_flagged",
|
|
9583
9908
|
"contextual_to_universal_risk"
|
|
9584
9909
|
]),
|
|
9585
|
-
claim_id:
|
|
9586
|
-
section_id:
|
|
9587
|
-
details:
|
|
9588
|
-
artifact_path:
|
|
9910
|
+
claim_id: z17.string(),
|
|
9911
|
+
section_id: z17.string(),
|
|
9912
|
+
details: z17.string(),
|
|
9913
|
+
artifact_path: z17.string()
|
|
9589
9914
|
});
|
|
9590
|
-
SourceDiversityGapRowSchema =
|
|
9591
|
-
reason:
|
|
9915
|
+
SourceDiversityGapRowSchema = z17.object({
|
|
9916
|
+
reason: z17.enum([
|
|
9592
9917
|
"section_publisher_monopoly",
|
|
9593
9918
|
"low_section_publisher_count",
|
|
9594
9919
|
"cross_section_publisher_overlap",
|
|
9595
9920
|
"section_has_no_sources"
|
|
9596
9921
|
]),
|
|
9597
|
-
section_id:
|
|
9598
|
-
details:
|
|
9599
|
-
evidence_ids:
|
|
9600
|
-
});
|
|
9601
|
-
SynthesisReadinessRowSchema =
|
|
9602
|
-
section_id:
|
|
9603
|
-
purpose:
|
|
9604
|
-
status:
|
|
9605
|
-
has_gate_run:
|
|
9606
|
-
has_review_run:
|
|
9607
|
-
gate_verdict:
|
|
9608
|
-
synthesis_eligible:
|
|
9609
|
-
candidate_claims:
|
|
9610
|
-
accepted_claims:
|
|
9611
|
-
repair_claims:
|
|
9612
|
-
rejected_claims:
|
|
9613
|
-
dispositioned_claims:
|
|
9614
|
-
blocking_reasons:
|
|
9922
|
+
section_id: z17.string(),
|
|
9923
|
+
details: z17.string(),
|
|
9924
|
+
evidence_ids: z17.array(z17.string())
|
|
9925
|
+
});
|
|
9926
|
+
SynthesisReadinessRowSchema = z17.object({
|
|
9927
|
+
section_id: z17.string(),
|
|
9928
|
+
purpose: z17.string(),
|
|
9929
|
+
status: z17.string(),
|
|
9930
|
+
has_gate_run: z17.boolean(),
|
|
9931
|
+
has_review_run: z17.boolean(),
|
|
9932
|
+
gate_verdict: z17.string().nullable(),
|
|
9933
|
+
synthesis_eligible: z17.boolean(),
|
|
9934
|
+
candidate_claims: z17.number().int().nonnegative(),
|
|
9935
|
+
accepted_claims: z17.number().int().nonnegative(),
|
|
9936
|
+
repair_claims: z17.number().int().nonnegative(),
|
|
9937
|
+
rejected_claims: z17.number().int().nonnegative(),
|
|
9938
|
+
dispositioned_claims: z17.number().int().nonnegative(),
|
|
9939
|
+
blocking_reasons: z17.array(z17.string()),
|
|
9615
9940
|
cowork_handoff_mode: HandoffModeSchema2,
|
|
9616
|
-
workspace_allowed:
|
|
9941
|
+
workspace_allowed: z17.boolean()
|
|
9617
9942
|
});
|
|
9618
|
-
PackAuditPayloadSchema =
|
|
9619
|
-
pack_id:
|
|
9620
|
-
pack_topic:
|
|
9621
|
-
generated_at:
|
|
9943
|
+
PackAuditPayloadSchema = z17.object({
|
|
9944
|
+
pack_id: z17.string(),
|
|
9945
|
+
pack_topic: z17.string(),
|
|
9946
|
+
generated_at: z17.string(),
|
|
9622
9947
|
verdict: PackVerdictSchema,
|
|
9623
|
-
synthesis_allowed:
|
|
9624
|
-
section_summaries:
|
|
9625
|
-
claim_summary:
|
|
9626
|
-
total:
|
|
9627
|
-
candidate:
|
|
9628
|
-
accepted_for_synthesis:
|
|
9629
|
-
rejected:
|
|
9630
|
-
needs_repair:
|
|
9631
|
-
dispositioned:
|
|
9632
|
-
no_review:
|
|
9633
|
-
with_evidence_excerpt:
|
|
9634
|
-
with_source_hashes:
|
|
9635
|
-
scope_null:
|
|
9636
|
-
not_null:
|
|
9637
|
-
orphans:
|
|
9948
|
+
synthesis_allowed: z17.boolean(),
|
|
9949
|
+
section_summaries: z17.array(SynthesisReadinessRowSchema),
|
|
9950
|
+
claim_summary: z17.object({
|
|
9951
|
+
total: z17.number().int().nonnegative(),
|
|
9952
|
+
candidate: z17.number().int().nonnegative(),
|
|
9953
|
+
accepted_for_synthesis: z17.number().int().nonnegative(),
|
|
9954
|
+
rejected: z17.number().int().nonnegative(),
|
|
9955
|
+
needs_repair: z17.number().int().nonnegative(),
|
|
9956
|
+
dispositioned: z17.number().int().nonnegative(),
|
|
9957
|
+
no_review: z17.number().int().nonnegative(),
|
|
9958
|
+
with_evidence_excerpt: z17.number().int().nonnegative(),
|
|
9959
|
+
with_source_hashes: z17.number().int().nonnegative(),
|
|
9960
|
+
scope_null: z17.number().int().nonnegative(),
|
|
9961
|
+
not_null: z17.number().int().nonnegative(),
|
|
9962
|
+
orphans: z17.number().int().nonnegative()
|
|
9638
9963
|
}),
|
|
9639
|
-
source_summary:
|
|
9640
|
-
total:
|
|
9641
|
-
primary:
|
|
9642
|
-
secondary:
|
|
9643
|
-
forum:
|
|
9644
|
-
benchmark:
|
|
9645
|
-
docs:
|
|
9646
|
-
unknown:
|
|
9647
|
-
independent_publishers:
|
|
9648
|
-
failed_fetches:
|
|
9649
|
-
sections_with_sources:
|
|
9650
|
-
sections_without_sources:
|
|
9964
|
+
source_summary: z17.object({
|
|
9965
|
+
total: z17.number().int().nonnegative(),
|
|
9966
|
+
primary: z17.number().int().nonnegative(),
|
|
9967
|
+
secondary: z17.number().int().nonnegative(),
|
|
9968
|
+
forum: z17.number().int().nonnegative(),
|
|
9969
|
+
benchmark: z17.number().int().nonnegative(),
|
|
9970
|
+
docs: z17.number().int().nonnegative(),
|
|
9971
|
+
unknown: z17.number().int().nonnegative(),
|
|
9972
|
+
independent_publishers: z17.number().int().nonnegative(),
|
|
9973
|
+
failed_fetches: z17.number().int().nonnegative(),
|
|
9974
|
+
sections_with_sources: z17.number().int().nonnegative(),
|
|
9975
|
+
sections_without_sources: z17.number().int().nonnegative()
|
|
9651
9976
|
}),
|
|
9652
|
-
contradiction_summary:
|
|
9653
|
-
total:
|
|
9654
|
-
unresolved:
|
|
9655
|
-
blocking:
|
|
9656
|
-
reconciled:
|
|
9657
|
-
preserved_deliberately:
|
|
9658
|
-
rejected:
|
|
9659
|
-
by_type:
|
|
9660
|
-
sections_with_clean_ledger:
|
|
9977
|
+
contradiction_summary: z17.object({
|
|
9978
|
+
total: z17.number().int().nonnegative(),
|
|
9979
|
+
unresolved: z17.number().int().nonnegative(),
|
|
9980
|
+
blocking: z17.number().int().nonnegative(),
|
|
9981
|
+
reconciled: z17.number().int().nonnegative(),
|
|
9982
|
+
preserved_deliberately: z17.number().int().nonnegative(),
|
|
9983
|
+
rejected: z17.number().int().nonnegative(),
|
|
9984
|
+
by_type: z17.record(z17.string(), z17.number().int().nonnegative()),
|
|
9985
|
+
sections_with_clean_ledger: z17.number().int().nonnegative()
|
|
9661
9986
|
}),
|
|
9662
|
-
review_summary:
|
|
9663
|
-
sections_with_review_run:
|
|
9664
|
-
sections_without_review_run:
|
|
9665
|
-
decision_counts:
|
|
9666
|
-
blocking_findings:
|
|
9987
|
+
review_summary: z17.object({
|
|
9988
|
+
sections_with_review_run: z17.number().int().nonnegative(),
|
|
9989
|
+
sections_without_review_run: z17.number().int().nonnegative(),
|
|
9990
|
+
decision_counts: z17.record(z17.string(), z17.number().int().nonnegative()),
|
|
9991
|
+
blocking_findings: z17.number().int().nonnegative()
|
|
9667
9992
|
}),
|
|
9668
|
-
waiver_summary:
|
|
9669
|
-
total:
|
|
9670
|
-
invalid:
|
|
9671
|
-
by_family:
|
|
9993
|
+
waiver_summary: z17.object({
|
|
9994
|
+
total: z17.number().int().nonnegative(),
|
|
9995
|
+
invalid: z17.number().int().nonnegative(),
|
|
9996
|
+
by_family: z17.record(z17.string(), z17.number().int().nonnegative())
|
|
9672
9997
|
}),
|
|
9673
|
-
readiness_summary:
|
|
9674
|
-
total_sections:
|
|
9675
|
-
ready_sections:
|
|
9676
|
-
repair_sections:
|
|
9677
|
-
blocked_sections:
|
|
9678
|
-
no_gate_sections:
|
|
9679
|
-
no_review_sections:
|
|
9998
|
+
readiness_summary: z17.object({
|
|
9999
|
+
total_sections: z17.number().int().nonnegative(),
|
|
10000
|
+
ready_sections: z17.number().int().nonnegative(),
|
|
10001
|
+
repair_sections: z17.number().int().nonnegative(),
|
|
10002
|
+
blocked_sections: z17.number().int().nonnegative(),
|
|
10003
|
+
no_gate_sections: z17.number().int().nonnegative(),
|
|
10004
|
+
no_review_sections: z17.number().int().nonnegative(),
|
|
9680
10005
|
cowork_handoff_mode: HandoffModeSchema2,
|
|
9681
|
-
workspace_allowed:
|
|
10006
|
+
workspace_allowed: z17.boolean()
|
|
9682
10007
|
}),
|
|
9683
|
-
audit_files:
|
|
9684
|
-
blocking_reasons:
|
|
9685
|
-
warnings:
|
|
9686
|
-
next_actions:
|
|
10008
|
+
audit_files: z17.array(z17.string()),
|
|
10009
|
+
blocking_reasons: z17.array(z17.string()),
|
|
10010
|
+
warnings: z17.array(z17.string()),
|
|
10011
|
+
next_actions: z17.array(z17.string())
|
|
9687
10012
|
});
|
|
9688
10013
|
}
|
|
9689
10014
|
});
|
|
@@ -9905,13 +10230,13 @@ var init_markdown6 = __esm({
|
|
|
9905
10230
|
});
|
|
9906
10231
|
|
|
9907
10232
|
// src/audit/run.ts
|
|
9908
|
-
import { existsSync as
|
|
9909
|
-
import { mkdir as
|
|
9910
|
-
import { join as
|
|
10233
|
+
import { existsSync as existsSync22 } from "fs";
|
|
10234
|
+
import { mkdir as mkdir17, readFile as readFile19, writeFile as writeFile17 } from "fs/promises";
|
|
10235
|
+
import { join as join22, resolve as resolve18 } from "path";
|
|
9911
10236
|
import { parse as yamlParse8 } from "yaml";
|
|
9912
10237
|
async function readJsonl5(path, parse, warnings) {
|
|
9913
|
-
if (!
|
|
9914
|
-
const text = await
|
|
10238
|
+
if (!existsSync22(path)) return [];
|
|
10239
|
+
const text = await readFile19(path, "utf8");
|
|
9915
10240
|
const out = [];
|
|
9916
10241
|
for (const line of text.split(/\r?\n/)) {
|
|
9917
10242
|
if (!line.trim()) continue;
|
|
@@ -9924,15 +10249,15 @@ async function readJsonl5(path, parse, warnings) {
|
|
|
9924
10249
|
return out;
|
|
9925
10250
|
}
|
|
9926
10251
|
async function readSourceCards6(packPath, warnings) {
|
|
9927
|
-
const dir =
|
|
9928
|
-
if (!
|
|
10252
|
+
const dir = join22(packPath, "evidence", "source-cards");
|
|
10253
|
+
if (!existsSync22(dir)) return [];
|
|
9929
10254
|
const { readdir: readdir4 } = await import("fs/promises");
|
|
9930
10255
|
const entries = await readdir4(dir);
|
|
9931
10256
|
const cards = [];
|
|
9932
10257
|
for (const entry of entries) {
|
|
9933
10258
|
if (!entry.endsWith(".json")) continue;
|
|
9934
10259
|
try {
|
|
9935
|
-
const text = await
|
|
10260
|
+
const text = await readFile19(join22(dir, entry), "utf8");
|
|
9936
10261
|
cards.push(SourceCardSchema.parse(JSON.parse(text)));
|
|
9937
10262
|
} catch (err) {
|
|
9938
10263
|
warnings.push(`malformed source card ${entry}: ${err instanceof Error ? err.message : "parse error"}`);
|
|
@@ -9941,29 +10266,29 @@ async function readSourceCards6(packPath, warnings) {
|
|
|
9941
10266
|
return cards;
|
|
9942
10267
|
}
|
|
9943
10268
|
async function readGate2(packPath, sectionId, warnings) {
|
|
9944
|
-
const path =
|
|
9945
|
-
if (!
|
|
10269
|
+
const path = join22(packPath, "audits", `${sectionId}-gate.json`);
|
|
10270
|
+
if (!existsSync22(path)) return null;
|
|
9946
10271
|
try {
|
|
9947
|
-
return SectionGateResultSchema.parse(JSON.parse(await
|
|
10272
|
+
return SectionGateResultSchema.parse(JSON.parse(await readFile19(path, "utf8")));
|
|
9948
10273
|
} catch (err) {
|
|
9949
10274
|
warnings.push(`malformed gate result for ${sectionId}: ${err instanceof Error ? err.message : "parse error"}`);
|
|
9950
10275
|
return null;
|
|
9951
10276
|
}
|
|
9952
10277
|
}
|
|
9953
10278
|
async function readHandoff(packPath, warnings) {
|
|
9954
|
-
const path =
|
|
9955
|
-
if (!
|
|
10279
|
+
const path = join22(packPath, "handoffs", "cowork-handoff.json");
|
|
10280
|
+
if (!existsSync22(path)) return null;
|
|
9956
10281
|
try {
|
|
9957
|
-
return CoworkHandoffPayloadSchema.parse(JSON.parse(await
|
|
10282
|
+
return CoworkHandoffPayloadSchema.parse(JSON.parse(await readFile19(path, "utf8")));
|
|
9958
10283
|
} catch (err) {
|
|
9959
10284
|
warnings.push(`malformed handoff: ${err instanceof Error ? err.message : "parse error"}`);
|
|
9960
10285
|
return null;
|
|
9961
10286
|
}
|
|
9962
10287
|
}
|
|
9963
10288
|
async function readSourceIdsForSection(packPath, sectionId) {
|
|
9964
|
-
const path =
|
|
9965
|
-
if (!
|
|
9966
|
-
const text = await
|
|
10289
|
+
const path = join22(packPath, "sections", sectionId, "sources.jsonl");
|
|
10290
|
+
if (!existsSync22(path)) return [];
|
|
10291
|
+
const text = await readFile19(path, "utf8");
|
|
9967
10292
|
const ids = [];
|
|
9968
10293
|
for (const line of text.split(/\r?\n/)) {
|
|
9969
10294
|
if (!line.trim()) continue;
|
|
@@ -9977,41 +10302,41 @@ async function readSourceIdsForSection(packPath, sectionId) {
|
|
|
9977
10302
|
}
|
|
9978
10303
|
async function audit(options) {
|
|
9979
10304
|
const packPath = options.packPath ? resolve18(options.packPath) : process.cwd();
|
|
9980
|
-
const yamlPath =
|
|
9981
|
-
if (!
|
|
9982
|
-
const research = ResearchYamlSchema.parse(yamlParse8(await
|
|
10305
|
+
const yamlPath = join22(packPath, "research.yaml");
|
|
10306
|
+
if (!existsSync22(yamlPath)) throw new PackNotFoundError(packPath);
|
|
10307
|
+
const research = ResearchYamlSchema.parse(yamlParse8(await readFile19(yamlPath, "utf8")));
|
|
9983
10308
|
const warnings = [];
|
|
9984
10309
|
const perSection = /* @__PURE__ */ new Map();
|
|
9985
10310
|
for (const section of research.sections) {
|
|
9986
10311
|
const sid = section.id;
|
|
9987
10312
|
const claims = await readJsonl5(
|
|
9988
|
-
|
|
10313
|
+
join22(packPath, "sections", sid, "claims.jsonl"),
|
|
9989
10314
|
(r) => ClaimSchema.parse(r),
|
|
9990
10315
|
warnings
|
|
9991
10316
|
);
|
|
9992
10317
|
const candidateClaims = claims.filter((c) => c.review_state === "candidate");
|
|
9993
10318
|
const claimReviews = await readJsonl5(
|
|
9994
|
-
|
|
10319
|
+
join22(packPath, "sections", sid, "claim-reviews.jsonl"),
|
|
9995
10320
|
(r) => ClaimReviewSchema.parse(r),
|
|
9996
10321
|
warnings
|
|
9997
10322
|
);
|
|
9998
10323
|
const contradictions = await readJsonl5(
|
|
9999
|
-
|
|
10324
|
+
join22(packPath, "sections", sid, "contradictions.jsonl"),
|
|
10000
10325
|
(r) => ContradictionSchema.parse(r),
|
|
10001
10326
|
warnings
|
|
10002
10327
|
);
|
|
10003
10328
|
const resolutions = await readJsonl5(
|
|
10004
|
-
|
|
10329
|
+
join22(packPath, "sections", sid, "contradiction-resolutions.jsonl"),
|
|
10005
10330
|
(r) => ContradictionResolutionSchema.parse(r),
|
|
10006
10331
|
warnings
|
|
10007
10332
|
);
|
|
10008
10333
|
const dispositions = await readJsonl5(
|
|
10009
|
-
|
|
10334
|
+
join22(packPath, "sections", sid, "claim-synthesis-dispositions.jsonl"),
|
|
10010
10335
|
(r) => ClaimSynthesisDispositionSchema.parse(r),
|
|
10011
10336
|
warnings
|
|
10012
10337
|
);
|
|
10013
10338
|
const findings = await readJsonl5(
|
|
10014
|
-
|
|
10339
|
+
join22(packPath, "audits", `${sid}-findings.jsonl`),
|
|
10015
10340
|
(r) => ReviewFindingSchema.parse(r),
|
|
10016
10341
|
warnings
|
|
10017
10342
|
);
|
|
@@ -10031,7 +10356,7 @@ async function audit(options) {
|
|
|
10031
10356
|
}
|
|
10032
10357
|
const sources = await readSourceCards6(packPath, warnings);
|
|
10033
10358
|
const receipts = await readJsonl5(
|
|
10034
|
-
|
|
10359
|
+
join22(packPath, "evidence", "fetch-log.jsonl"),
|
|
10035
10360
|
(r) => FetchReceiptSchema.parse(r),
|
|
10036
10361
|
warnings
|
|
10037
10362
|
);
|
|
@@ -10047,11 +10372,11 @@ async function audit(options) {
|
|
|
10047
10372
|
warnings
|
|
10048
10373
|
});
|
|
10049
10374
|
const payload = PackAuditPayloadSchema.parse(result.payload);
|
|
10050
|
-
const auditsDir =
|
|
10051
|
-
await
|
|
10375
|
+
const auditsDir = join22(packPath, "audits");
|
|
10376
|
+
await mkdir17(auditsDir, { recursive: true });
|
|
10052
10377
|
const filesWritten = [];
|
|
10053
10378
|
const writeFileAndTrack = async (rel, content) => {
|
|
10054
|
-
const abs =
|
|
10379
|
+
const abs = join22(packPath, rel);
|
|
10055
10380
|
await writeFile17(abs, content, "utf8");
|
|
10056
10381
|
filesWritten.push(abs);
|
|
10057
10382
|
};
|
|
@@ -10135,18 +10460,18 @@ var init_audit = __esm({
|
|
|
10135
10460
|
});
|
|
10136
10461
|
|
|
10137
10462
|
// src/freeze/checks.ts
|
|
10138
|
-
import { existsSync as
|
|
10139
|
-
import { readFile as
|
|
10463
|
+
import { existsSync as existsSync23 } from "fs";
|
|
10464
|
+
import { readFile as readFile20, stat as stat2 } from "fs/promises";
|
|
10140
10465
|
import { createHash as createHash8 } from "crypto";
|
|
10141
|
-
import { join as
|
|
10466
|
+
import { join as join23 } from "path";
|
|
10142
10467
|
async function fileSha2562(absPath) {
|
|
10143
|
-
const buf = await
|
|
10468
|
+
const buf = await readFile20(absPath);
|
|
10144
10469
|
const sha = createHash8("sha256").update(buf).digest("hex");
|
|
10145
10470
|
return { path: absPath, sha256: sha, bytes: buf.byteLength };
|
|
10146
10471
|
}
|
|
10147
10472
|
async function hashArtifact(ctx, rel) {
|
|
10148
|
-
const abs =
|
|
10149
|
-
if (!
|
|
10473
|
+
const abs = join23(ctx.packPath, rel);
|
|
10474
|
+
if (!existsSync23(abs)) {
|
|
10150
10475
|
ctx.missingArtifacts.push(rel);
|
|
10151
10476
|
return null;
|
|
10152
10477
|
}
|
|
@@ -10357,88 +10682,88 @@ var init_markdown7 = __esm({
|
|
|
10357
10682
|
});
|
|
10358
10683
|
|
|
10359
10684
|
// src/freeze/schema.ts
|
|
10360
|
-
import { z as
|
|
10685
|
+
import { z as z18 } from "zod";
|
|
10361
10686
|
var ArtifactHashSchema, IntegrityCheckSchema, FreezeReceiptPayloadSchema, FreezeRefusalPayloadSchema;
|
|
10362
10687
|
var init_schema16 = __esm({
|
|
10363
10688
|
"src/freeze/schema.ts"() {
|
|
10364
10689
|
"use strict";
|
|
10365
|
-
ArtifactHashSchema =
|
|
10366
|
-
path:
|
|
10367
|
-
sha256:
|
|
10368
|
-
bytes:
|
|
10369
|
-
});
|
|
10370
|
-
IntegrityCheckSchema =
|
|
10371
|
-
name:
|
|
10372
|
-
passed:
|
|
10373
|
-
detail:
|
|
10374
|
-
});
|
|
10375
|
-
FreezeReceiptPayloadSchema =
|
|
10376
|
-
pack_id:
|
|
10377
|
-
pack_topic:
|
|
10378
|
-
frozen_at:
|
|
10379
|
-
verdict:
|
|
10380
|
-
pack_audit_hash:
|
|
10381
|
-
handoff_hash:
|
|
10382
|
-
synthesis_hashes:
|
|
10383
|
-
canonical_artifact_hashes:
|
|
10384
|
-
accepted_claim_ids:
|
|
10385
|
-
cited_claim_ids:
|
|
10386
|
-
uncited_accepted_claim_ids:
|
|
10387
|
-
unresolved_contradictions:
|
|
10388
|
-
|
|
10389
|
-
contradiction_id:
|
|
10390
|
-
section_id:
|
|
10391
|
-
type:
|
|
10392
|
-
severity:
|
|
10393
|
-
status:
|
|
10394
|
-
disclosed_in:
|
|
10690
|
+
ArtifactHashSchema = z18.object({
|
|
10691
|
+
path: z18.string(),
|
|
10692
|
+
sha256: z18.string().regex(/^[a-f0-9]{64}$/),
|
|
10693
|
+
bytes: z18.number().int().nonnegative()
|
|
10694
|
+
});
|
|
10695
|
+
IntegrityCheckSchema = z18.object({
|
|
10696
|
+
name: z18.string().min(1),
|
|
10697
|
+
passed: z18.boolean(),
|
|
10698
|
+
detail: z18.string()
|
|
10699
|
+
});
|
|
10700
|
+
FreezeReceiptPayloadSchema = z18.object({
|
|
10701
|
+
pack_id: z18.string(),
|
|
10702
|
+
pack_topic: z18.string(),
|
|
10703
|
+
frozen_at: z18.string(),
|
|
10704
|
+
verdict: z18.literal("frozen"),
|
|
10705
|
+
pack_audit_hash: z18.string().regex(/^[a-f0-9]{64}$/),
|
|
10706
|
+
handoff_hash: z18.string().regex(/^[a-f0-9]{64}$/),
|
|
10707
|
+
synthesis_hashes: z18.array(ArtifactHashSchema),
|
|
10708
|
+
canonical_artifact_hashes: z18.array(ArtifactHashSchema),
|
|
10709
|
+
accepted_claim_ids: z18.array(z18.string()),
|
|
10710
|
+
cited_claim_ids: z18.array(z18.string()),
|
|
10711
|
+
uncited_accepted_claim_ids: z18.array(z18.string()),
|
|
10712
|
+
unresolved_contradictions: z18.array(
|
|
10713
|
+
z18.object({
|
|
10714
|
+
contradiction_id: z18.string(),
|
|
10715
|
+
section_id: z18.string(),
|
|
10716
|
+
type: z18.string(),
|
|
10717
|
+
severity: z18.string(),
|
|
10718
|
+
status: z18.string(),
|
|
10719
|
+
disclosed_in: z18.array(z18.string())
|
|
10395
10720
|
})
|
|
10396
10721
|
),
|
|
10397
|
-
waivers_disclosed:
|
|
10398
|
-
|
|
10399
|
-
family:
|
|
10400
|
-
applied_to:
|
|
10401
|
-
reason:
|
|
10402
|
-
compensating_controls:
|
|
10403
|
-
disclosed_in:
|
|
10722
|
+
waivers_disclosed: z18.array(
|
|
10723
|
+
z18.object({
|
|
10724
|
+
family: z18.string(),
|
|
10725
|
+
applied_to: z18.string(),
|
|
10726
|
+
reason: z18.string(),
|
|
10727
|
+
compensating_controls: z18.array(z18.string()),
|
|
10728
|
+
disclosed_in: z18.array(z18.string())
|
|
10404
10729
|
})
|
|
10405
10730
|
),
|
|
10406
|
-
sections:
|
|
10407
|
-
|
|
10408
|
-
section_id:
|
|
10409
|
-
status:
|
|
10410
|
-
accepted_claims:
|
|
10411
|
-
sources:
|
|
10412
|
-
contradictions:
|
|
10731
|
+
sections: z18.array(
|
|
10732
|
+
z18.object({
|
|
10733
|
+
section_id: z18.string(),
|
|
10734
|
+
status: z18.string(),
|
|
10735
|
+
accepted_claims: z18.number().int().nonnegative(),
|
|
10736
|
+
sources: z18.number().int().nonnegative(),
|
|
10737
|
+
contradictions: z18.number().int().nonnegative()
|
|
10413
10738
|
})
|
|
10414
10739
|
),
|
|
10415
|
-
source_count:
|
|
10416
|
-
claim_count:
|
|
10417
|
-
contradiction_count:
|
|
10418
|
-
review_finding_count:
|
|
10419
|
-
gate_result_count:
|
|
10420
|
-
integrity_checks:
|
|
10421
|
-
});
|
|
10422
|
-
FreezeRefusalPayloadSchema =
|
|
10423
|
-
pack_id:
|
|
10424
|
-
pack_topic:
|
|
10425
|
-
checked_at:
|
|
10426
|
-
verdict:
|
|
10427
|
-
reasons:
|
|
10428
|
-
blocking_reasons:
|
|
10429
|
-
missing_artifacts:
|
|
10430
|
-
invalid_artifacts:
|
|
10431
|
-
next_actions:
|
|
10432
|
-
would_freeze:
|
|
10740
|
+
source_count: z18.number().int().nonnegative(),
|
|
10741
|
+
claim_count: z18.number().int().nonnegative(),
|
|
10742
|
+
contradiction_count: z18.number().int().nonnegative(),
|
|
10743
|
+
review_finding_count: z18.number().int().nonnegative(),
|
|
10744
|
+
gate_result_count: z18.number().int().nonnegative(),
|
|
10745
|
+
integrity_checks: z18.array(IntegrityCheckSchema)
|
|
10746
|
+
});
|
|
10747
|
+
FreezeRefusalPayloadSchema = z18.object({
|
|
10748
|
+
pack_id: z18.string(),
|
|
10749
|
+
pack_topic: z18.string(),
|
|
10750
|
+
checked_at: z18.string(),
|
|
10751
|
+
verdict: z18.literal("refused"),
|
|
10752
|
+
reasons: z18.array(z18.string()),
|
|
10753
|
+
blocking_reasons: z18.array(z18.string()),
|
|
10754
|
+
missing_artifacts: z18.array(z18.string()),
|
|
10755
|
+
invalid_artifacts: z18.array(z18.object({ path: z18.string(), error: z18.string() })),
|
|
10756
|
+
next_actions: z18.array(z18.string()),
|
|
10757
|
+
would_freeze: z18.literal(false)
|
|
10433
10758
|
});
|
|
10434
10759
|
}
|
|
10435
10760
|
});
|
|
10436
10761
|
|
|
10437
10762
|
// src/freeze/run.ts
|
|
10438
|
-
import { existsSync as
|
|
10439
|
-
import { mkdir as
|
|
10763
|
+
import { existsSync as existsSync24 } from "fs";
|
|
10764
|
+
import { mkdir as mkdir18, readFile as readFile21, readdir as readdir2, unlink, writeFile as writeFile18 } from "fs/promises";
|
|
10440
10765
|
import { createHash as createHash9 } from "crypto";
|
|
10441
|
-
import { join as
|
|
10766
|
+
import { join as join24, resolve as resolve19 } from "path";
|
|
10442
10767
|
import { parse as yamlParse9, stringify as yamlStringify6 } from "yaml";
|
|
10443
10768
|
function packId3(research) {
|
|
10444
10769
|
const fingerprint = `${research.topic}|${research.created_at}`;
|
|
@@ -10457,10 +10782,10 @@ function noteRefusal(ctx, reason, blocking = true) {
|
|
|
10457
10782
|
if (blocking) ctx.blockingReasons.push(reason);
|
|
10458
10783
|
}
|
|
10459
10784
|
async function tryReadJson(packPath, rel, parse, invalid) {
|
|
10460
|
-
const abs =
|
|
10461
|
-
if (!
|
|
10785
|
+
const abs = join24(packPath, rel);
|
|
10786
|
+
if (!existsSync24(abs)) return null;
|
|
10462
10787
|
try {
|
|
10463
|
-
return parse(JSON.parse(await
|
|
10788
|
+
return parse(JSON.parse(await readFile21(abs, "utf8")));
|
|
10464
10789
|
} catch (err) {
|
|
10465
10790
|
invalid.push({ path: rel, error: err instanceof Error ? err.message : "parse error" });
|
|
10466
10791
|
return null;
|
|
@@ -10468,8 +10793,8 @@ async function tryReadJson(packPath, rel, parse, invalid) {
|
|
|
10468
10793
|
}
|
|
10469
10794
|
async function freeze(options) {
|
|
10470
10795
|
const packPath = options.packPath ? resolve19(options.packPath) : process.cwd();
|
|
10471
|
-
const yamlPath =
|
|
10472
|
-
if (!
|
|
10796
|
+
const yamlPath = join24(packPath, "research.yaml");
|
|
10797
|
+
if (!existsSync24(yamlPath)) throw new PackNotFoundError(packPath);
|
|
10473
10798
|
const refusal = {
|
|
10474
10799
|
reasons: [],
|
|
10475
10800
|
blockingReasons: [],
|
|
@@ -10478,7 +10803,7 @@ async function freeze(options) {
|
|
|
10478
10803
|
};
|
|
10479
10804
|
let research;
|
|
10480
10805
|
try {
|
|
10481
|
-
research = ResearchYamlSchema.parse(yamlParse9(await
|
|
10806
|
+
research = ResearchYamlSchema.parse(yamlParse9(await readFile21(yamlPath, "utf8")));
|
|
10482
10807
|
} catch (err) {
|
|
10483
10808
|
refusal.invalidArtifacts.push({ path: "research.yaml", error: err instanceof Error ? err.message : "parse error" });
|
|
10484
10809
|
return writeRefusal({
|
|
@@ -10490,13 +10815,13 @@ async function freeze(options) {
|
|
|
10490
10815
|
}
|
|
10491
10816
|
const pid = packId3(research);
|
|
10492
10817
|
for (const rel of REQUIRED_PACK_ARTIFACTS) {
|
|
10493
|
-
if (!
|
|
10818
|
+
if (!existsSync24(join24(packPath, rel))) {
|
|
10494
10819
|
refusal.missingArtifacts.push(rel);
|
|
10495
10820
|
noteRefusal(refusal, `Required artifact missing: ${rel}.`);
|
|
10496
10821
|
}
|
|
10497
10822
|
}
|
|
10498
10823
|
for (const rel of SYNTHESIS_FILES) {
|
|
10499
|
-
if (!
|
|
10824
|
+
if (!existsSync24(join24(packPath, rel))) {
|
|
10500
10825
|
refusal.missingArtifacts.push(rel);
|
|
10501
10826
|
noteRefusal(refusal, `Synthesis artifact missing: ${rel}. Run \`research-os synth workspace\` after the pack reaches synthesis_ready.`);
|
|
10502
10827
|
}
|
|
@@ -10530,22 +10855,22 @@ async function freeze(options) {
|
|
|
10530
10855
|
if (handoff2 && handoff2.mode !== "synthesis_ready") {
|
|
10531
10856
|
noteRefusal(refusal, `Cowork handoff mode is "${handoff2.mode}", not "synthesis_ready".`);
|
|
10532
10857
|
}
|
|
10533
|
-
const finalReportAbs =
|
|
10534
|
-
const decisionBriefAbs =
|
|
10535
|
-
const workingReportAbs =
|
|
10858
|
+
const finalReportAbs = join24(packPath, "synthesis/final-report.md");
|
|
10859
|
+
const decisionBriefAbs = join24(packPath, "synthesis/decision-brief.md");
|
|
10860
|
+
const workingReportAbs = join24(packPath, "synthesis/working-report.md");
|
|
10536
10861
|
let finalReportText = "";
|
|
10537
10862
|
let decisionBriefText = "";
|
|
10538
10863
|
let workingReportText = "";
|
|
10539
|
-
if (
|
|
10540
|
-
if (
|
|
10541
|
-
if (
|
|
10864
|
+
if (existsSync24(finalReportAbs)) finalReportText = await readFile21(finalReportAbs, "utf8");
|
|
10865
|
+
if (existsSync24(decisionBriefAbs)) decisionBriefText = await readFile21(decisionBriefAbs, "utf8");
|
|
10866
|
+
if (existsSync24(workingReportAbs)) workingReportText = await readFile21(workingReportAbs, "utf8");
|
|
10542
10867
|
const livePackClaimIds = /* @__PURE__ */ new Set();
|
|
10543
10868
|
const liveLatestDecisionByClaim = /* @__PURE__ */ new Map();
|
|
10544
10869
|
const liveLatestCreatedAtByClaim = /* @__PURE__ */ new Map();
|
|
10545
10870
|
for (const section of research.sections) {
|
|
10546
|
-
const claimsFile =
|
|
10547
|
-
if (
|
|
10548
|
-
const text = await
|
|
10871
|
+
const claimsFile = join24(packPath, "sections", section.id, "claims.jsonl");
|
|
10872
|
+
if (existsSync24(claimsFile)) {
|
|
10873
|
+
const text = await readFile21(claimsFile, "utf8");
|
|
10549
10874
|
for (const line of text.split(/\r?\n/)) {
|
|
10550
10875
|
if (!line.trim()) continue;
|
|
10551
10876
|
try {
|
|
@@ -10559,9 +10884,9 @@ async function freeze(options) {
|
|
|
10559
10884
|
}
|
|
10560
10885
|
}
|
|
10561
10886
|
}
|
|
10562
|
-
const reviewsFile =
|
|
10563
|
-
if (
|
|
10564
|
-
const text = await
|
|
10887
|
+
const reviewsFile = join24(packPath, "sections", section.id, "claim-reviews.jsonl");
|
|
10888
|
+
if (existsSync24(reviewsFile)) {
|
|
10889
|
+
const text = await readFile21(reviewsFile, "utf8");
|
|
10565
10890
|
const reviews = [];
|
|
10566
10891
|
for (const line of text.split(/\r?\n/)) {
|
|
10567
10892
|
if (!line.trim()) continue;
|
|
@@ -10603,7 +10928,7 @@ async function freeze(options) {
|
|
|
10603
10928
|
const unknownCitations = allCited.filter((c) => isWellFormedClaimId(c) && !allClaimIds.has(c));
|
|
10604
10929
|
const repairCitations = allCited.filter((c) => repairOrRejected.has(c));
|
|
10605
10930
|
const uncitedAccepted = acceptedClaimIds.filter((c) => !allCitedSet.has(c));
|
|
10606
|
-
if (
|
|
10931
|
+
if (existsSync24(finalReportAbs) && finalReportText.trim().length > 0) {
|
|
10607
10932
|
if (citationsInFinal.length === 0 && acceptedClaimIds.length > 0) {
|
|
10608
10933
|
noteRefusal(refusal, "final-report.md contains no [claim:...] citations even though accepted claims exist.");
|
|
10609
10934
|
}
|
|
@@ -10655,7 +10980,7 @@ async function freeze(options) {
|
|
|
10655
10980
|
}
|
|
10656
10981
|
}
|
|
10657
10982
|
for (const section of research.sections) {
|
|
10658
|
-
if (!
|
|
10983
|
+
if (!existsSync24(join24(packPath, "audits", `${section.id}-gate.json`))) {
|
|
10659
10984
|
noteRefusal(refusal, `Section ${section.id} has no gate result on file.`);
|
|
10660
10985
|
refusal.missingArtifacts.push(`audits/${section.id}-gate.json`);
|
|
10661
10986
|
}
|
|
@@ -10695,16 +11020,16 @@ async function freeze(options) {
|
|
|
10695
11020
|
}
|
|
10696
11021
|
canonicalPaths.push("evidence/fetch-log.jsonl");
|
|
10697
11022
|
canonicalPaths.push("evidence/citation-ledger.jsonl");
|
|
10698
|
-
if (
|
|
10699
|
-
const entries = await readdir2(
|
|
11023
|
+
if (existsSync24(join24(packPath, "evidence", "source-cards"))) {
|
|
11024
|
+
const entries = await readdir2(join24(packPath, "evidence", "source-cards"));
|
|
10700
11025
|
for (const e of entries) {
|
|
10701
11026
|
if (e.endsWith(".json")) canonicalPaths.push(`evidence/source-cards/${e}`);
|
|
10702
11027
|
}
|
|
10703
11028
|
}
|
|
10704
11029
|
const canonicalHashes = [];
|
|
10705
11030
|
for (const rel of canonicalPaths) {
|
|
10706
|
-
const abs =
|
|
10707
|
-
if (!
|
|
11031
|
+
const abs = join24(packPath, rel);
|
|
11032
|
+
if (!existsSync24(abs)) continue;
|
|
10708
11033
|
const h = await hashArtifact(ctx, rel);
|
|
10709
11034
|
if (h) canonicalHashes.push(h);
|
|
10710
11035
|
}
|
|
@@ -10758,7 +11083,7 @@ async function freeze(options) {
|
|
|
10758
11083
|
claim_count: acceptedClaimIds.length,
|
|
10759
11084
|
contradiction_count: unresolvedContradictionRefs.length,
|
|
10760
11085
|
review_finding_count: 0,
|
|
10761
|
-
gate_result_count: research.sections.filter((s) =>
|
|
11086
|
+
gate_result_count: research.sections.filter((s) => existsSync24(join24(packPath, "audits", `${s.id}-gate.json`))).length,
|
|
10762
11087
|
integrity_checks: checks
|
|
10763
11088
|
});
|
|
10764
11089
|
const frozenResearch = {
|
|
@@ -10767,14 +11092,14 @@ async function freeze(options) {
|
|
|
10767
11092
|
sections: research.sections.map((s) => ({ ...s, status: "frozen" }))
|
|
10768
11093
|
};
|
|
10769
11094
|
await writeFile18(yamlPath, yamlStringify6(frozenResearch, { lineWidth: 0 }), "utf8");
|
|
10770
|
-
const auditsDir =
|
|
10771
|
-
await
|
|
11095
|
+
const auditsDir = join24(packPath, "audits");
|
|
11096
|
+
await mkdir18(auditsDir, { recursive: true });
|
|
10772
11097
|
for (const stale of ["freeze-refusal.json", "freeze-refusal.md"]) {
|
|
10773
|
-
const p =
|
|
10774
|
-
if (
|
|
11098
|
+
const p = join24(auditsDir, stale);
|
|
11099
|
+
if (existsSync24(p)) await unlink(p);
|
|
10775
11100
|
}
|
|
10776
|
-
const jsonPath =
|
|
10777
|
-
const mdPath =
|
|
11101
|
+
const jsonPath = join24(auditsDir, "freeze-receipt.json");
|
|
11102
|
+
const mdPath = join24(auditsDir, "freeze-receipt.md");
|
|
10778
11103
|
await writeFile18(jsonPath, JSON.stringify(receipt, null, 2), "utf8");
|
|
10779
11104
|
await writeFile18(mdPath, renderFreezeReceiptMarkdown(receipt), "utf8");
|
|
10780
11105
|
return {
|
|
@@ -10804,14 +11129,14 @@ async function writeRefusal(args) {
|
|
|
10804
11129
|
next_actions: nextActions,
|
|
10805
11130
|
would_freeze: false
|
|
10806
11131
|
});
|
|
10807
|
-
const auditsDir =
|
|
10808
|
-
await
|
|
11132
|
+
const auditsDir = join24(args.packPath, "audits");
|
|
11133
|
+
await mkdir18(auditsDir, { recursive: true });
|
|
10809
11134
|
for (const stale of ["freeze-receipt.json", "freeze-receipt.md"]) {
|
|
10810
|
-
const p =
|
|
10811
|
-
if (
|
|
11135
|
+
const p = join24(auditsDir, stale);
|
|
11136
|
+
if (existsSync24(p)) await unlink(p);
|
|
10812
11137
|
}
|
|
10813
|
-
const jsonPath =
|
|
10814
|
-
const mdPath =
|
|
11138
|
+
const jsonPath = join24(auditsDir, "freeze-refusal.json");
|
|
11139
|
+
const mdPath = join24(auditsDir, "freeze-refusal.md");
|
|
10815
11140
|
await writeFile18(jsonPath, JSON.stringify(payload, null, 2), "utf8");
|
|
10816
11141
|
await writeFile18(mdPath, renderFreezeRefusalMarkdown(payload), "utf8");
|
|
10817
11142
|
return {
|
|
@@ -10903,43 +11228,43 @@ var init_freeze = __esm({
|
|
|
10903
11228
|
});
|
|
10904
11229
|
|
|
10905
11230
|
// src/invalidate/schema.ts
|
|
10906
|
-
import { z as
|
|
11231
|
+
import { z as z19 } from "zod";
|
|
10907
11232
|
var ArchivedArtifactSchema, SectionStatusChangeSchema, InvalidationReceiptSchema;
|
|
10908
11233
|
var init_schema17 = __esm({
|
|
10909
11234
|
"src/invalidate/schema.ts"() {
|
|
10910
11235
|
"use strict";
|
|
10911
|
-
ArchivedArtifactSchema =
|
|
10912
|
-
src:
|
|
11236
|
+
ArchivedArtifactSchema = z19.object({
|
|
11237
|
+
src: z19.string(),
|
|
10913
11238
|
// path relative to packPath, before archival
|
|
10914
|
-
dst:
|
|
11239
|
+
dst: z19.string()
|
|
10915
11240
|
// path relative to packPath, after archival
|
|
10916
11241
|
});
|
|
10917
|
-
SectionStatusChangeSchema =
|
|
10918
|
-
section_id:
|
|
10919
|
-
before:
|
|
10920
|
-
after:
|
|
10921
|
-
});
|
|
10922
|
-
InvalidationReceiptSchema =
|
|
10923
|
-
receipt_id:
|
|
10924
|
-
contract_label:
|
|
10925
|
-
superseded_contract:
|
|
10926
|
-
new_contract:
|
|
10927
|
-
reason:
|
|
10928
|
-
invalidated_at:
|
|
10929
|
-
research_os_version:
|
|
10930
|
-
affected_sections:
|
|
10931
|
-
archived_artifacts:
|
|
10932
|
-
section_status_changes:
|
|
10933
|
-
frozen_at_cleared:
|
|
10934
|
-
notes:
|
|
11242
|
+
SectionStatusChangeSchema = z19.object({
|
|
11243
|
+
section_id: z19.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
11244
|
+
before: z19.string(),
|
|
11245
|
+
after: z19.string()
|
|
11246
|
+
});
|
|
11247
|
+
InvalidationReceiptSchema = z19.object({
|
|
11248
|
+
receipt_id: z19.string().regex(/^inv_[0-9]+_[a-z0-9-]+$/),
|
|
11249
|
+
contract_label: z19.string().min(1),
|
|
11250
|
+
superseded_contract: z19.string().min(1).nullable(),
|
|
11251
|
+
new_contract: z19.string().min(1),
|
|
11252
|
+
reason: z19.string().min(8),
|
|
11253
|
+
invalidated_at: z19.string(),
|
|
11254
|
+
research_os_version: z19.string(),
|
|
11255
|
+
affected_sections: z19.array(z19.string().regex(/^[0-9]{2}-[a-z0-9-]+$/)),
|
|
11256
|
+
archived_artifacts: z19.array(ArchivedArtifactSchema),
|
|
11257
|
+
section_status_changes: z19.array(SectionStatusChangeSchema),
|
|
11258
|
+
frozen_at_cleared: z19.boolean(),
|
|
11259
|
+
notes: z19.string().nullable()
|
|
10935
11260
|
});
|
|
10936
11261
|
}
|
|
10937
11262
|
});
|
|
10938
11263
|
|
|
10939
11264
|
// src/invalidate/run.ts
|
|
10940
|
-
import { existsSync as
|
|
10941
|
-
import { mkdir as
|
|
10942
|
-
import { dirname as
|
|
11265
|
+
import { existsSync as existsSync25 } from "fs";
|
|
11266
|
+
import { mkdir as mkdir19, readFile as readFile22, readdir as readdir3, rename, writeFile as writeFile19 } from "fs/promises";
|
|
11267
|
+
import { dirname as dirname6, join as join25, posix, relative as relative3, resolve as resolve20, sep } from "path";
|
|
10943
11268
|
import { parse as yamlParse10, stringify as yamlStringify7 } from "yaml";
|
|
10944
11269
|
function posixify(p) {
|
|
10945
11270
|
return p.split(sep).join("/");
|
|
@@ -10957,15 +11282,15 @@ function isLegacyClaimLine(line) {
|
|
|
10957
11282
|
}
|
|
10958
11283
|
}
|
|
10959
11284
|
async function detectLegacyClaimSections(packPath) {
|
|
10960
|
-
const sectionsDir =
|
|
10961
|
-
if (!
|
|
11285
|
+
const sectionsDir = join25(packPath, "sections");
|
|
11286
|
+
if (!existsSync25(sectionsDir)) return [];
|
|
10962
11287
|
const entries = await readdir3(sectionsDir, { withFileTypes: true });
|
|
10963
11288
|
const affected = [];
|
|
10964
11289
|
for (const entry of entries) {
|
|
10965
11290
|
if (!entry.isDirectory()) continue;
|
|
10966
|
-
const claimsPath =
|
|
10967
|
-
if (!
|
|
10968
|
-
const text = await
|
|
11291
|
+
const claimsPath = join25(sectionsDir, entry.name, "claims.jsonl");
|
|
11292
|
+
if (!existsSync25(claimsPath)) continue;
|
|
11293
|
+
const text = await readFile22(claimsPath, "utf8");
|
|
10969
11294
|
let hasLegacy = false;
|
|
10970
11295
|
for (const line of text.split(/\r?\n/)) {
|
|
10971
11296
|
if (isLegacyClaimLine(line)) {
|
|
@@ -10978,16 +11303,16 @@ async function detectLegacyClaimSections(packPath) {
|
|
|
10978
11303
|
return affected.sort();
|
|
10979
11304
|
}
|
|
10980
11305
|
async function moveIfExists(packPath, archiveRel, rel) {
|
|
10981
|
-
const src =
|
|
10982
|
-
if (!
|
|
10983
|
-
const dst =
|
|
10984
|
-
await
|
|
11306
|
+
const src = join25(packPath, rel);
|
|
11307
|
+
if (!existsSync25(src)) return null;
|
|
11308
|
+
const dst = join25(packPath, archiveRel, rel);
|
|
11309
|
+
await mkdir19(dirname6(dst), { recursive: true });
|
|
10985
11310
|
await rename(src, dst);
|
|
10986
|
-
return { src: posixify(rel), dst: posixify(
|
|
11311
|
+
return { src: posixify(rel), dst: posixify(join25(archiveRel, rel)) };
|
|
10987
11312
|
}
|
|
10988
11313
|
async function moveDirContentsIfExists(packPath, archiveRel, relDir, skipPrefix) {
|
|
10989
|
-
const fullDir =
|
|
10990
|
-
if (!
|
|
11314
|
+
const fullDir = join25(packPath, relDir);
|
|
11315
|
+
if (!existsSync25(fullDir)) return [];
|
|
10991
11316
|
const entries = await readdir3(fullDir, { withFileTypes: true });
|
|
10992
11317
|
const moved = [];
|
|
10993
11318
|
for (const entry of entries) {
|
|
@@ -11065,8 +11390,8 @@ function buildReceiptMarkdown(receipt) {
|
|
|
11065
11390
|
}
|
|
11066
11391
|
async function invalidateExtraction(options) {
|
|
11067
11392
|
const packPath = options.packPath ? resolve20(options.packPath) : process.cwd();
|
|
11068
|
-
const yamlPath =
|
|
11069
|
-
if (!
|
|
11393
|
+
const yamlPath = join25(packPath, "research.yaml");
|
|
11394
|
+
if (!existsSync25(yamlPath)) throw new PackNotFoundError(packPath);
|
|
11070
11395
|
const reason = options.reason.trim();
|
|
11071
11396
|
if (reason.length < 8) {
|
|
11072
11397
|
throw new Error("invalidation reason must be at least 8 characters");
|
|
@@ -11084,13 +11409,13 @@ async function invalidateExtraction(options) {
|
|
|
11084
11409
|
const stampPath = stampIso.replace(/[:]/g, "").replace(/\.\d+Z$/, "Z");
|
|
11085
11410
|
const archiveRel = posix.join("audits", "legacy", label, stampPath);
|
|
11086
11411
|
const affectedSections = await detectLegacyClaimSections(packPath);
|
|
11087
|
-
const research = ResearchYamlSchema.parse(yamlParse10(await
|
|
11412
|
+
const research = ResearchYamlSchema.parse(yamlParse10(await readFile22(yamlPath, "utf8")));
|
|
11088
11413
|
const packLevelDirs = ["handoffs", "synthesis", "audits"];
|
|
11089
11414
|
let probeArtifactsExist = affectedSections.length > 0;
|
|
11090
11415
|
if (!probeArtifactsExist) {
|
|
11091
11416
|
for (const d of packLevelDirs) {
|
|
11092
|
-
const full =
|
|
11093
|
-
if (!
|
|
11417
|
+
const full = join25(packPath, d);
|
|
11418
|
+
if (!existsSync25(full)) continue;
|
|
11094
11419
|
const entries = await readdir3(full, { withFileTypes: true });
|
|
11095
11420
|
const meaningful = entries.some(
|
|
11096
11421
|
(e) => !(d === "audits" && e.isDirectory() && e.name === "legacy")
|
|
@@ -11112,7 +11437,7 @@ async function invalidateExtraction(options) {
|
|
|
11112
11437
|
message: "No legacy artifacts found. Pack is on the current extraction contract."
|
|
11113
11438
|
};
|
|
11114
11439
|
}
|
|
11115
|
-
await
|
|
11440
|
+
await mkdir19(join25(packPath, archiveRel), { recursive: true });
|
|
11116
11441
|
const archived = [];
|
|
11117
11442
|
for (const sectionId of affectedSections) {
|
|
11118
11443
|
for (const filename of [
|
|
@@ -11161,14 +11486,14 @@ async function invalidateExtraction(options) {
|
|
|
11161
11486
|
frozen_at_cleared: frozenAtCleared,
|
|
11162
11487
|
notes: options.notes ?? null
|
|
11163
11488
|
});
|
|
11164
|
-
const receiptDir =
|
|
11489
|
+
const receiptDir = join25(packPath, archiveRel);
|
|
11165
11490
|
await writeFile19(
|
|
11166
|
-
|
|
11491
|
+
join25(receiptDir, "invalidation.json"),
|
|
11167
11492
|
JSON.stringify(receipt, null, 2),
|
|
11168
11493
|
"utf8"
|
|
11169
11494
|
);
|
|
11170
11495
|
await writeFile19(
|
|
11171
|
-
|
|
11496
|
+
join25(receiptDir, "invalidation.md"),
|
|
11172
11497
|
buildReceiptMarkdown(receipt),
|
|
11173
11498
|
"utf8"
|
|
11174
11499
|
);
|
|
@@ -11194,20 +11519,20 @@ var init_run9 = __esm({
|
|
|
11194
11519
|
});
|
|
11195
11520
|
|
|
11196
11521
|
// src/invalidate/review.ts
|
|
11197
|
-
import { existsSync as
|
|
11198
|
-
import { mkdir as
|
|
11199
|
-
import { dirname as
|
|
11200
|
-
import { z as
|
|
11522
|
+
import { existsSync as existsSync26 } from "fs";
|
|
11523
|
+
import { mkdir as mkdir20, rename as rename2, writeFile as writeFile20 } from "fs/promises";
|
|
11524
|
+
import { dirname as dirname7, join as join26, posix as posix2, relative as relative4, resolve as resolve21, sep as sep2 } from "path";
|
|
11525
|
+
import { z as z20 } from "zod";
|
|
11201
11526
|
function posixify2(p) {
|
|
11202
11527
|
return p.split(sep2).join("/");
|
|
11203
11528
|
}
|
|
11204
11529
|
async function moveIfExists2(packPath, archiveRel, rel) {
|
|
11205
|
-
const src =
|
|
11206
|
-
if (!
|
|
11207
|
-
const dst =
|
|
11208
|
-
await
|
|
11530
|
+
const src = join26(packPath, rel);
|
|
11531
|
+
if (!existsSync26(src)) return null;
|
|
11532
|
+
const dst = join26(packPath, archiveRel, rel);
|
|
11533
|
+
await mkdir20(dirname7(dst), { recursive: true });
|
|
11209
11534
|
await rename2(src, dst);
|
|
11210
|
-
return { src: posixify2(rel), dst: posixify2(
|
|
11535
|
+
return { src: posixify2(rel), dst: posixify2(join26(archiveRel, rel)) };
|
|
11211
11536
|
}
|
|
11212
11537
|
function buildReceiptMarkdown2(receipt) {
|
|
11213
11538
|
const lines = [];
|
|
@@ -11249,8 +11574,8 @@ function buildReceiptMarkdown2(receipt) {
|
|
|
11249
11574
|
}
|
|
11250
11575
|
async function invalidateReview(options) {
|
|
11251
11576
|
const packPath = options.packPath ? resolve21(options.packPath) : process.cwd();
|
|
11252
|
-
if (!
|
|
11253
|
-
if (!
|
|
11577
|
+
if (!existsSync26(join26(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
11578
|
+
if (!existsSync26(join26(packPath, "sections", options.sectionId)))
|
|
11254
11579
|
throw new SectionNotFoundError(options.sectionId);
|
|
11255
11580
|
const reason = options.reason.trim();
|
|
11256
11581
|
if (reason.length < 8) {
|
|
@@ -11273,7 +11598,7 @@ async function invalidateReview(options) {
|
|
|
11273
11598
|
// Also clear review-active.json so the next review run is unambiguous.
|
|
11274
11599
|
posix2.join("sections", options.sectionId, "review-active.json")
|
|
11275
11600
|
];
|
|
11276
|
-
const present = candidatePaths.filter((rel) =>
|
|
11601
|
+
const present = candidatePaths.filter((rel) => existsSync26(join26(packPath, rel)));
|
|
11277
11602
|
if (present.length === 0) {
|
|
11278
11603
|
return {
|
|
11279
11604
|
performed: false,
|
|
@@ -11285,7 +11610,7 @@ async function invalidateReview(options) {
|
|
|
11285
11610
|
message: "No canonical review artifacts found to invalidate. Section has no active review state."
|
|
11286
11611
|
};
|
|
11287
11612
|
}
|
|
11288
|
-
await
|
|
11613
|
+
await mkdir20(join26(packPath, archiveRel), { recursive: true });
|
|
11289
11614
|
const archived = [];
|
|
11290
11615
|
for (const rel of present) {
|
|
11291
11616
|
const a = await moveIfExists2(packPath, archiveRel, rel);
|
|
@@ -11301,14 +11626,14 @@ async function invalidateReview(options) {
|
|
|
11301
11626
|
archived_artifacts: archived,
|
|
11302
11627
|
notes: options.notes ?? null
|
|
11303
11628
|
});
|
|
11304
|
-
const receiptDir =
|
|
11629
|
+
const receiptDir = join26(packPath, archiveRel);
|
|
11305
11630
|
await writeFile20(
|
|
11306
|
-
|
|
11631
|
+
join26(receiptDir, "invalidation.json"),
|
|
11307
11632
|
JSON.stringify(receipt, null, 2),
|
|
11308
11633
|
"utf8"
|
|
11309
11634
|
);
|
|
11310
11635
|
await writeFile20(
|
|
11311
|
-
|
|
11636
|
+
join26(receiptDir, "invalidation.md"),
|
|
11312
11637
|
buildReceiptMarkdown2(receipt),
|
|
11313
11638
|
"utf8"
|
|
11314
11639
|
);
|
|
@@ -11329,15 +11654,15 @@ var init_review2 = __esm({
|
|
|
11329
11654
|
init_errors();
|
|
11330
11655
|
init_src();
|
|
11331
11656
|
init_schema17();
|
|
11332
|
-
ReviewInvalidationReceiptSchema =
|
|
11333
|
-
receipt_id:
|
|
11334
|
-
section_id:
|
|
11335
|
-
contract_label:
|
|
11336
|
-
reason:
|
|
11337
|
-
invalidated_at:
|
|
11338
|
-
research_os_version:
|
|
11339
|
-
archived_artifacts:
|
|
11340
|
-
notes:
|
|
11657
|
+
ReviewInvalidationReceiptSchema = z20.object({
|
|
11658
|
+
receipt_id: z20.string().regex(/^invr_[0-9]+_[a-z0-9-]+$/),
|
|
11659
|
+
section_id: z20.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
11660
|
+
contract_label: z20.string().min(1),
|
|
11661
|
+
reason: z20.string().min(8),
|
|
11662
|
+
invalidated_at: z20.string(),
|
|
11663
|
+
research_os_version: z20.string(),
|
|
11664
|
+
archived_artifacts: z20.array(ArchivedArtifactSchema),
|
|
11665
|
+
notes: z20.string().nullable()
|
|
11341
11666
|
});
|
|
11342
11667
|
}
|
|
11343
11668
|
});
|
|
@@ -11353,103 +11678,103 @@ var init_invalidate = __esm({
|
|
|
11353
11678
|
});
|
|
11354
11679
|
|
|
11355
11680
|
// src/section_report/schema.ts
|
|
11356
|
-
import { z as
|
|
11681
|
+
import { z as z21 } from "zod";
|
|
11357
11682
|
var SectionReportSourcesSchema, SectionReportExtractionSchema, SectionReportContradictionsSchema, SectionReportReviewSchema, SectionReportAcceptanceSchema, SectionReportSchema;
|
|
11358
11683
|
var init_schema18 = __esm({
|
|
11359
11684
|
"src/section_report/schema.ts"() {
|
|
11360
11685
|
"use strict";
|
|
11361
|
-
SectionReportSourcesSchema =
|
|
11362
|
-
fetched_ok:
|
|
11363
|
-
source_cards:
|
|
11364
|
-
publishers:
|
|
11365
|
-
primary_source_waiver:
|
|
11366
|
-
status:
|
|
11367
|
-
reason:
|
|
11368
|
-
compensating_controls:
|
|
11686
|
+
SectionReportSourcesSchema = z21.object({
|
|
11687
|
+
fetched_ok: z21.number().int().nonnegative(),
|
|
11688
|
+
source_cards: z21.number().int().nonnegative(),
|
|
11689
|
+
publishers: z21.array(z21.string()),
|
|
11690
|
+
primary_source_waiver: z21.object({
|
|
11691
|
+
status: z21.enum(["none", "requested", "granted"]),
|
|
11692
|
+
reason: z21.string().nullable(),
|
|
11693
|
+
compensating_controls: z21.array(z21.string())
|
|
11369
11694
|
})
|
|
11370
11695
|
});
|
|
11371
|
-
SectionReportExtractionSchema =
|
|
11372
|
-
candidate_claims:
|
|
11373
|
-
claims_per_source:
|
|
11374
|
-
|
|
11375
|
-
source_id:
|
|
11376
|
-
claims:
|
|
11696
|
+
SectionReportExtractionSchema = z21.object({
|
|
11697
|
+
candidate_claims: z21.number().int().nonnegative(),
|
|
11698
|
+
claims_per_source: z21.array(
|
|
11699
|
+
z21.object({
|
|
11700
|
+
source_id: z21.string(),
|
|
11701
|
+
claims: z21.number().int().nonnegative()
|
|
11377
11702
|
})
|
|
11378
11703
|
),
|
|
11379
|
-
claims_per_1k_words:
|
|
11380
|
-
excerpt_pages_processed:
|
|
11381
|
-
excerpt_id_failures:
|
|
11382
|
-
malformed_extractor_outputs:
|
|
11383
|
-
near_duplicate_clusters:
|
|
11384
|
-
weak_scope_count:
|
|
11385
|
-
generic_scope_count:
|
|
11386
|
-
density_flags:
|
|
11387
|
-
});
|
|
11388
|
-
SectionReportContradictionsSchema =
|
|
11389
|
-
pairs_compared:
|
|
11390
|
-
contradiction_candidates:
|
|
11391
|
-
overgeneralization_risks:
|
|
11392
|
-
});
|
|
11393
|
-
SectionReportReviewSchema =
|
|
11394
|
-
reviewed:
|
|
11395
|
-
accepted_for_synthesis:
|
|
11396
|
-
needs_scope_repair:
|
|
11397
|
-
needs_source_repair:
|
|
11398
|
-
needs_contradiction_mapping:
|
|
11399
|
-
rejected:
|
|
11400
|
-
needs_human_review:
|
|
11401
|
-
rejection_or_repair_by_category:
|
|
11402
|
-
|
|
11403
|
-
category:
|
|
11404
|
-
count:
|
|
11704
|
+
claims_per_1k_words: z21.number(),
|
|
11705
|
+
excerpt_pages_processed: z21.number().int().nonnegative().nullable(),
|
|
11706
|
+
excerpt_id_failures: z21.number().int().nonnegative().nullable(),
|
|
11707
|
+
malformed_extractor_outputs: z21.number().int().nonnegative().nullable(),
|
|
11708
|
+
near_duplicate_clusters: z21.number().int().nonnegative(),
|
|
11709
|
+
weak_scope_count: z21.number().int().nonnegative(),
|
|
11710
|
+
generic_scope_count: z21.number().int().nonnegative(),
|
|
11711
|
+
density_flags: z21.number().int().nonnegative()
|
|
11712
|
+
});
|
|
11713
|
+
SectionReportContradictionsSchema = z21.object({
|
|
11714
|
+
pairs_compared: z21.number().int().nonnegative().nullable(),
|
|
11715
|
+
contradiction_candidates: z21.number().int().nonnegative(),
|
|
11716
|
+
overgeneralization_risks: z21.number().int().nonnegative()
|
|
11717
|
+
});
|
|
11718
|
+
SectionReportReviewSchema = z21.object({
|
|
11719
|
+
reviewed: z21.boolean(),
|
|
11720
|
+
accepted_for_synthesis: z21.number().int().nonnegative(),
|
|
11721
|
+
needs_scope_repair: z21.number().int().nonnegative(),
|
|
11722
|
+
needs_source_repair: z21.number().int().nonnegative(),
|
|
11723
|
+
needs_contradiction_mapping: z21.number().int().nonnegative(),
|
|
11724
|
+
rejected: z21.number().int().nonnegative(),
|
|
11725
|
+
needs_human_review: z21.number().int().nonnegative(),
|
|
11726
|
+
rejection_or_repair_by_category: z21.array(
|
|
11727
|
+
z21.object({
|
|
11728
|
+
category: z21.string(),
|
|
11729
|
+
count: z21.number().int().nonnegative()
|
|
11405
11730
|
})
|
|
11406
11731
|
)
|
|
11407
11732
|
});
|
|
11408
|
-
SectionReportAcceptanceSchema =
|
|
11409
|
-
candidate_claims:
|
|
11410
|
-
accepted_for_synthesis:
|
|
11411
|
-
acceptance_ratio:
|
|
11733
|
+
SectionReportAcceptanceSchema = z21.object({
|
|
11734
|
+
candidate_claims: z21.number().int().nonnegative(),
|
|
11735
|
+
accepted_for_synthesis: z21.number().int().nonnegative(),
|
|
11736
|
+
acceptance_ratio: z21.number(),
|
|
11412
11737
|
// 0..1
|
|
11413
|
-
accepted_per_source:
|
|
11738
|
+
accepted_per_source: z21.number(),
|
|
11414
11739
|
// accepted / source_count, 0 if no sources
|
|
11415
|
-
accepted_per_1k_words:
|
|
11416
|
-
top_rejection_category:
|
|
11417
|
-
claim_overproduction_fired:
|
|
11418
|
-
synthesis_ready:
|
|
11740
|
+
accepted_per_1k_words: z21.number(),
|
|
11741
|
+
top_rejection_category: z21.string().nullable(),
|
|
11742
|
+
claim_overproduction_fired: z21.boolean(),
|
|
11743
|
+
synthesis_ready: z21.boolean()
|
|
11419
11744
|
});
|
|
11420
|
-
SectionReportSchema =
|
|
11421
|
-
report_id:
|
|
11422
|
-
section_id:
|
|
11423
|
-
reported_at:
|
|
11424
|
-
research_os_version:
|
|
11425
|
-
status:
|
|
11745
|
+
SectionReportSchema = z21.object({
|
|
11746
|
+
report_id: z21.string().regex(/^secrep_[0-9]+_[a-z0-9-]+$/),
|
|
11747
|
+
section_id: z21.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
11748
|
+
reported_at: z21.string(),
|
|
11749
|
+
research_os_version: z21.string(),
|
|
11750
|
+
status: z21.string(),
|
|
11426
11751
|
sources: SectionReportSourcesSchema,
|
|
11427
11752
|
extraction: SectionReportExtractionSchema,
|
|
11428
11753
|
contradictions: SectionReportContradictionsSchema,
|
|
11429
11754
|
review: SectionReportReviewSchema,
|
|
11430
11755
|
acceptance: SectionReportAcceptanceSchema,
|
|
11431
|
-
gate_verdict:
|
|
11432
|
-
gate_synthesis_eligible:
|
|
11756
|
+
gate_verdict: z21.string().nullable(),
|
|
11757
|
+
gate_synthesis_eligible: z21.boolean().nullable()
|
|
11433
11758
|
});
|
|
11434
11759
|
}
|
|
11435
11760
|
});
|
|
11436
11761
|
|
|
11437
11762
|
// src/section_report/run.ts
|
|
11438
|
-
import { existsSync as
|
|
11439
|
-
import { mkdir as
|
|
11440
|
-
import { join as
|
|
11763
|
+
import { existsSync as existsSync27 } from "fs";
|
|
11764
|
+
import { mkdir as mkdir21, readFile as readFile23, writeFile as writeFile21 } from "fs/promises";
|
|
11765
|
+
import { join as join27, resolve as resolve22 } from "path";
|
|
11441
11766
|
import { parse as yamlParse11 } from "yaml";
|
|
11442
11767
|
async function readJson(path, parser) {
|
|
11443
|
-
if (!
|
|
11768
|
+
if (!existsSync27(path)) return null;
|
|
11444
11769
|
try {
|
|
11445
|
-
return parser(JSON.parse(await
|
|
11770
|
+
return parser(JSON.parse(await readFile23(path, "utf8")));
|
|
11446
11771
|
} catch {
|
|
11447
11772
|
return null;
|
|
11448
11773
|
}
|
|
11449
11774
|
}
|
|
11450
11775
|
async function readJsonl6(path, parse) {
|
|
11451
|
-
if (!
|
|
11452
|
-
const text = await
|
|
11776
|
+
if (!existsSync27(path)) return [];
|
|
11777
|
+
const text = await readFile23(path, "utf8");
|
|
11453
11778
|
const out = [];
|
|
11454
11779
|
for (const line of text.split(/\r?\n/)) {
|
|
11455
11780
|
if (!line.trim()) continue;
|
|
@@ -11466,15 +11791,15 @@ function countWords2(text) {
|
|
|
11466
11791
|
}
|
|
11467
11792
|
async function reportSection(options) {
|
|
11468
11793
|
const packPath = options.packPath ? resolve22(options.packPath) : process.cwd();
|
|
11469
|
-
if (!
|
|
11470
|
-
if (!
|
|
11794
|
+
if (!existsSync27(join27(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
11795
|
+
if (!existsSync27(join27(packPath, "sections", options.sectionId)))
|
|
11471
11796
|
throw new SectionNotFoundError(options.sectionId);
|
|
11472
11797
|
const research = ResearchYamlSchema.parse(
|
|
11473
|
-
yamlParse11(await
|
|
11798
|
+
yamlParse11(await readFile23(join27(packPath, "research.yaml"), "utf8"))
|
|
11474
11799
|
);
|
|
11475
11800
|
const section = research.sections.find((s) => s.id === options.sectionId);
|
|
11476
11801
|
const allReceipts = await readJsonl6(
|
|
11477
|
-
|
|
11802
|
+
join27(packPath, "evidence", "fetch-log.jsonl"),
|
|
11478
11803
|
(raw) => FetchReceiptSchema.parse(raw)
|
|
11479
11804
|
);
|
|
11480
11805
|
const okReceipts = /* @__PURE__ */ new Map();
|
|
@@ -11485,9 +11810,9 @@ async function reportSection(options) {
|
|
|
11485
11810
|
if (!prev || prev.fetched_at < r.fetched_at) okReceipts.set(r.source_id, r);
|
|
11486
11811
|
}
|
|
11487
11812
|
const sectionSourceIds = [];
|
|
11488
|
-
const sourcesPath =
|
|
11489
|
-
if (
|
|
11490
|
-
const text = await
|
|
11813
|
+
const sourcesPath = join27(packPath, "sections", options.sectionId, "sources.jsonl");
|
|
11814
|
+
if (existsSync27(sourcesPath)) {
|
|
11815
|
+
const text = await readFile23(sourcesPath, "utf8");
|
|
11491
11816
|
for (const line of text.split(/\r?\n/)) {
|
|
11492
11817
|
if (!line.trim()) continue;
|
|
11493
11818
|
try {
|
|
@@ -11499,10 +11824,10 @@ async function reportSection(options) {
|
|
|
11499
11824
|
}
|
|
11500
11825
|
const cards = /* @__PURE__ */ new Map();
|
|
11501
11826
|
for (const sid of sectionSourceIds) {
|
|
11502
|
-
const cardPath =
|
|
11503
|
-
if (!
|
|
11827
|
+
const cardPath = join27(packPath, "evidence", "source-cards", `${sid}.json`);
|
|
11828
|
+
if (!existsSync27(cardPath)) continue;
|
|
11504
11829
|
try {
|
|
11505
|
-
cards.set(sid, SourceCardSchema.parse(JSON.parse(await
|
|
11830
|
+
cards.set(sid, SourceCardSchema.parse(JSON.parse(await readFile23(cardPath, "utf8"))));
|
|
11506
11831
|
} catch {
|
|
11507
11832
|
}
|
|
11508
11833
|
}
|
|
@@ -11513,12 +11838,12 @@ async function reportSection(options) {
|
|
|
11513
11838
|
for (const sid of sectionSourceIds) {
|
|
11514
11839
|
const r = okReceipts.get(sid);
|
|
11515
11840
|
if (!r?.raw_text_path) continue;
|
|
11516
|
-
const p =
|
|
11517
|
-
if (!
|
|
11518
|
-
totalWords += countWords2(await
|
|
11841
|
+
const p = join27(packPath, r.raw_text_path);
|
|
11842
|
+
if (!existsSync27(p)) continue;
|
|
11843
|
+
totalWords += countWords2(await readFile23(p, "utf8"));
|
|
11519
11844
|
}
|
|
11520
11845
|
const claims = await readJsonl6(
|
|
11521
|
-
|
|
11846
|
+
join27(packPath, "sections", options.sectionId, "claims.jsonl"),
|
|
11522
11847
|
(raw) => ClaimSchema.parse(raw)
|
|
11523
11848
|
);
|
|
11524
11849
|
const claimsBySrc = /* @__PURE__ */ new Map();
|
|
@@ -11530,11 +11855,11 @@ async function reportSection(options) {
|
|
|
11530
11855
|
}
|
|
11531
11856
|
}
|
|
11532
11857
|
const density = await readJson(
|
|
11533
|
-
|
|
11858
|
+
join27(packPath, "audits", `${options.sectionId}-claim-density.json`),
|
|
11534
11859
|
(raw) => raw
|
|
11535
11860
|
);
|
|
11536
11861
|
const extractReceipt = await readJson(
|
|
11537
|
-
|
|
11862
|
+
join27(packPath, "audits", `${options.sectionId}-claim-extract.json`),
|
|
11538
11863
|
(raw) => raw
|
|
11539
11864
|
);
|
|
11540
11865
|
let excerptPagesProcessed = null;
|
|
@@ -11552,7 +11877,7 @@ async function reportSection(options) {
|
|
|
11552
11877
|
).length;
|
|
11553
11878
|
}
|
|
11554
11879
|
const contradictions = await readJsonl6(
|
|
11555
|
-
|
|
11880
|
+
join27(packPath, "sections", options.sectionId, "contradictions.jsonl"),
|
|
11556
11881
|
(raw) => ContradictionSchema.parse(raw)
|
|
11557
11882
|
);
|
|
11558
11883
|
let pairsCompared = null;
|
|
@@ -11561,7 +11886,7 @@ async function reportSection(options) {
|
|
|
11561
11886
|
(c) => c.type === "overgeneralization_risk"
|
|
11562
11887
|
).length;
|
|
11563
11888
|
const reviews = await readJsonl6(
|
|
11564
|
-
|
|
11889
|
+
join27(packPath, "sections", options.sectionId, "claim-reviews.jsonl"),
|
|
11565
11890
|
(raw) => ClaimReviewSchema.parse(raw)
|
|
11566
11891
|
);
|
|
11567
11892
|
const latestReviewByClaim = /* @__PURE__ */ new Map();
|
|
@@ -11570,7 +11895,7 @@ async function reportSection(options) {
|
|
|
11570
11895
|
if (!prev || prev.created_at < r.created_at) latestReviewByClaim.set(r.claim_id, r);
|
|
11571
11896
|
}
|
|
11572
11897
|
const findings = await readJsonl6(
|
|
11573
|
-
|
|
11898
|
+
join27(packPath, "audits", `${options.sectionId}-findings.jsonl`),
|
|
11574
11899
|
(raw) => ReviewFindingSchema.parse(raw)
|
|
11575
11900
|
);
|
|
11576
11901
|
const decisionCounts = {
|
|
@@ -11595,7 +11920,7 @@ async function reportSection(options) {
|
|
|
11595
11920
|
const topRejectionCategory = rejectionByCategory[0]?.category ?? null;
|
|
11596
11921
|
const claimOverproductionFired = (categoryCounts.get("claim_overproduction") ?? 0) > 0;
|
|
11597
11922
|
const gate2 = await readJson(
|
|
11598
|
-
|
|
11923
|
+
join27(packPath, "audits", `${options.sectionId}-gate.json`),
|
|
11599
11924
|
(raw) => raw
|
|
11600
11925
|
);
|
|
11601
11926
|
const candidate = claims.length;
|
|
@@ -11731,10 +12056,10 @@ async function reportSection(options) {
|
|
|
11731
12056
|
md.push("---");
|
|
11732
12057
|
md.push("");
|
|
11733
12058
|
md.push("_This report is read-only \u2014 it does not mutate any canonical artifact. Re-run after any pipeline step to refresh._");
|
|
11734
|
-
const auditsDir =
|
|
11735
|
-
await
|
|
11736
|
-
const jsonPath =
|
|
11737
|
-
const markdownPath =
|
|
12059
|
+
const auditsDir = join27(packPath, "audits");
|
|
12060
|
+
await mkdir21(auditsDir, { recursive: true });
|
|
12061
|
+
const jsonPath = join27(auditsDir, `${options.sectionId}-section-report.json`);
|
|
12062
|
+
const markdownPath = join27(auditsDir, `${options.sectionId}-section-report.md`);
|
|
11738
12063
|
await writeFile21(jsonPath, JSON.stringify(report, null, 2), "utf8");
|
|
11739
12064
|
await writeFile21(markdownPath, md.join("\n"), "utf8");
|
|
11740
12065
|
return { report, jsonPath, markdownPath };
|
|
@@ -11772,17 +12097,17 @@ var init_triage = __esm({
|
|
|
11772
12097
|
});
|
|
11773
12098
|
|
|
11774
12099
|
// src/discover/schema.ts
|
|
11775
|
-
import { z as
|
|
12100
|
+
import { z as z22 } from "zod";
|
|
11776
12101
|
var DiscoveryCandidateStatusSchema, SourceTypeGuessSchema, DiscoveryCandidateSchema, DiscoverySummarySchema;
|
|
11777
12102
|
var init_schema19 = __esm({
|
|
11778
12103
|
"src/discover/schema.ts"() {
|
|
11779
12104
|
"use strict";
|
|
11780
|
-
DiscoveryCandidateStatusSchema =
|
|
12105
|
+
DiscoveryCandidateStatusSchema = z22.enum([
|
|
11781
12106
|
"candidate",
|
|
11782
12107
|
"approved",
|
|
11783
12108
|
"rejected"
|
|
11784
12109
|
]);
|
|
11785
|
-
SourceTypeGuessSchema =
|
|
12110
|
+
SourceTypeGuessSchema = z22.enum([
|
|
11786
12111
|
"primary",
|
|
11787
12112
|
"docs",
|
|
11788
12113
|
"paper",
|
|
@@ -11792,36 +12117,36 @@ var init_schema19 = __esm({
|
|
|
11792
12117
|
"benchmark",
|
|
11793
12118
|
"unknown"
|
|
11794
12119
|
]);
|
|
11795
|
-
DiscoveryCandidateSchema =
|
|
11796
|
-
candidate_id:
|
|
11797
|
-
section_id:
|
|
11798
|
-
url:
|
|
11799
|
-
title:
|
|
11800
|
-
publisher:
|
|
12120
|
+
DiscoveryCandidateSchema = z22.object({
|
|
12121
|
+
candidate_id: z22.string().regex(/^disc_[a-f0-9]{12}$/),
|
|
12122
|
+
section_id: z22.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
12123
|
+
url: z22.string().url(),
|
|
12124
|
+
title: z22.string().min(1),
|
|
12125
|
+
publisher: z22.string().nullable(),
|
|
11801
12126
|
source_type_guess: SourceTypeGuessSchema,
|
|
11802
|
-
why_relevant:
|
|
12127
|
+
why_relevant: z22.string().min(1),
|
|
11803
12128
|
// The free-text query that produced this candidate (for traceability).
|
|
11804
|
-
query:
|
|
12129
|
+
query: z22.string().min(1),
|
|
11805
12130
|
// Lower rank = more central. Stable per-(query, provider) ordering.
|
|
11806
|
-
rank:
|
|
11807
|
-
discovered_at:
|
|
12131
|
+
rank: z22.number().int().positive(),
|
|
12132
|
+
discovered_at: z22.string(),
|
|
11808
12133
|
// 'candidate' | 'approved' | 'rejected'. Append-only: new entries with
|
|
11809
12134
|
// same candidate_id supersede older ones; the latest entry's status wins.
|
|
11810
12135
|
status: DiscoveryCandidateStatusSchema,
|
|
11811
|
-
discovered_by:
|
|
11812
|
-
reason:
|
|
11813
|
-
});
|
|
11814
|
-
DiscoverySummarySchema =
|
|
11815
|
-
summary_id:
|
|
11816
|
-
section_id:
|
|
11817
|
-
ran_at:
|
|
11818
|
-
research_os_version:
|
|
11819
|
-
query:
|
|
11820
|
-
provider:
|
|
11821
|
-
candidates_proposed:
|
|
11822
|
-
candidates_validated:
|
|
11823
|
-
candidates_rejected_invalid_url:
|
|
11824
|
-
warnings:
|
|
12136
|
+
discovered_by: z22.string().min(1),
|
|
12137
|
+
reason: z22.string().nullable().default(null)
|
|
12138
|
+
});
|
|
12139
|
+
DiscoverySummarySchema = z22.object({
|
|
12140
|
+
summary_id: z22.string().regex(/^disum_[0-9]+_[a-z0-9-]+$/),
|
|
12141
|
+
section_id: z22.string().regex(/^[0-9]{2}-[a-z0-9-]+$/),
|
|
12142
|
+
ran_at: z22.string(),
|
|
12143
|
+
research_os_version: z22.string(),
|
|
12144
|
+
query: z22.string().min(1),
|
|
12145
|
+
provider: z22.string().min(1),
|
|
12146
|
+
candidates_proposed: z22.number().int().nonnegative(),
|
|
12147
|
+
candidates_validated: z22.number().int().nonnegative(),
|
|
12148
|
+
candidates_rejected_invalid_url: z22.number().int().nonnegative(),
|
|
12149
|
+
warnings: z22.array(z22.string())
|
|
11825
12150
|
});
|
|
11826
12151
|
}
|
|
11827
12152
|
});
|
|
@@ -11973,10 +12298,10 @@ Propose source-URL candidates for this section. Quality over quantity.`;
|
|
|
11973
12298
|
});
|
|
11974
12299
|
|
|
11975
12300
|
// src/discover/run.ts
|
|
11976
|
-
import { existsSync as
|
|
12301
|
+
import { existsSync as existsSync28 } from "fs";
|
|
11977
12302
|
import { createHash as createHash10 } from "crypto";
|
|
11978
|
-
import { mkdir as
|
|
11979
|
-
import { join as
|
|
12303
|
+
import { mkdir as mkdir22, readFile as readFile24, writeFile as writeFile22, appendFile as appendFile8 } from "fs/promises";
|
|
12304
|
+
import { join as join28, resolve as resolve23 } from "path";
|
|
11980
12305
|
import { parse as yamlParse12 } from "yaml";
|
|
11981
12306
|
function makeCandidateId(sectionId, url) {
|
|
11982
12307
|
const hex = createHash10("sha256").update(`${sectionId}|${url}`).digest("hex").slice(0, 12);
|
|
@@ -11991,21 +12316,21 @@ function isHttpsUrl(s) {
|
|
|
11991
12316
|
}
|
|
11992
12317
|
}
|
|
11993
12318
|
function candidatesPath(packPath, sectionId) {
|
|
11994
|
-
return
|
|
12319
|
+
return join28(packPath, "sections", sectionId, "discovery-candidates.jsonl");
|
|
11995
12320
|
}
|
|
11996
12321
|
function reportPath(packPath, sectionId) {
|
|
11997
|
-
return
|
|
12322
|
+
return join28(packPath, "sections", sectionId, "discovery-report.md");
|
|
11998
12323
|
}
|
|
11999
12324
|
function summaryPath(packPath, sectionId) {
|
|
12000
|
-
return
|
|
12325
|
+
return join28(packPath, "audits", `${sectionId}-discovery.json`);
|
|
12001
12326
|
}
|
|
12002
12327
|
function approvedUrlsPath(packPath, sectionId) {
|
|
12003
|
-
return
|
|
12328
|
+
return join28(packPath, "sections", sectionId, "urls.approved.txt");
|
|
12004
12329
|
}
|
|
12005
12330
|
async function readCandidates(packPath, sectionId) {
|
|
12006
12331
|
const path = candidatesPath(packPath, sectionId);
|
|
12007
|
-
if (!
|
|
12008
|
-
const text = await
|
|
12332
|
+
if (!existsSync28(path)) return [];
|
|
12333
|
+
const text = await readFile24(path, "utf8");
|
|
12009
12334
|
const out = [];
|
|
12010
12335
|
for (const line of text.split(/\r?\n/)) {
|
|
12011
12336
|
if (!line.trim()) continue;
|
|
@@ -12035,7 +12360,7 @@ async function pickProvider(providers) {
|
|
|
12035
12360
|
}
|
|
12036
12361
|
async function loadSectionPurpose(packPath, sectionId) {
|
|
12037
12362
|
const research = ResearchYamlSchema.parse(
|
|
12038
|
-
yamlParse12(await
|
|
12363
|
+
yamlParse12(await readFile24(join28(packPath, "research.yaml"), "utf8"))
|
|
12039
12364
|
);
|
|
12040
12365
|
const section = research.sections.find((s) => s.id === sectionId);
|
|
12041
12366
|
return section?.purpose ?? "";
|
|
@@ -12073,8 +12398,8 @@ function buildReportMarkdown(args) {
|
|
|
12073
12398
|
}
|
|
12074
12399
|
async function discover(options) {
|
|
12075
12400
|
const packPath = options.packPath ? resolve23(options.packPath) : process.cwd();
|
|
12076
|
-
if (!
|
|
12077
|
-
if (!
|
|
12401
|
+
if (!existsSync28(join28(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
12402
|
+
if (!existsSync28(join28(packPath, "sections", options.sectionId)))
|
|
12078
12403
|
throw new SectionNotFoundError(options.sectionId);
|
|
12079
12404
|
const query2 = options.query.trim();
|
|
12080
12405
|
if (query2.length < 4) throw new Error("discover query must be at least 4 characters");
|
|
@@ -12134,9 +12459,9 @@ async function discover(options) {
|
|
|
12134
12459
|
newCandidates.push(candidate);
|
|
12135
12460
|
}
|
|
12136
12461
|
const ledgerPath = candidatesPath(packPath, options.sectionId);
|
|
12137
|
-
await
|
|
12462
|
+
await mkdir22(join28(packPath, "sections", options.sectionId), { recursive: true });
|
|
12138
12463
|
for (const c of newCandidates) {
|
|
12139
|
-
await
|
|
12464
|
+
await appendFile8(ledgerPath, JSON.stringify(c) + "\n", "utf8");
|
|
12140
12465
|
}
|
|
12141
12466
|
const all = await readCandidates(packPath, options.sectionId);
|
|
12142
12467
|
const latest = Array.from(latestPerCandidate(all).values());
|
|
@@ -12160,7 +12485,7 @@ async function discover(options) {
|
|
|
12160
12485
|
candidates_rejected_invalid_url: invalidCount,
|
|
12161
12486
|
warnings
|
|
12162
12487
|
});
|
|
12163
|
-
await
|
|
12488
|
+
await mkdir22(join28(packPath, "audits"), { recursive: true });
|
|
12164
12489
|
await writeFile22(summaryPath(packPath, options.sectionId), JSON.stringify(summary, null, 2), "utf8");
|
|
12165
12490
|
return {
|
|
12166
12491
|
candidatesAdded: newCandidates.length,
|
|
@@ -12180,13 +12505,13 @@ async function appendStatusUpdate(packPath, sectionId, candidate, newStatus, rea
|
|
|
12180
12505
|
reason,
|
|
12181
12506
|
discovered_at: stampIso
|
|
12182
12507
|
});
|
|
12183
|
-
await
|
|
12508
|
+
await appendFile8(candidatesPath(packPath, sectionId), JSON.stringify(updated) + "\n", "utf8");
|
|
12184
12509
|
return updated;
|
|
12185
12510
|
}
|
|
12186
12511
|
async function approve(options) {
|
|
12187
12512
|
const packPath = options.packPath ? resolve23(options.packPath) : process.cwd();
|
|
12188
|
-
if (!
|
|
12189
|
-
if (!
|
|
12513
|
+
if (!existsSync28(join28(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
12514
|
+
if (!existsSync28(join28(packPath, "sections", options.sectionId)))
|
|
12190
12515
|
throw new SectionNotFoundError(options.sectionId);
|
|
12191
12516
|
const all = await readCandidates(packPath, options.sectionId);
|
|
12192
12517
|
const latest = latestPerCandidate(all);
|
|
@@ -12219,8 +12544,8 @@ async function approve(options) {
|
|
|
12219
12544
|
}
|
|
12220
12545
|
async function reject(options) {
|
|
12221
12546
|
const packPath = options.packPath ? resolve23(options.packPath) : process.cwd();
|
|
12222
|
-
if (!
|
|
12223
|
-
if (!
|
|
12547
|
+
if (!existsSync28(join28(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
12548
|
+
if (!existsSync28(join28(packPath, "sections", options.sectionId)))
|
|
12224
12549
|
throw new SectionNotFoundError(options.sectionId);
|
|
12225
12550
|
if (options.reason.trim().length < 4) {
|
|
12226
12551
|
throw new Error("reject requires --reason of at least 4 characters");
|
|
@@ -12248,15 +12573,15 @@ async function reject(options) {
|
|
|
12248
12573
|
}
|
|
12249
12574
|
async function exportUrls(options) {
|
|
12250
12575
|
const packPath = options.packPath ? resolve23(options.packPath) : process.cwd();
|
|
12251
|
-
if (!
|
|
12252
|
-
if (!
|
|
12576
|
+
if (!existsSync28(join28(packPath, "research.yaml"))) throw new PackNotFoundError(packPath);
|
|
12577
|
+
if (!existsSync28(join28(packPath, "sections", options.sectionId)))
|
|
12253
12578
|
throw new SectionNotFoundError(options.sectionId);
|
|
12254
12579
|
const all = await readCandidates(packPath, options.sectionId);
|
|
12255
12580
|
const latest = latestPerCandidate(all);
|
|
12256
12581
|
const approved = Array.from(latest.values()).filter((c) => c.status === "approved").sort((a, b) => a.rank - b.rank);
|
|
12257
12582
|
const lines = approved.map((c) => c.url).join("\n");
|
|
12258
12583
|
const path = approvedUrlsPath(packPath, options.sectionId);
|
|
12259
|
-
await
|
|
12584
|
+
await mkdir22(join28(packPath, "sections", options.sectionId), { recursive: true });
|
|
12260
12585
|
await writeFile22(path, lines + (lines.length > 0 ? "\n" : ""), "utf8");
|
|
12261
12586
|
return { exportPath: path, approvedCount: approved.length };
|
|
12262
12587
|
}
|
|
@@ -12304,7 +12629,7 @@ var init_src = __esm({
|
|
|
12304
12629
|
init_triage();
|
|
12305
12630
|
init_discover();
|
|
12306
12631
|
init_errors();
|
|
12307
|
-
RESEARCH_OS_VERSION = "0.
|
|
12632
|
+
RESEARCH_OS_VERSION = "0.5.0";
|
|
12308
12633
|
}
|
|
12309
12634
|
});
|
|
12310
12635
|
init_src();
|
|
@@ -12411,6 +12736,7 @@ export {
|
|
|
12411
12736
|
SectionStatusChangeSchema,
|
|
12412
12737
|
SeveritySchema,
|
|
12413
12738
|
SharedSourceSchema,
|
|
12739
|
+
SourceCardOverrideSchema,
|
|
12414
12740
|
SourceCardSchema,
|
|
12415
12741
|
SourceDiversityGapRowSchema,
|
|
12416
12742
|
SourceTypeGuessSchema,
|
|
@@ -12430,6 +12756,7 @@ export {
|
|
|
12430
12756
|
add,
|
|
12431
12757
|
aggregate,
|
|
12432
12758
|
appendFetchLog,
|
|
12759
|
+
appendOverride,
|
|
12433
12760
|
appendSectionSourceId,
|
|
12434
12761
|
applySchema,
|
|
12435
12762
|
applyWaivers,
|
|
@@ -12470,6 +12797,8 @@ export {
|
|
|
12470
12797
|
freeze,
|
|
12471
12798
|
gate,
|
|
12472
12799
|
gather,
|
|
12800
|
+
getEffectivePublisher,
|
|
12801
|
+
getEffectiveSourceType,
|
|
12473
12802
|
handoff,
|
|
12474
12803
|
hasNegation,
|
|
12475
12804
|
indexDbPath,
|
|
@@ -12494,6 +12823,7 @@ export {
|
|
|
12494
12823
|
promote,
|
|
12495
12824
|
query,
|
|
12496
12825
|
readActiveProfile,
|
|
12826
|
+
readOverrides,
|
|
12497
12827
|
readTriagedClaimIds,
|
|
12498
12828
|
readUrlsFile,
|
|
12499
12829
|
reject,
|
|
@@ -12524,6 +12854,7 @@ export {
|
|
|
12524
12854
|
syncRepoKnowledge,
|
|
12525
12855
|
tokenize,
|
|
12526
12856
|
triage,
|
|
12857
|
+
validateSourceCardOverride,
|
|
12527
12858
|
workspace,
|
|
12528
12859
|
writeActiveProfile,
|
|
12529
12860
|
writeSourceCard
|