@agwab/pi-workflow 0.3.0 → 0.4.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/README.md +3 -1
- package/dist/artifact-graph-runtime.d.ts +1 -1
- package/dist/artifact-graph-runtime.js +10 -5
- package/dist/artifact-graph-schema.js +127 -5
- package/dist/compiler.js +46 -11
- package/dist/dynamic-decision.d.ts +1 -0
- package/dist/dynamic-decision.js +7 -0
- package/dist/dynamic-generated-task-runtime.js +3 -1
- package/dist/dynamic-profiles.d.ts +1 -0
- package/dist/dynamic-profiles.js +3 -0
- package/dist/engine-run-graph.d.ts +2 -0
- package/dist/engine-run-graph.js +55 -5
- package/dist/engine.js +278 -15
- package/dist/extension.js +3 -2
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4 -0
- package/dist/prompt-json.d.ts +7 -0
- package/dist/prompt-json.js +13 -0
- package/dist/roles.d.ts +1 -1
- package/dist/roles.js +5 -8
- package/dist/store.d.ts +20 -1
- package/dist/store.js +89 -29
- package/dist/strings.d.ts +11 -0
- package/dist/strings.js +24 -0
- package/dist/subagent-backend.js +557 -13
- package/dist/types.d.ts +101 -1
- package/dist/verification-ontology.d.ts +31 -0
- package/dist/verification-ontology.js +66 -0
- package/dist/workflow-artifact-tool.js +5 -6
- package/dist/workflow-artifacts.d.ts +7 -0
- package/dist/workflow-artifacts.js +55 -4
- package/dist/workflow-fetch-cache-extension.d.ts +1 -0
- package/dist/workflow-fetch-cache-extension.js +57 -9
- package/dist/workflow-metrics.d.ts +113 -0
- package/dist/workflow-metrics.js +272 -0
- package/dist/workflow-output-artifacts.js +5 -3
- package/dist/workflow-partial-output.d.ts +45 -0
- package/dist/workflow-partial-output.js +205 -0
- package/dist/workflow-progress-health.js +42 -10
- package/dist/workflow-web-source-extension.js +27 -4
- package/dist/workflow-web-source.js +26 -12
- package/docs/usage.md +76 -29
- package/node_modules/@agwab/pi-subagent/package.json +1 -1
- package/node_modules/@agwab/pi-subagent/src/index.ts +53 -5
- package/node_modules/@agwab/pi-subagent/src/panel.ts +7 -3
- package/package.json +2 -2
- package/skills/workflow-guide/SKILL.md +1 -0
- package/src/artifact-graph-runtime.ts +19 -13
- package/src/artifact-graph-schema.ts +143 -3
- package/src/cli.mjs +52 -0
- package/src/compiler.ts +49 -9
- package/src/dynamic-decision.ts +11 -0
- package/src/dynamic-generated-task-runtime.ts +3 -1
- package/src/dynamic-profiles.ts +4 -0
- package/src/engine-run-graph.ts +63 -4
- package/src/engine.ts +400 -14
- package/src/extension.ts +3 -2
- package/src/index.ts +49 -0
- package/src/prompt-json.ts +13 -0
- package/src/roles.ts +6 -9
- package/src/store.ts +123 -34
- package/src/strings.ts +38 -0
- package/src/subagent-backend.ts +727 -41
- package/src/types.ts +110 -2
- package/src/verification-ontology.ts +88 -0
- package/src/workflow-artifact-tool.ts +5 -7
- package/src/workflow-artifacts.ts +83 -3
- package/src/workflow-fetch-cache-extension.ts +78 -13
- package/src/workflow-metrics.ts +478 -0
- package/src/workflow-output-artifacts.ts +5 -3
- package/src/workflow-partial-output.ts +299 -0
- package/src/workflow-progress-health.ts +47 -15
- package/src/workflow-web-source-extension.ts +33 -4
- package/src/workflow-web-source.ts +36 -12
- package/workflows/README.md +7 -25
- package/workflows/deep-research/batched-verification.spec.json +253 -0
- package/workflows/deep-research/helpers/batch-verification-candidates.mjs +136 -0
- package/workflows/deep-research/helpers/claim-evidence-gate.mjs +173 -20
- package/workflows/deep-research/helpers/normalize-input-packet.mjs +80 -1
- package/workflows/deep-research/helpers/render-executive.mjs +32 -5
- package/workflows/deep-research/helpers/shadow-select-verification.mjs +229 -0
- package/workflows/deep-research/helpers/verification-ontology.mjs +77 -0
- package/workflows/deep-research/schemas/deep-research-executive-render-control.schema.json +3 -2
- package/workflows/deep-research/schemas/deep-research-research-questions-control.schema.json +38 -0
- package/workflows/deep-research/schemas/deep-research-sanitize-claims-control.schema.json +63 -0
- package/workflows/deep-research/schemas/deep-research-verify-claims-batch-control.schema.json +47 -0
- package/workflows/deep-research/schemas/deep-research-verify-claims-control.schema.json +10 -3
- package/workflows/deep-research/spec.json +32 -12
- package/skills/workflow-guide/scaffolds/dag-required-reads/spec.json.validate.stderr +0 -0
- package/skills/workflow-guide/scaffolds/dag-required-reads/spec.json.validate.stdout +0 -13
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERIFICATION_STATUS,
|
|
3
|
+
VERIFICATION_STATUS_BUCKETS,
|
|
4
|
+
canonicalVerificationStatus,
|
|
5
|
+
} from "./verification-ontology.mjs";
|
|
6
|
+
|
|
1
7
|
// Deterministic claim audit for deep-research.
|
|
2
8
|
//
|
|
3
9
|
// Sources: plan (optional), normalize-claims (optional), verify-claims foreach
|
|
@@ -16,10 +22,6 @@ function asArray(value) {
|
|
|
16
22
|
if (Array.isArray(value)) return value;
|
|
17
23
|
if (value && typeof value === "object") {
|
|
18
24
|
if (Array.isArray(value.auditedClaims)) return value.auditedClaims;
|
|
19
|
-
if (Array.isArray(value.claims)) return value.claims;
|
|
20
|
-
if (Array.isArray(value.claimVerdicts)) return value.claimVerdicts;
|
|
21
|
-
if (Array.isArray(value.verdicts)) return value.verdicts;
|
|
22
|
-
if (Array.isArray(value.items)) return value.items;
|
|
23
25
|
if (
|
|
24
26
|
"status" in value ||
|
|
25
27
|
"verdict" in value ||
|
|
@@ -28,6 +30,11 @@ function asArray(value) {
|
|
|
28
30
|
"id" in value
|
|
29
31
|
)
|
|
30
32
|
return [value];
|
|
33
|
+
if (Array.isArray(value.results)) return value.results;
|
|
34
|
+
if (Array.isArray(value.claims)) return value.claims;
|
|
35
|
+
if (Array.isArray(value.claimVerdicts)) return value.claimVerdicts;
|
|
36
|
+
if (Array.isArray(value.verdicts)) return value.verdicts;
|
|
37
|
+
if (Array.isArray(value.items)) return value.items;
|
|
31
38
|
return Object.values(value).flatMap(asArray);
|
|
32
39
|
}
|
|
33
40
|
return [];
|
|
@@ -345,40 +352,133 @@ function compactStrings(values) {
|
|
|
345
352
|
}
|
|
346
353
|
|
|
347
354
|
function canonicalVerifierStatus(status) {
|
|
348
|
-
return status
|
|
355
|
+
return canonicalVerificationStatus(status);
|
|
349
356
|
}
|
|
350
357
|
|
|
351
358
|
function conservativeVerifierStatus(statuses) {
|
|
352
359
|
const normalized = statuses.map(canonicalVerifierStatus);
|
|
353
360
|
for (const status of [
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
361
|
+
VERIFICATION_STATUS.CONFLICTING,
|
|
362
|
+
VERIFICATION_STATUS.UNSUPPORTED,
|
|
363
|
+
VERIFICATION_STATUS.VERIFICATION_BLOCKED,
|
|
364
|
+
VERIFICATION_STATUS.PARTIALLY_SUPPORTED,
|
|
365
|
+
VERIFICATION_STATUS.UNVERIFIED,
|
|
358
366
|
]) {
|
|
359
367
|
if (normalized.includes(status)) return status;
|
|
360
368
|
}
|
|
361
|
-
if (normalized.every((status) => status ===
|
|
369
|
+
if (normalized.every((status) => status === VERIFICATION_STATUS.VERIFIED))
|
|
370
|
+
return VERIFICATION_STATUS.VERIFIED;
|
|
362
371
|
return (
|
|
363
372
|
normalized.find((status) => typeof status === "string" && status) ??
|
|
364
|
-
|
|
373
|
+
VERIFICATION_STATUS.UNVERIFIED
|
|
365
374
|
);
|
|
366
375
|
}
|
|
367
376
|
|
|
368
|
-
function issueForVerifierRow({
|
|
377
|
+
function issueForVerifierRow({
|
|
378
|
+
sourceId,
|
|
379
|
+
claim,
|
|
380
|
+
reason,
|
|
381
|
+
claimId,
|
|
382
|
+
index,
|
|
383
|
+
...details
|
|
384
|
+
}) {
|
|
369
385
|
return {
|
|
370
386
|
sourceId,
|
|
371
387
|
...(Number.isInteger(index) ? { index } : {}),
|
|
372
388
|
...(claimId ? { claimId } : {}),
|
|
389
|
+
...details,
|
|
373
390
|
reason,
|
|
374
391
|
status: verdictOf(claim),
|
|
375
392
|
nextStep:
|
|
376
393
|
reason === "unknown_claim_id"
|
|
377
394
|
? "Verify-claims output did not match any normalized verification candidate; quarantine it from claim counts."
|
|
378
|
-
:
|
|
395
|
+
: reason === "batch_result_id_not_in_source_batch"
|
|
396
|
+
? "Verifier batch output included a claim id outside the source batch; rerun or repair the batch before counting any row."
|
|
397
|
+
: reason === "unknown_verification_batch_id"
|
|
398
|
+
? "Verifier batch output came from an unknown batch id; rerun or repair the batch before counting any row."
|
|
399
|
+
: "Verifier output is missing a usable string id/claimId; rerun or repair the verifier row before counting it.",
|
|
379
400
|
};
|
|
380
401
|
}
|
|
381
402
|
|
|
403
|
+
function asBatchArray(value) {
|
|
404
|
+
if (Array.isArray(value?.batches)) return value.batches;
|
|
405
|
+
if (Array.isArray(value)) return value;
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function buildBatchMembershipById(verificationBatches) {
|
|
410
|
+
const batches = new Map();
|
|
411
|
+
for (const batch of asBatchArray(verificationBatches)) {
|
|
412
|
+
const id = typeof batch?.id === "string" ? batch.id.trim() : "";
|
|
413
|
+
if (!id) continue;
|
|
414
|
+
const claimIds = Array.isArray(batch.claimIds)
|
|
415
|
+
? batch.claimIds
|
|
416
|
+
: Array.isArray(batch.claims)
|
|
417
|
+
? batch.claims.map(
|
|
418
|
+
(claim, index) =>
|
|
419
|
+
claimIdOf(claim).id ??
|
|
420
|
+
`candidate-${String(index + 1).padStart(3, "0")}`,
|
|
421
|
+
)
|
|
422
|
+
: [];
|
|
423
|
+
batches.set(
|
|
424
|
+
id,
|
|
425
|
+
new Set(
|
|
426
|
+
claimIds
|
|
427
|
+
.filter((claimId) => typeof claimId === "string")
|
|
428
|
+
.map((claimId) => claimId.trim())
|
|
429
|
+
.filter(Boolean),
|
|
430
|
+
),
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
return batches;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function verifierBatchId(sourceId) {
|
|
437
|
+
const prefix = "verify-claims.";
|
|
438
|
+
if (typeof sourceId !== "string" || !sourceId.startsWith(prefix)) return null;
|
|
439
|
+
const id = sourceId.slice(prefix.length).trim();
|
|
440
|
+
return id || null;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function buildBatchIdBySourceName(sourceStatuses) {
|
|
444
|
+
const bySource = new Map();
|
|
445
|
+
for (const status of Array.isArray(sourceStatuses) ? sourceStatuses : []) {
|
|
446
|
+
const source = typeof status?.source === "string" ? status.source : "";
|
|
447
|
+
const batchId = verifierBatchId(status?.specId);
|
|
448
|
+
if (source && batchId) bySource.set(source, batchId);
|
|
449
|
+
}
|
|
450
|
+
return bySource;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function batchMembershipIssue({
|
|
454
|
+
sourceId,
|
|
455
|
+
claimId,
|
|
456
|
+
batchMembershipById,
|
|
457
|
+
batchIdBySourceName,
|
|
458
|
+
}) {
|
|
459
|
+
if (!(batchMembershipById instanceof Map) || batchMembershipById.size === 0)
|
|
460
|
+
return null;
|
|
461
|
+
const batchId =
|
|
462
|
+
verifierBatchId(sourceId) ?? batchIdBySourceName?.get(sourceId);
|
|
463
|
+
if (!batchId) return null;
|
|
464
|
+
const expectedClaimIds = batchMembershipById.get(batchId);
|
|
465
|
+
if (!expectedClaimIds) {
|
|
466
|
+
return {
|
|
467
|
+
reason: "unknown_verification_batch_id",
|
|
468
|
+
batchId,
|
|
469
|
+
expectedBatchIds: [...batchMembershipById.keys()],
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
if (!expectedClaimIds.has(claimId)) {
|
|
473
|
+
return {
|
|
474
|
+
reason: "batch_result_id_not_in_source_batch",
|
|
475
|
+
batchId,
|
|
476
|
+
expectedClaimIds: [...expectedClaimIds],
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
|
|
382
482
|
function gapForVerifierIssue(issue) {
|
|
383
483
|
return {
|
|
384
484
|
...(issue.claimId ? { claimId: issue.claimId } : {}),
|
|
@@ -437,12 +537,33 @@ function mergeVerifierRows(rows) {
|
|
|
437
537
|
};
|
|
438
538
|
}
|
|
439
539
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
540
|
+
function buildBatchAdoptionReadiness({ gateSummary, candidateCount }) {
|
|
541
|
+
const checks = [
|
|
542
|
+
["invalid_verifier_rows", gateSummary.invalidVerifierRows],
|
|
543
|
+
["missing_verifier_results", gateSummary.missingVerifierResults],
|
|
544
|
+
["duplicate_verifier_rows", gateSummary.duplicateVerifierRows],
|
|
545
|
+
["duplicate_status_conflicts", gateSummary.duplicateStatusConflicts],
|
|
546
|
+
["invalid_normalized_candidates", gateSummary.invalidNormalizedCandidates],
|
|
547
|
+
["source_ref_join_failures", gateSummary.sourceRefJoinFailures],
|
|
548
|
+
];
|
|
549
|
+
const blockers = checks
|
|
550
|
+
.filter(([, count]) => Number(count ?? 0) > 0)
|
|
551
|
+
.map(([reason, count]) => ({ reason, count }));
|
|
552
|
+
if (candidateCount === 0)
|
|
553
|
+
blockers.push({ reason: "no_verification_candidates", count: 0 });
|
|
554
|
+
return {
|
|
555
|
+
status: blockers.length === 0 ? "eligible_for_canary" : "blocked",
|
|
556
|
+
adopted: false,
|
|
557
|
+
canaryRequired: true,
|
|
558
|
+
reason:
|
|
559
|
+
blockers.length === 0
|
|
560
|
+
? "Verifier identity/sourceRef integrity is clean; batch adoption still requires a non-holdout canary before use."
|
|
561
|
+
: "Batch adoption is blocked until verifier identity/sourceRef integrity issues are resolved.",
|
|
562
|
+
blockers,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const STATUS_BUCKETS = VERIFICATION_STATUS_BUCKETS;
|
|
446
567
|
|
|
447
568
|
function findSource(sources, stageId) {
|
|
448
569
|
for (const [specId, source] of Object.entries(sources ?? {})) {
|
|
@@ -451,11 +572,18 @@ function findSource(sources, stageId) {
|
|
|
451
572
|
return null;
|
|
452
573
|
}
|
|
453
574
|
|
|
454
|
-
export default async function claimEvidenceGate({
|
|
575
|
+
export default async function claimEvidenceGate({
|
|
576
|
+
sources,
|
|
577
|
+
options = {},
|
|
578
|
+
context = {},
|
|
579
|
+
}) {
|
|
455
580
|
const plan = findSource(sources, "plan");
|
|
456
581
|
const normalizeClaims = findSource(sources, "normalize-claims");
|
|
457
582
|
const sanitizedCandidates = findSource(sources, "sanitize-claims");
|
|
458
583
|
const normalized = sanitizedCandidates ?? normalizeClaims;
|
|
584
|
+
const verificationBatches = findSource(sources, "verification-batches");
|
|
585
|
+
const batchMembershipById = buildBatchMembershipById(verificationBatches);
|
|
586
|
+
const batchIdBySourceName = buildBatchIdBySourceName(context.sourceStatuses);
|
|
459
587
|
const normalizeInputPacket = findSource(sources, "normalize-input-packet");
|
|
460
588
|
const urlToSourceRef = buildUrlSourceRefLookup(normalizeInputPacket);
|
|
461
589
|
const candidateRecords = [];
|
|
@@ -568,6 +696,25 @@ export default async function claimEvidenceGate({ sources, options = {} }) {
|
|
|
568
696
|
gateSummary.invalidVerifierRows += 1;
|
|
569
697
|
continue;
|
|
570
698
|
}
|
|
699
|
+
const batchIssue = batchMembershipIssue({
|
|
700
|
+
sourceId,
|
|
701
|
+
claimId: idCheck.id,
|
|
702
|
+
batchMembershipById,
|
|
703
|
+
batchIdBySourceName,
|
|
704
|
+
});
|
|
705
|
+
if (batchIssue) {
|
|
706
|
+
const issue = issueForVerifierRow({
|
|
707
|
+
sourceId,
|
|
708
|
+
claim,
|
|
709
|
+
index,
|
|
710
|
+
claimId: idCheck.id,
|
|
711
|
+
...batchIssue,
|
|
712
|
+
});
|
|
713
|
+
invalidVerifierRows.push(issue);
|
|
714
|
+
remainingGaps.push(gapForVerifierIssue(issue));
|
|
715
|
+
gateSummary.invalidVerifierRows += 1;
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
571
718
|
const row = {
|
|
572
719
|
sourceId,
|
|
573
720
|
claimId: idCheck.id,
|
|
@@ -806,6 +953,7 @@ export default async function claimEvidenceGate({ sources, options = {} }) {
|
|
|
806
953
|
partiallySupported: [],
|
|
807
954
|
unsupported: [],
|
|
808
955
|
conflicting: [],
|
|
956
|
+
verificationBlocked: [],
|
|
809
957
|
other: [],
|
|
810
958
|
};
|
|
811
959
|
for (const claim of auditedClaims) {
|
|
@@ -859,11 +1007,16 @@ export default async function claimEvidenceGate({ sources, options = {} }) {
|
|
|
859
1007
|
verdictDigest: claim.verdictDigest,
|
|
860
1008
|
correctionOrCounterclaim: claim.correctionOrCounterclaim,
|
|
861
1009
|
}));
|
|
1010
|
+
const batchAdoptionReadiness = buildBatchAdoptionReadiness({
|
|
1011
|
+
gateSummary,
|
|
1012
|
+
candidateCount: candidateRecords.length,
|
|
1013
|
+
});
|
|
862
1014
|
|
|
863
1015
|
return {
|
|
864
1016
|
auditedClaims,
|
|
865
1017
|
claimDigests,
|
|
866
1018
|
gateSummary,
|
|
1019
|
+
batchAdoptionReadiness,
|
|
867
1020
|
remainingGaps,
|
|
868
1021
|
sourceRefJoinFailures,
|
|
869
1022
|
invalidVerifierRows,
|
|
@@ -157,6 +157,60 @@ function compactGap(gap, sourceId, index) {
|
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
function compactBudgetLedger(source, sourceId) {
|
|
161
|
+
const ledger = asObject(source.budgetLedger);
|
|
162
|
+
if (Object.keys(ledger).length === 0) return undefined;
|
|
163
|
+
const searchBudget = Number(ledger.searchBudget);
|
|
164
|
+
const searchCallsUsed = Number(ledger.searchCallsUsed);
|
|
165
|
+
return {
|
|
166
|
+
sourceId,
|
|
167
|
+
question: stringOf(source.question)?.slice(0, 300),
|
|
168
|
+
...(Number.isFinite(searchBudget) ? { searchBudget } : {}),
|
|
169
|
+
...(Number.isFinite(searchCallsUsed) ? { searchCallsUsed } : {}),
|
|
170
|
+
searchQueriesAttempted: compactStrings(ledger.searchQueriesAttempted, 12),
|
|
171
|
+
omittedSearchQueries: compactStrings(ledger.omittedSearchQueries, 12),
|
|
172
|
+
budgetExhausted: ledger.budgetExhausted === true,
|
|
173
|
+
gapRecorded: ledger.gapRecorded === true,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function sourceStatusesOf(context) {
|
|
178
|
+
return asArray(context?.sourceStatuses).map(asObject);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function isResearchQuestionStatus(status) {
|
|
182
|
+
return [status.source, status.specId, status.displayName, status.stageId]
|
|
183
|
+
.map((value) => String(value ?? ""))
|
|
184
|
+
.some(
|
|
185
|
+
(value) =>
|
|
186
|
+
value === "research-questions" ||
|
|
187
|
+
value.startsWith("research-questions."),
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function compactSourceStatusGap(status, index) {
|
|
192
|
+
const sourceId =
|
|
193
|
+
stringOf(status.specId) ??
|
|
194
|
+
stringOf(status.source) ??
|
|
195
|
+
stringOf(status.displayName) ??
|
|
196
|
+
`research-questions.status-${String(index + 1).padStart(3, "0")}`;
|
|
197
|
+
const detail = compactStrings(
|
|
198
|
+
[status.statusDetail, status.errorType, status.lastMessage],
|
|
199
|
+
3,
|
|
200
|
+
).join("; ");
|
|
201
|
+
return {
|
|
202
|
+
originLocator: `${sourceId}.status-gap`,
|
|
203
|
+
sourceId,
|
|
204
|
+
lead: `Research question source ${sourceId} ended with status ${String(status.status ?? "unknown")}${detail ? ` (${detail.slice(0, 300)})` : ""}.`,
|
|
205
|
+
sourceUrls: [],
|
|
206
|
+
sourceRefs: [],
|
|
207
|
+
factSlotIds: [],
|
|
208
|
+
reason: "research_question_non_completed",
|
|
209
|
+
status: String(status.status ?? "unknown"),
|
|
210
|
+
...(stringOf(status.taskId) ? { taskId: stringOf(status.taskId) } : {}),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
160
214
|
function pushBounded(target, overflow, items, limit, overflowKind) {
|
|
161
215
|
for (const item of items) {
|
|
162
216
|
if (target.length < limit) target.push(item);
|
|
@@ -428,19 +482,21 @@ function buildPrecisionGuard({ claims, planSlots }) {
|
|
|
428
482
|
};
|
|
429
483
|
}
|
|
430
484
|
|
|
431
|
-
export default async function normalizeInputPacket({ sources }) {
|
|
485
|
+
export default async function normalizeInputPacket({ sources, context } = {}) {
|
|
432
486
|
const plan = asObject(findSource(sources, "plan"));
|
|
433
487
|
const research = researchSources(sources);
|
|
434
488
|
const extractedFacts = [];
|
|
435
489
|
const claims = [];
|
|
436
490
|
const sourceCards = [];
|
|
437
491
|
const evidenceGaps = [];
|
|
492
|
+
const questionBudgetLedger = [];
|
|
438
493
|
const overflow = {};
|
|
439
494
|
const limits = {
|
|
440
495
|
extractedFacts: 240,
|
|
441
496
|
claims: 240,
|
|
442
497
|
sources: 160,
|
|
443
498
|
evidenceGaps: 120,
|
|
499
|
+
questionBudgetLedger: 80,
|
|
444
500
|
};
|
|
445
501
|
|
|
446
502
|
for (const { sourceId, source } of research) {
|
|
@@ -480,7 +536,29 @@ export default async function normalizeInputPacket({ sources }) {
|
|
|
480
536
|
limits.evidenceGaps,
|
|
481
537
|
"omittedEvidenceGaps",
|
|
482
538
|
);
|
|
539
|
+
const budgetLedger = compactBudgetLedger(source, sourceId);
|
|
540
|
+
if (budgetLedger) {
|
|
541
|
+
pushBounded(
|
|
542
|
+
questionBudgetLedger,
|
|
543
|
+
overflow,
|
|
544
|
+
[budgetLedger],
|
|
545
|
+
limits.questionBudgetLedger,
|
|
546
|
+
"omittedQuestionBudgetLedgers",
|
|
547
|
+
);
|
|
548
|
+
}
|
|
483
549
|
}
|
|
550
|
+
pushBounded(
|
|
551
|
+
evidenceGaps,
|
|
552
|
+
overflow,
|
|
553
|
+
sourceStatusesOf(context)
|
|
554
|
+
.filter(
|
|
555
|
+
(status) =>
|
|
556
|
+
isResearchQuestionStatus(status) && status.status !== "completed",
|
|
557
|
+
)
|
|
558
|
+
.map(compactSourceStatusGap),
|
|
559
|
+
limits.evidenceGaps,
|
|
560
|
+
"omittedEvidenceGaps",
|
|
561
|
+
);
|
|
484
562
|
|
|
485
563
|
const planSlots = asArray(plan.factSlots).map(compactPlanSlot);
|
|
486
564
|
const precisionGuard = buildPrecisionGuard({ claims, planSlots });
|
|
@@ -506,6 +584,7 @@ export default async function normalizeInputPacket({ sources }) {
|
|
|
506
584
|
claims,
|
|
507
585
|
sources: sourceCards,
|
|
508
586
|
evidenceGaps,
|
|
587
|
+
questionBudgetLedger,
|
|
509
588
|
},
|
|
510
589
|
slotPreservation,
|
|
511
590
|
precisionGuard,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
10
10
|
import { join } from "node:path";
|
|
11
|
+
import { canonicalVerificationStatus } from "./verification-ontology.mjs";
|
|
11
12
|
|
|
12
13
|
function findSource(sources, stageId) {
|
|
13
14
|
const entries = Object.entries(sources ?? {});
|
|
@@ -298,11 +299,24 @@ function finiteNumber(value) {
|
|
|
298
299
|
function normalizeClaimStatus(status) {
|
|
299
300
|
const text = cleanText(status).toLowerCase();
|
|
300
301
|
if (!text) return "";
|
|
302
|
+
const canonical = canonicalVerificationStatus(text);
|
|
303
|
+
if (canonical !== "unverified") return canonical;
|
|
304
|
+
if (
|
|
305
|
+
text === "unverified" ||
|
|
306
|
+
text.includes("not verified") ||
|
|
307
|
+
text.includes("not_verified")
|
|
308
|
+
)
|
|
309
|
+
return "unverified";
|
|
310
|
+
if (
|
|
311
|
+
text.includes("verification_blocked") ||
|
|
312
|
+
text.includes("verification blocked")
|
|
313
|
+
)
|
|
314
|
+
return "verification_blocked";
|
|
301
315
|
if (text.includes("conflict")) return "conflicting";
|
|
302
316
|
if (text.includes("unsupported")) return "unsupported";
|
|
303
317
|
if (text.includes("partial")) return "partially_supported";
|
|
304
|
-
if (text
|
|
305
|
-
return
|
|
318
|
+
if (/\bverified\b/.test(text)) return "verified";
|
|
319
|
+
return canonical;
|
|
306
320
|
}
|
|
307
321
|
|
|
308
322
|
function coverageCounts(coverage, fallback) {
|
|
@@ -316,13 +330,18 @@ function coverageCounts(coverage, fallback) {
|
|
|
316
330
|
fallback.partially_supported,
|
|
317
331
|
unsupported: finiteNumber(coverage.unsupported) ?? fallback.unsupported,
|
|
318
332
|
conflicting: finiteNumber(coverage.conflicting) ?? fallback.conflicting,
|
|
333
|
+
verification_blocked:
|
|
334
|
+
finiteNumber(coverage.verificationBlocked) ??
|
|
335
|
+
finiteNumber(coverage.verification_blocked) ??
|
|
336
|
+
fallback.verification_blocked,
|
|
319
337
|
};
|
|
320
338
|
if (counts.total == null) {
|
|
321
339
|
counts.total =
|
|
322
340
|
counts.verified +
|
|
323
341
|
counts.partially_supported +
|
|
324
342
|
counts.unsupported +
|
|
325
|
-
counts.conflicting
|
|
343
|
+
counts.conflicting +
|
|
344
|
+
counts.verification_blocked;
|
|
326
345
|
}
|
|
327
346
|
return counts;
|
|
328
347
|
}
|
|
@@ -338,7 +357,8 @@ function packetVerdictCounts(packet, fallback) {
|
|
|
338
357
|
counts.verified +
|
|
339
358
|
counts.partially_supported +
|
|
340
359
|
counts.unsupported +
|
|
341
|
-
counts.conflicting
|
|
360
|
+
counts.conflicting +
|
|
361
|
+
counts.verification_blocked;
|
|
342
362
|
return counts;
|
|
343
363
|
}
|
|
344
364
|
|
|
@@ -350,6 +370,7 @@ function claimCounts(control, packet) {
|
|
|
350
370
|
partially_supported: 0,
|
|
351
371
|
unsupported: 0,
|
|
352
372
|
conflicting: 0,
|
|
373
|
+
verification_blocked: 0,
|
|
353
374
|
};
|
|
354
375
|
for (const claim of claims) {
|
|
355
376
|
const status = normalizeClaimStatus(claim?.status);
|
|
@@ -372,6 +393,7 @@ function claimCounts(control, packet) {
|
|
|
372
393
|
"partially_supported",
|
|
373
394
|
"unsupported",
|
|
374
395
|
"conflicting",
|
|
396
|
+
"verification_blocked",
|
|
375
397
|
]) {
|
|
376
398
|
if (coverage[key] !== counts[key]) {
|
|
377
399
|
mismatches.push({
|
|
@@ -520,6 +542,8 @@ function evidenceStrength(status) {
|
|
|
520
542
|
case "unsupported":
|
|
521
543
|
return 1;
|
|
522
544
|
case "conflicting":
|
|
545
|
+
case "verification_blocked":
|
|
546
|
+
case "unverified":
|
|
523
547
|
return 0;
|
|
524
548
|
default:
|
|
525
549
|
return -1;
|
|
@@ -587,6 +611,7 @@ function coverageSummaryFromPacket(packet, fallback = {}) {
|
|
|
587
611
|
partially_supported: 0,
|
|
588
612
|
unsupported: 0,
|
|
589
613
|
conflicting: 0,
|
|
614
|
+
verification_blocked: 0,
|
|
590
615
|
});
|
|
591
616
|
if (!counts) return fallback;
|
|
592
617
|
return {
|
|
@@ -595,6 +620,7 @@ function coverageSummaryFromPacket(packet, fallback = {}) {
|
|
|
595
620
|
partiallySupported: counts.partially_supported,
|
|
596
621
|
unsupported: counts.unsupported,
|
|
597
622
|
conflicting: counts.conflicting,
|
|
623
|
+
verificationBlocked: counts.verification_blocked,
|
|
598
624
|
verificationCandidates: counts.total,
|
|
599
625
|
depth: packet?.researchMetadataSeed?.depth ?? fallback.depth,
|
|
600
626
|
researchQuestions:
|
|
@@ -975,7 +1001,7 @@ function renderAuditSummary(report, claimSummary, slots) {
|
|
|
975
1001
|
return [
|
|
976
1002
|
"## Audit summary",
|
|
977
1003
|
"",
|
|
978
|
-
`- Claims: ${claimSummary.verified} verified, ${claimSummary.partially_supported} partially supported, ${claimSummary.unsupported} unsupported, ${claimSummary.conflicting} conflicting.`,
|
|
1004
|
+
`- Claims: ${claimSummary.verified} verified, ${claimSummary.partially_supported} partially supported, ${claimSummary.unsupported} unsupported, ${claimSummary.conflicting} conflicting, ${claimSummary.verification_blocked} verification blocked.`,
|
|
979
1005
|
`- Fact slots: ${slots.filled} filled, ${slots.partial} partial, ${slots.missingOrConflicting} missing/conflicting, ${slots.total} total.`,
|
|
980
1006
|
...(mismatches.length > 0
|
|
981
1007
|
? [
|
|
@@ -1240,6 +1266,7 @@ export default async function renderExecutive({
|
|
|
1240
1266
|
partially_supported: 0,
|
|
1241
1267
|
unsupported: 0,
|
|
1242
1268
|
conflicting: 0,
|
|
1269
|
+
verification_blocked: 0,
|
|
1243
1270
|
},
|
|
1244
1271
|
factSlotSummary: {
|
|
1245
1272
|
total: 0,
|