@gitroll/tacitt-cli 0.6.10 → 0.6.12
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 +47 -4
- package/bin/INDEX.md +6 -4
- package/bin/tacitt.cjs +1 -0
- package/dist/{agent-setup-LPd8WEsN.mjs → agent-setup-B12VbvN_.mjs} +2 -2
- package/dist/agent-setup-worker.mjs +5 -5
- package/dist/cli.mjs +39 -25
- package/dist/codex-title-worker.mjs +2 -2
- package/dist/configured-preview-worker.mjs +5 -5
- package/dist/configured-session-worker.mjs +27 -27
- package/dist/{frame-ByT1xayJ.mjs → frame-B3He21G8.mjs} +1 -1
- package/dist/{heap-CM298Yu0.mjs → heap-Blrat--4.mjs} +469 -30
- package/dist/inspection-worker.mjs +4 -4
- package/dist/{job-BHIwElNF.mjs → job-CBuIMTQ0.mjs} +57 -22
- package/dist/{locate-Cwv6WH8n.mjs → locate-D-ZaHpI0.mjs} +184 -18
- package/dist/{model-zvn5GUJ9.mjs → model-DR9odhWP.mjs} +1 -1
- package/dist/operation-executor.mjs +3 -3
- package/dist/preview-worker.mjs +1 -1
- package/dist/privacy-validator.mjs +49 -2
- package/dist/{query-By41gaKm.mjs → query-BYDcNKy2.mjs} +1869 -716
- package/dist/{run-ZQx7p4Rw.mjs → run-DQ9xyKSt.mjs} +4 -4
- package/dist/session-process.mjs +20 -0
- package/dist/{src-D_DfY--2.mjs → src-CKQlTA2Z.mjs} +297 -207
- package/dist/{src-3jvMvSQn.mjs → src-DeNJ8vOD.mjs} +535 -140
- package/dist/{src-BqtdFVq7.mjs → src-Do-qzuMn.mjs} +2329 -1786
- package/dist/store-database-worker.mjs +1 -1
- package/dist/web/assets/index-BgDdPL1c.js +172 -0
- package/dist/web/assets/index-DzOozqms.css +1 -0
- package/dist/web/index.html +3 -2
- package/package.json +2 -1
- package/skills/INDEX.md +6 -4
- package/skills/tacitt/INDEX.md +7 -6
- package/skills/tacitt/SKILL.md +11 -11
- package/skills/tacitt/references/INDEX.md +14 -11
- package/skills/tacitt/references/b-method.md +4 -4
- package/skills/tacitt/references/bootstrap.md +19 -5
- package/skills/tacitt/references/classification.md +4 -4
- package/skills/tacitt/references/commands.md +51 -34
- package/skills/tacitt/references/journey.md +7 -7
- package/skills/tacitt/references/parallel-review.md +35 -35
- package/skills/tacitt/references/send.md +15 -6
- package/skills/tacitt/scripts/INDEX.md +40 -37
- package/skills/tacitt/scripts/answer.mjs +91 -15
- package/skills/tacitt/scripts/journey-card-consolidation.mjs +1 -1
- package/skills/tacitt/scripts/journey-classification-metadata.mjs +75 -26
- package/skills/tacitt/scripts/journey-classification-progress.mjs +1 -2
- package/skills/tacitt/scripts/journey-classification-tasks.mjs +28 -8
- package/skills/tacitt/scripts/journey-classification.mjs +6 -1
- package/skills/tacitt/scripts/journey-consolidation.mjs +1 -0
- package/skills/tacitt/scripts/journey-panel-host.d.mts +2 -0
- package/skills/tacitt/scripts/journey-panel-host.mjs +25 -2
- package/skills/tacitt/scripts/journey-scan-timing.d.mts +5 -0
- package/skills/tacitt/scripts/journey-scan-timing.mjs +31 -4
- package/skills/tacitt/scripts/journey-state.d.mts +9 -1
- package/skills/tacitt/scripts/journey-state.mjs +95 -8
- package/skills/tacitt/scripts/journey-tasks.d.mts +1 -0
- package/skills/tacitt/scripts/journey-tasks.mjs +24 -9
- package/skills/tacitt/scripts/journey.d.mts +44 -31
- package/skills/tacitt/scripts/journey.mjs +34 -7
- package/skills/tacitt/scripts/privacy-validator.mjs +188 -11
- package/skills/tacitt/scripts/review.d.mts +7 -6
- package/skills/tacitt/scripts/review.mjs +922 -205
- package/dist/web/assets/index-B14e6_-z.js +0 -174
- package/dist/web/assets/index-CYJBq1px.css +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $n as
|
|
2
|
-
import { t as createZstdFrameCheck } from "./frame-
|
|
3
|
-
import {
|
|
1
|
+
import { $n as buildPlan, An as createDetectionSummary, Bn as cleanupImplementationVersion, C as createBAnalysisUnits, Cn as reviewRoles, Dn as bindInspection, En as createSessionPreparation, Gn as nativeField, Hn as nativeParserVersion, In as createReplacementKey, Jn as transformRecords, Kn as nativeItems, Ln as sessionNonce, Mn as walkNativeFields, N as bDuplicateShift, Rn as projectNativeRecord, Sn as mainReviewRole, Tn as renderNative, U as bDigest, Un as redactionImplementationVersion, Vn as entityDictionaryVersion, W as codePointLength, Xn as retainedMainTextNodes, Yn as frameRecords, Zn as validateProfile, ar as detectStatic, bn as processNativeRecord, br as processingSite, c as reviewDigest, cn as reviewFamilies, cr as jsonSpans, er as validatePlan, fn as sourceSnapshotId, gr as ProcessingError, hr as defaultDetectionLimits, in as safeCode, ir as resolveLimits, j as bBindingCap, lr as agentContextLocation, nn as ApplicationError, nr as defaultLimits, qn as nativeText, rr as recordPointerLimits, sn as familySelected, u as textDigest, un as sourceKey, ur as createEntityMatcher, vn as nativeSourceIdentitySchema, vr as fail$1, wn as createSentenceContext, xn as projectNativeReviewInput, xr as siteFields, yn as withMandatoryCustomTerms, yr as isProcessingCode, zn as parseNativeRecord } from "./locate-D-ZaHpI0.mjs";
|
|
2
|
+
import { t as createZstdFrameCheck } from "./frame-B3He21G8.mjs";
|
|
3
|
+
import { L as sourceIdentityEvidence, Mn as resolveSourceSelection, Ni as approvedTreatmentSchema, Qr as metadataProcessingVersion, R as withSourceEvidence, Ri as staticCatalogRef, ai as agentSourcePathSegment, ar as bWordBounded, ji as sourceChangePolicy, nr as bExceptionRanges, oi as agentSourceSchema, ot as classifyAgentSetup, st as defaultAgentSetupInclusion, tr as bContainment, z as agentSetupKey } from "./src-Do-qzuMn.mjs";
|
|
4
4
|
import { constants } from "node:fs";
|
|
5
5
|
import { link, lstat, mkdir, open, readFile, readdir, realpath, rm, rmdir, stat, unlink } from "node:fs/promises";
|
|
6
6
|
import { execFile, fork, spawn } from "node:child_process";
|
|
@@ -11,7 +11,7 @@ import { Readable } from "node:stream";
|
|
|
11
11
|
import { TextDecoder as TextDecoder$1, isDeepStrictEqual, promisify } from "node:util";
|
|
12
12
|
import { createHash, createHmac, randomUUID } from "node:crypto";
|
|
13
13
|
import { setImmediate } from "node:timers/promises";
|
|
14
|
-
import { ERR_UNSUPPORTED_FORMAT, Reader, TextReader, ZipReader, ZipWriter, configure } from "@zip.js/zip.js/index-native.js";
|
|
14
|
+
import { ERR_UNSUPPORTED_FORMAT, Reader, TextReader, Uint8ArrayReader, ZipReader, ZipWriter, configure } from "@zip.js/zip.js/index-native.js";
|
|
15
15
|
import "node:perf_hooks";
|
|
16
16
|
import { availableParallelism, platform, tmpdir, totalmem } from "node:os";
|
|
17
17
|
import { pipeline } from "node:stream/promises";
|
|
@@ -1874,11 +1874,11 @@ function description(value) {
|
|
|
1874
1874
|
sha256
|
|
1875
1875
|
};
|
|
1876
1876
|
}
|
|
1877
|
-
function checkWorkspaceManifest(
|
|
1878
|
-
const manifest = record$1(strictJson(
|
|
1877
|
+
function checkWorkspaceManifest(source, entries, bundleId, expectedPathHash, summary) {
|
|
1878
|
+
const manifest = record$1(typeof source === "string" ? strictJson(source, manifestLimitBytes, manifestNodeLimit) : source);
|
|
1879
1879
|
const treatment = manifest["contentTreatment"];
|
|
1880
1880
|
const configured = treatment === "configured";
|
|
1881
|
-
const configuredManifest = configured ? parseConfiguredManifest(
|
|
1881
|
+
const configuredManifest = typeof source !== "string" ? source : configured ? parseConfiguredManifest(source) : null;
|
|
1882
1882
|
if (configuredManifest) validateConfiguredManifest(configuredManifest);
|
|
1883
1883
|
const sourceWorkspaces = configuredManifest?.sourceWorkspaces ?? [record$1(manifest["workspace"])];
|
|
1884
1884
|
const workspaceIds = new Set(sourceWorkspaces.map((workspace) => string(workspace["id"])));
|
|
@@ -2443,7 +2443,7 @@ function parseAuditRow(value, sourceId, sourceSha256, ordinal) {
|
|
|
2443
2443
|
diagnostics
|
|
2444
2444
|
};
|
|
2445
2445
|
}
|
|
2446
|
-
const location$
|
|
2446
|
+
const location$2 = (pointer, subject) => `${subject}:${pointer}`;
|
|
2447
2447
|
const child = (pointer, key) => `${pointer}/${String(key).replaceAll("~", "~0").replaceAll("/", "~1")}`;
|
|
2448
2448
|
function outputLocations(text, signal) {
|
|
2449
2449
|
let root;
|
|
@@ -2462,7 +2462,7 @@ function outputLocations(text, signal) {
|
|
|
2462
2462
|
let bytes = 0;
|
|
2463
2463
|
function visit(node, pointer, subject) {
|
|
2464
2464
|
checkAbort(signal);
|
|
2465
|
-
const key = location$
|
|
2465
|
+
const key = location$2(pointer, subject);
|
|
2466
2466
|
bytes += Buffer.byteLength(key);
|
|
2467
2467
|
if (bytes > maximumBytes) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2468
2468
|
locations.set(key, node);
|
|
@@ -2491,7 +2491,7 @@ function verifyCompanion(row, outputText, signal) {
|
|
|
2491
2491
|
if (!field.fieldId.startsWith(`${row.recordId}-f`) || match === null || Number(match[1]) >= maximumEntries || match[2] !== void 0 && Number(match[2]) >= maximumEntries || fields.has(field.fieldId)) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2492
2492
|
if (match?.[2] === void 0 && match?.[3] === void 0) originals.add(Number(match?.[1]));
|
|
2493
2493
|
if (field.pointer !== null) {
|
|
2494
|
-
const key = location$
|
|
2494
|
+
const key = location$2(field.pointer, field.subject);
|
|
2495
2495
|
if (!locations.has(key) || referenced.has(key)) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2496
2496
|
referenced.add(key);
|
|
2497
2497
|
}
|
|
@@ -2505,7 +2505,7 @@ function verifyCompanion(row, outputText, signal) {
|
|
|
2505
2505
|
if (marker === null) continue;
|
|
2506
2506
|
const baseId = field.fieldId.replace(/-s\d+$|-k$/u, "");
|
|
2507
2507
|
const base = fields.get(baseId);
|
|
2508
|
-
if (!sampled.has(baseId) || base === void 0 || field.subject !== "value" || (base.pointer === null ? field.pointer !== null : field.pointer !== (marker[2] === "k" ? child(base.pointer, "skeleton") : child(child(base.pointer, "segments"), marker[1] ?? "")) || locations.get(location$
|
|
2508
|
+
if (!sampled.has(baseId) || base === void 0 || field.subject !== "value" || (base.pointer === null ? field.pointer !== null : field.pointer !== (marker[2] === "k" ? child(base.pointer, "skeleton") : child(child(base.pointer, "segments"), marker[1] ?? "")) || locations.get(location$2(field.pointer, field.subject))?.kind !== "string")) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2509
2509
|
}
|
|
2510
2510
|
const synthetic = sampleLocations(row.bodies, fields, locations);
|
|
2511
2511
|
for (const key of locations.keys()) if (!referenced.has(key) && !synthetic.has(key)) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
@@ -2643,37 +2643,31 @@ async function verifyConfiguredPart(part, entries, descriptions, signal) {
|
|
|
2643
2643
|
//#endregion
|
|
2644
2644
|
//#region packages/artifact/src/read/configured/workspace.ts
|
|
2645
2645
|
/** Public primary facts are parsed independently; no source file is opened. */
|
|
2646
|
-
function workspaceSummary(
|
|
2647
|
-
const manifest =
|
|
2648
|
-
if (manifest["contentTreatment"] !== "configured" || manifest["formatVersion"] !== 5 || manifest["companionVersion"] !== 3) return fail("ARTIFACT_INVALID_MANIFEST");
|
|
2646
|
+
function workspaceSummary(input) {
|
|
2647
|
+
const manifest = typeof input === "string" ? parseConfiguredManifest(input) : input;
|
|
2649
2648
|
return {
|
|
2650
2649
|
format: "sess-pilot-workspace-summary",
|
|
2651
2650
|
formatVersion: 1,
|
|
2652
|
-
bundleId:
|
|
2653
|
-
counts:
|
|
2654
|
-
sessions:
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
sourceOrdinal,
|
|
2667
|
-
native: part.native
|
|
2668
|
-
}))
|
|
2669
|
-
};
|
|
2670
|
-
})
|
|
2651
|
+
bundleId: manifest.bundleId,
|
|
2652
|
+
counts: manifest.counts,
|
|
2653
|
+
sessions: manifest.sessions.map((session) => ({
|
|
2654
|
+
sessionId: session.id,
|
|
2655
|
+
scopeOrdinal: 0,
|
|
2656
|
+
harness: session.harness,
|
|
2657
|
+
nativeSessionId: session.sourceSessionId,
|
|
2658
|
+
treatmentId: session.treatmentId,
|
|
2659
|
+
sources: session.parts.map((part, sourceOrdinal) => ({
|
|
2660
|
+
sourceId: part.sourceId,
|
|
2661
|
+
sourceOrdinal,
|
|
2662
|
+
native: part.native
|
|
2663
|
+
}))
|
|
2664
|
+
}))
|
|
2671
2665
|
};
|
|
2672
2666
|
}
|
|
2673
2667
|
/** Validate exact primary coverage and metadata before either native-data consumer runs. */
|
|
2674
2668
|
async function readPrimaryMetadata(primaryEntries, primaryText, signal, only) {
|
|
2675
|
-
const summary = workspaceSummary(primaryText);
|
|
2676
2669
|
const manifest = parseConfiguredManifest(primaryText);
|
|
2670
|
+
const summary = workspaceSummary(manifest);
|
|
2677
2671
|
checkWorkspaceManifest(primaryText, primaryEntries, summary.bundleId, manifest.sourceWorkspaces.length === 1 ? manifest.sourceWorkspaces[0]?.pathHash ?? null : null, summary);
|
|
2678
2672
|
for (const description of manifest.entries) {
|
|
2679
2673
|
checkAbort(signal);
|
|
@@ -3544,7 +3538,9 @@ function unavailableContribution(kind, id, workspaceId, status, reason) {
|
|
|
3544
3538
|
function reportInspectionFailure(observer, stage, error) {
|
|
3545
3539
|
try {
|
|
3546
3540
|
if (!observer) {
|
|
3547
|
-
|
|
3541
|
+
const named = processingSite(error);
|
|
3542
|
+
const fields = named ? ` site=${named.site}` + (named.harness ? ` harness=${named.harness}` : "") + (named.harnessVersion ? ` version=${named.harnessVersion}` : "") : "";
|
|
3543
|
+
process.stderr.write(`Inspection processing failed: ${safeCode(error)} (${stage})${fields}\n`);
|
|
3548
3544
|
return;
|
|
3549
3545
|
}
|
|
3550
3546
|
observer(stage, error);
|
|
@@ -4004,11 +4000,14 @@ function configuredSelection(selection, treatment) {
|
|
|
4004
4000
|
mode: { kind: "remove" },
|
|
4005
4001
|
replacement: edit.retainAs
|
|
4006
4002
|
};
|
|
4007
|
-
|
|
4003
|
+
if (mode.kind !== "retain") return {
|
|
4004
|
+
...edit,
|
|
4005
|
+
mode
|
|
4006
|
+
};
|
|
4007
|
+
const { replacement: _replacement, replacementSourceRanges: _source, replacementTargetRanges: _target, ...original } = edit;
|
|
4008
4008
|
return {
|
|
4009
4009
|
...original,
|
|
4010
|
-
mode
|
|
4011
|
-
...mode.kind !== "retain" && edit.replacement !== void 0 ? { replacement: edit.replacement } : {}
|
|
4010
|
+
mode
|
|
4012
4011
|
};
|
|
4013
4012
|
}),
|
|
4014
4013
|
diagnostics: selection.diagnostics,
|
|
@@ -5583,17 +5582,20 @@ function matchFrozenOutput(input, checked) {
|
|
|
5583
5582
|
if (input.sha256 !== checked.sha256 || input.archiveBytes !== checked.archiveBytes) fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
5584
5583
|
}
|
|
5585
5584
|
async function checkFrozenOutput(input, signal) {
|
|
5586
|
-
let
|
|
5585
|
+
let verified;
|
|
5587
5586
|
const checked = await checkWrittenArchive(input.path, input.identity, void 0, (text, entries) => {
|
|
5588
5587
|
const manifest = parseConfiguredManifest(text);
|
|
5589
|
-
checkWorkspaceManifest(
|
|
5590
|
-
|
|
5588
|
+
checkWorkspaceManifest(manifest, entries, manifest.bundleId, manifest.sourceWorkspaces.length === 1 ? manifest.sourceWorkspaces[0]?.pathHash ?? null : null, workspaceSummary(manifest));
|
|
5589
|
+
verified = {
|
|
5590
|
+
manifestText: text,
|
|
5591
|
+
manifest
|
|
5592
|
+
};
|
|
5591
5593
|
}, signal);
|
|
5592
5594
|
matchFrozenOutput(input, checked);
|
|
5595
|
+
if (!verified) return fail("ARTIFACT_INVALID_MANIFEST");
|
|
5593
5596
|
return {
|
|
5594
5597
|
checked,
|
|
5595
|
-
|
|
5596
|
-
manifest: parseConfiguredManifest(manifestText)
|
|
5598
|
+
...verified
|
|
5597
5599
|
};
|
|
5598
5600
|
}
|
|
5599
5601
|
/** Hold the exact verified descriptor; every entry is separately hashed before use. */
|
|
@@ -7289,6 +7291,24 @@ function stringOffsets(root, changes) {
|
|
|
7289
7291
|
return offsets;
|
|
7290
7292
|
}
|
|
7291
7293
|
const encodedLength = (text) => JSON.stringify(text).length - 2;
|
|
7294
|
+
/** Absolute JSON string-content coordinates. Fixed-size checkpoints bound both the work
|
|
7295
|
+
* per lookup and retained memory, including out-of-order overlapping contributor ranges. */
|
|
7296
|
+
function encodedOffset(text, base) {
|
|
7297
|
+
const stride = 1024;
|
|
7298
|
+
const offsets = [base];
|
|
7299
|
+
const boundary = (block) => {
|
|
7300
|
+
const at = block * stride;
|
|
7301
|
+
return scalarBoundary(text, at) ? at : at - 1;
|
|
7302
|
+
};
|
|
7303
|
+
return (position) => {
|
|
7304
|
+
const block = Math.floor(position / stride);
|
|
7305
|
+
while (offsets.length <= block) {
|
|
7306
|
+
const next = offsets.length;
|
|
7307
|
+
offsets.push((offsets[next - 1] ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(text.slice(boundary(next - 1), boundary(next))));
|
|
7308
|
+
}
|
|
7309
|
+
return (offsets[block] ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(text.slice(boundary(block), position));
|
|
7310
|
+
};
|
|
7311
|
+
}
|
|
7292
7312
|
/** Restore verified untouched scalar lexemes without round-tripping through JS numbers. */
|
|
7293
7313
|
function restoreLiterals(root, literals) {
|
|
7294
7314
|
const raw = literals.get(root.id);
|
|
@@ -7362,37 +7382,42 @@ function renderReviewRow(row, before, edits, markers, signal) {
|
|
|
7362
7382
|
const changed = inner ? renderNative(inner, innerChanges, reviewLimits, signal).text : pieces[0]?.changed ?? fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
7363
7383
|
const sourceOffsets = inner ? stringOffsets(inner, /* @__PURE__ */ new Map()) : void 0, outputOffsets = inner ? stringOffsets(inner, innerChanges) : void 0;
|
|
7364
7384
|
const inputSha256 = hash$4(sourceText), outputSha256 = hash$4(changed), context = createSentenceContext(sourceText);
|
|
7365
|
-
for (const piece of pieces)
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7385
|
+
for (const piece of pieces) {
|
|
7386
|
+
if (!piece.items.length) continue;
|
|
7387
|
+
const inputOffset = sourceOffsets && encodedOffset(piece.source, sourceOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH"));
|
|
7388
|
+
const outputOffset = outputOffsets && encodedOffset(piece.changed, outputOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH"));
|
|
7389
|
+
const coordinates = (range) => inputOffset ? {
|
|
7390
|
+
start: inputOffset(range.start),
|
|
7391
|
+
end: inputOffset(range.end)
|
|
7369
7392
|
} : range;
|
|
7370
|
-
const
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7393
|
+
for (const item of piece.items) {
|
|
7394
|
+
const inputRange = coordinates(item.inputRange);
|
|
7395
|
+
const start = outputOffset ? outputOffset(item.outputRange.start) : item.outputRange.start;
|
|
7396
|
+
const { span, ...applied } = item;
|
|
7397
|
+
const transcript = {
|
|
7398
|
+
...applied,
|
|
7399
|
+
pointer,
|
|
7400
|
+
inputSha256,
|
|
7401
|
+
outputSha256,
|
|
7402
|
+
inputRange,
|
|
7403
|
+
outputRange: {
|
|
7404
|
+
start,
|
|
7405
|
+
end: start + item.replacement.length
|
|
7406
|
+
},
|
|
7407
|
+
context: context(inputRange)
|
|
7408
|
+
};
|
|
7409
|
+
transcripts.push({
|
|
7410
|
+
...transcript,
|
|
7411
|
+
contributors: reconstructedContributors({
|
|
7412
|
+
row,
|
|
7413
|
+
field: piece.field,
|
|
7414
|
+
span,
|
|
7415
|
+
transcript,
|
|
7416
|
+
coordinates,
|
|
7417
|
+
context
|
|
7418
|
+
})
|
|
7419
|
+
});
|
|
7420
|
+
}
|
|
7396
7421
|
}
|
|
7397
7422
|
if (nativeContainer && changed === sourceText) {
|
|
7398
7423
|
if (nativeContainerText(target, signal) !== sourceText) fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
@@ -7508,10 +7533,12 @@ function indexFamilyHides(manifest, hides = []) {
|
|
|
7508
7533
|
if (!family) {
|
|
7509
7534
|
const categories = /* @__PURE__ */ new Map();
|
|
7510
7535
|
const bounded = /* @__PURE__ */ new Set();
|
|
7511
|
-
|
|
7536
|
+
const toolResultEscapes = /* @__PURE__ */ new Set();
|
|
7537
|
+
for (const { term, category, bounded: whole, toolResultEscapes: escaped } of hide.terms) {
|
|
7512
7538
|
if (categories.has(term)) mismatch("duplicate-term");
|
|
7513
7539
|
categories.set(term, maskCategory(category));
|
|
7514
7540
|
if (whole) bounded.add(term);
|
|
7541
|
+
if (escaped) toolResultEscapes.add(term);
|
|
7515
7542
|
}
|
|
7516
7543
|
family = {
|
|
7517
7544
|
matcher: createEntityMatcher([...categories.keys()].map((value) => ({
|
|
@@ -7520,6 +7547,7 @@ function indexFamilyHides(manifest, hides = []) {
|
|
|
7520
7547
|
}))),
|
|
7521
7548
|
categories,
|
|
7522
7549
|
bounded,
|
|
7550
|
+
toolResultEscapes,
|
|
7523
7551
|
excepted: bExceptionRanges(hide.exceptions ?? [])
|
|
7524
7552
|
};
|
|
7525
7553
|
shared.set(key, family);
|
|
@@ -7530,7 +7558,7 @@ function indexFamilyHides(manifest, hides = []) {
|
|
|
7530
7558
|
return parts;
|
|
7531
7559
|
}
|
|
7532
7560
|
/** Disjoint literal hits outside existing markers; overlaps join under the highest category. */
|
|
7533
|
-
function familySpans(text, family, signal) {
|
|
7561
|
+
function familySpans(text, family, signal, toolResult) {
|
|
7534
7562
|
const markers = [...text.matchAll(markerPattern)].map((match) => ({
|
|
7535
7563
|
start: match.index,
|
|
7536
7564
|
end: match.index + match[0].length
|
|
@@ -7546,7 +7574,7 @@ function familySpans(text, family, signal) {
|
|
|
7546
7574
|
}
|
|
7547
7575
|
return (markers[low]?.start ?? Infinity) < range.end;
|
|
7548
7576
|
};
|
|
7549
|
-
const hits = family.matcher.find(text, signal, 2e6).filter(({ range, entity }) => !marked(range) && (!family.bounded.has(entity.value) || bWordBounded(text, range.start, range.end)) && !excepted(range)).map(({ range, entity }) => ({
|
|
7577
|
+
const hits = family.matcher.find(text, signal, 2e6).filter(({ range, entity }) => !marked(range) && (!family.bounded.has(entity.value) || bWordBounded(text, range.start, range.end, toolResult && family.toolResultEscapes.has(entity.value))) && !excepted(range)).map(({ range, entity }) => ({
|
|
7550
7578
|
...range,
|
|
7551
7579
|
category: family.categories.get(entity.value) ?? mismatch("unknown-term")
|
|
7552
7580
|
})).sort((left, right) => left.start - right.start || right.end - left.end);
|
|
@@ -7620,8 +7648,10 @@ function maskFamilyFields(text, root, annotations, family, markers, signal, onAp
|
|
|
7620
7648
|
if (skip(field)) continue;
|
|
7621
7649
|
if (field.text.includes(markers.prefix)) mismatch("marker-prefix");
|
|
7622
7650
|
if (field.subject !== "value" || field.scalarKind !== "string" || field.field.protection || !bodies.has(field.nodeId) && structural(field.field.name)) continue;
|
|
7623
|
-
const
|
|
7624
|
-
const
|
|
7651
|
+
const toolResult = field.origin.carrier === "tool-result";
|
|
7652
|
+
const find = (value) => familySpans(value, family, signal, toolResult);
|
|
7653
|
+
const raw = find(field.text);
|
|
7654
|
+
const carrier = raw.length || field.text.includes("\\") ? familyCarrierSpans(field, find, signal) : void 0;
|
|
7625
7655
|
const spans = (carrier ?? raw).sort((left, right) => left.start - right.start);
|
|
7626
7656
|
if (!spans.length) continue;
|
|
7627
7657
|
const changed = maskOutputField({
|
|
@@ -9618,7 +9648,14 @@ function isWorkerMessage(value) {
|
|
|
9618
9648
|
if (kind === "spool") return typeof path === "string" && path.length > 0;
|
|
9619
9649
|
if (kind === "result") return isResult(Reflect.get(value, "result"));
|
|
9620
9650
|
if (kind === "worker-error") return code === "ARTIFACT_WORKER_MEMORY" || code === "ARTIFACT_PROCESSING_FAILED";
|
|
9621
|
-
return kind === "error" && typeof code === "string" && code.length > 0 && (sourceId === void 0 || typeof sourceId === "string")
|
|
9651
|
+
return kind === "error" && typeof code === "string" && code.length > 0 && (sourceId === void 0 || typeof sourceId === "string") && [
|
|
9652
|
+
"site",
|
|
9653
|
+
"harness",
|
|
9654
|
+
"harnessVersion"
|
|
9655
|
+
].every((key) => {
|
|
9656
|
+
const field = Reflect.get(value, key);
|
|
9657
|
+
return field === void 0 || typeof field === "string";
|
|
9658
|
+
});
|
|
9622
9659
|
}
|
|
9623
9660
|
/** How long a stopped controller may take to end its Worker and flush its messages (ADR 0219). */
|
|
9624
9661
|
const stopGraceMs = 2e3;
|
|
@@ -9699,13 +9736,18 @@ function createSessionProcess(workerUrl, heapMb, onMessage, onFailure) {
|
|
|
9699
9736
|
}
|
|
9700
9737
|
//#endregion
|
|
9701
9738
|
//#region packages/artifact/src/configured/parallel/pool.ts
|
|
9702
|
-
/** Failure code plus the frozen source id
|
|
9739
|
+
/** Failure code plus the frozen source id and the named refusal site (#59), when known. */
|
|
9703
9740
|
var SessionWorkerError = class extends Error {
|
|
9704
9741
|
sourceId;
|
|
9742
|
+
site;
|
|
9743
|
+
harness;
|
|
9744
|
+
harnessVersion;
|
|
9705
9745
|
constructor(code, sourceId, options) {
|
|
9706
9746
|
super(code, options);
|
|
9707
9747
|
this.name = "SessionWorkerError";
|
|
9708
9748
|
if (sourceId !== void 0) this.sourceId = sourceId;
|
|
9749
|
+
const named = siteFields(options);
|
|
9750
|
+
if (named) Object.assign(this, named);
|
|
9709
9751
|
}
|
|
9710
9752
|
};
|
|
9711
9753
|
/**
|
|
@@ -9827,7 +9869,16 @@ function createSessionWorkerPool(url, size, heapMb = workerHeapMb) {
|
|
|
9827
9869
|
stopping = Promise.all(slots.map(async (slot) => {
|
|
9828
9870
|
try {
|
|
9829
9871
|
await slot.process.close();
|
|
9830
|
-
if (slot.task)
|
|
9872
|
+
if (slot.task) {
|
|
9873
|
+
if (requestKind(slot.task) === "journey-base") {
|
|
9874
|
+
await removeNamedTemporarySpools(slot.task.spoolPaths);
|
|
9875
|
+
for (const path of slot.task.spoolPaths) try {
|
|
9876
|
+
await unlink(path);
|
|
9877
|
+
} catch (error) {
|
|
9878
|
+
if (filesystemCode(error) !== "ENOENT") throw error;
|
|
9879
|
+
}
|
|
9880
|
+
} else await removeStoppedSpools(slot.task.spoolPaths);
|
|
9881
|
+
}
|
|
9831
9882
|
} finally {
|
|
9832
9883
|
slot.task?.reject(blame(slot));
|
|
9833
9884
|
slot.task = void 0;
|
|
@@ -9868,6 +9919,10 @@ function createSessionWorkerPool(url, size, heapMb = workerHeapMb) {
|
|
|
9868
9919
|
}
|
|
9869
9920
|
task.spoolPaths.add(message.path);
|
|
9870
9921
|
task.onSpool?.(message.path);
|
|
9922
|
+
if (!closed) slot.process.send({
|
|
9923
|
+
kind: "spool-owned",
|
|
9924
|
+
path: message.path
|
|
9925
|
+
});
|
|
9871
9926
|
} else if (message.kind === "result") {
|
|
9872
9927
|
const requestedKind = requestKind(task);
|
|
9873
9928
|
if ((requestedKind === "render" || requestedKind === "capture" || requestedKind === "scan" || requestedKind === "journey-output" || requestedKind === "journey-output-shard" || requestedKind === "journey-output-verify" || requestedKind === "journey-base") && message.result.kind !== requestedKind) {
|
|
@@ -9912,7 +9967,7 @@ function createSessionWorkerPool(url, size, heapMb = workerHeapMb) {
|
|
|
9912
9967
|
return;
|
|
9913
9968
|
}
|
|
9914
9969
|
settle(slot, void 0, message.result);
|
|
9915
|
-
} else settle(slot, new SessionWorkerError(message.code, message.sourceId));
|
|
9970
|
+
} else settle(slot, new SessionWorkerError(message.code, message.sourceId, siteFields(message)));
|
|
9916
9971
|
} catch {
|
|
9917
9972
|
failPool(/* @__PURE__ */ new Error("ARTIFACT_PROCESSING_FAILED"), slot);
|
|
9918
9973
|
}
|
|
@@ -10169,7 +10224,7 @@ function selectConfiguredApproval(approval, admission, configuration = configure
|
|
|
10169
10224
|
//#region packages/artifact/src/collection/producer/versions.ts
|
|
10170
10225
|
/** Only configured output consumes these dependencies; hash them with actual version facts. */
|
|
10171
10226
|
const configuredProcessingSemantics = Object.freeze({
|
|
10172
|
-
catalog: "
|
|
10227
|
+
catalog: "12",
|
|
10173
10228
|
parser: nativeParserVersion,
|
|
10174
10229
|
dictionary: entityDictionaryVersion,
|
|
10175
10230
|
metadata: metadataProcessingVersion,
|
|
@@ -12855,32 +12910,39 @@ async function writeOriginalWorkspace(production, workspaceId, bundleId, identit
|
|
|
12855
12910
|
}
|
|
12856
12911
|
//#endregion
|
|
12857
12912
|
//#region packages/artifact/src/configured/admission/lifecycle.ts
|
|
12858
|
-
function
|
|
12913
|
+
function parsed(text) {
|
|
12859
12914
|
try {
|
|
12860
|
-
return
|
|
12915
|
+
return JSON.parse(text);
|
|
12861
12916
|
} catch {
|
|
12862
|
-
return
|
|
12917
|
+
return;
|
|
12863
12918
|
}
|
|
12864
12919
|
}
|
|
12865
12920
|
/**
|
|
12866
|
-
* Reads the whole snapshot one bounded record at a time. Returns only when every record is
|
|
12867
|
-
*
|
|
12921
|
+
* Reads the whole snapshot one bounded record at a time. Returns only when every record is a
|
|
12922
|
+
* lifecycle record and either one names an agent run or all match the exact journal schema
|
|
12923
|
+
* (ADR 0279). A launched-only file at the exact journal path is excluded when every record
|
|
12924
|
+
* matches that schema. Empty files, other records and oversized records fail closed.
|
|
12868
12925
|
*/
|
|
12869
12926
|
async function confirmLifecycleSource(part, lifecycle, signal, overrides, open = openConfiguredSource) {
|
|
12870
12927
|
const input = await open(part, signal);
|
|
12871
12928
|
const cleanup = createCleanup();
|
|
12872
12929
|
try {
|
|
12930
|
+
let agentRecords = 0;
|
|
12873
12931
|
let records = 0;
|
|
12932
|
+
let exactOnly = true;
|
|
12874
12933
|
try {
|
|
12875
12934
|
for await (const text of frameRecords(input.chunks, "jsonl", resolveLimits(overrides).maxRecordBytes, signal)) {
|
|
12876
|
-
|
|
12935
|
+
const value = parsed(text);
|
|
12936
|
+
if (!lifecycle.record(value)) fail("ARTIFACT_UNRECOGNIZED_JOURNAL");
|
|
12937
|
+
if (lifecycle.agentRecord(value)) agentRecords++;
|
|
12877
12938
|
records++;
|
|
12939
|
+
if (!lifecycle.exactRecord(value)) exactOnly = false;
|
|
12878
12940
|
}
|
|
12879
12941
|
} catch (error) {
|
|
12880
12942
|
if (error instanceof ProcessingError && (error.code === "PROCESSING_LIMIT" || error.code === "PROCESSING_INVALID_RECORD")) fail("ARTIFACT_UNRECOGNIZED_JOURNAL", { cause: error });
|
|
12881
12943
|
throw error;
|
|
12882
12944
|
}
|
|
12883
|
-
if (records === 0) fail("ARTIFACT_UNRECOGNIZED_JOURNAL");
|
|
12945
|
+
if (records === 0 || agentRecords === 0 && !exactOnly) fail("ARTIFACT_UNRECOGNIZED_JOURNAL");
|
|
12884
12946
|
await input.finish();
|
|
12885
12947
|
} catch (error) {
|
|
12886
12948
|
cleanup.failed(error);
|
|
@@ -15449,7 +15511,7 @@ async function sessionFileFacts(file, size, signal) {
|
|
|
15449
15511
|
/** Verify bounded final redacted bytes before starting a second ZIP codec. */
|
|
15450
15512
|
async function sessionPart(entry, expected, signal) {
|
|
15451
15513
|
if (expected.byteLength > 268435456 || entry.uncompressedSize !== expected.byteLength) fail("ARTIFACT_PART_LIMIT");
|
|
15452
|
-
const
|
|
15514
|
+
const scratch = expected.byteLength <= 65536 ? { bytes: new Uint8Array(expected.byteLength) } : { file: await sessionFile() };
|
|
15453
15515
|
let size = 0;
|
|
15454
15516
|
const digest = createHash("sha256");
|
|
15455
15517
|
let crc = 0;
|
|
@@ -15459,11 +15521,14 @@ async function sessionPart(entry, expected, signal) {
|
|
|
15459
15521
|
if (size + bytes.byteLength > expected.byteLength) fail("ARTIFACT_PART_LIMIT");
|
|
15460
15522
|
digest.update(bytes);
|
|
15461
15523
|
crc = crc32(bytes, crc);
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15524
|
+
if (scratch.bytes) scratch.bytes.set(bytes, size);
|
|
15525
|
+
else {
|
|
15526
|
+
let offset = 0;
|
|
15527
|
+
while (offset < bytes.byteLength) {
|
|
15528
|
+
const { bytesWritten } = await scratch.file.write(bytes, offset, bytes.byteLength - offset, size + offset);
|
|
15529
|
+
if (!bytesWritten) fail("ARTIFACT_IO_FAILED");
|
|
15530
|
+
offset += bytesWritten;
|
|
15531
|
+
}
|
|
15467
15532
|
}
|
|
15468
15533
|
size += bytes.byteLength;
|
|
15469
15534
|
} }), {
|
|
@@ -15471,55 +15536,93 @@ async function sessionPart(entry, expected, signal) {
|
|
|
15471
15536
|
checkSignature: true
|
|
15472
15537
|
});
|
|
15473
15538
|
if (size !== expected.byteLength || digest.digest("hex") !== expected.sha256) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15539
|
+
const reader = scratch.bytes ? new Uint8ArrayReader(scratch.bytes) : new FileReader(scratch.file, size, 262144, true, signal);
|
|
15474
15540
|
return {
|
|
15475
|
-
file,
|
|
15541
|
+
file: scratch.file,
|
|
15542
|
+
reader,
|
|
15476
15543
|
crc32: crc
|
|
15477
15544
|
};
|
|
15478
15545
|
} catch (error) {
|
|
15479
15546
|
const cleanup = createCleanup();
|
|
15480
15547
|
cleanup.failed(error);
|
|
15481
|
-
|
|
15548
|
+
const { file } = scratch;
|
|
15549
|
+
if (file) await cleanup.run(() => file.close());
|
|
15482
15550
|
throw error;
|
|
15483
15551
|
}
|
|
15484
15552
|
}
|
|
15485
15553
|
//#endregion
|
|
15486
15554
|
//#region packages/artifact/src/configured/output/sessions.ts
|
|
15487
|
-
|
|
15488
|
-
async function* configuredSessionUploads(input, identities, signal) {
|
|
15555
|
+
async function* configuredSessionUploads(input, identities, signal, mode = "upload", omitted = /* @__PURE__ */ new Set(), checkMinimumBytes) {
|
|
15489
15556
|
const verified = await checkFrozenOutput(input, signal);
|
|
15490
15557
|
const archive = await openCheckedOutput(input, verified.checked, signal);
|
|
15491
15558
|
const cleanup = createCleanup();
|
|
15492
15559
|
try {
|
|
15493
15560
|
if (archive.manifestText !== verified.manifestText) fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
15494
15561
|
const descriptions = new Map(verified.manifest.entries.map((entry) => [entry.entryPath, entry]));
|
|
15562
|
+
const byId = new Map(identities.map((identity) => [identity.archiveSessionId, identity]));
|
|
15563
|
+
if (byId.size !== identities.length) fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15564
|
+
if (checkMinimumBytes) {
|
|
15565
|
+
const measured = /* @__PURE__ */ new Set();
|
|
15566
|
+
let bytes = 0;
|
|
15567
|
+
for (const session of verified.manifest.sessions) {
|
|
15568
|
+
if (omitted.has(session.id)) continue;
|
|
15569
|
+
if (!byId.has(session.id)) fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15570
|
+
for (const part of session.parts) {
|
|
15571
|
+
const entry = descriptions.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15572
|
+
if (measured.has(entry.sha256)) continue;
|
|
15573
|
+
measured.add(entry.sha256);
|
|
15574
|
+
bytes += entry.byteLength;
|
|
15575
|
+
}
|
|
15576
|
+
}
|
|
15577
|
+
checkMinimumBytes(bytes);
|
|
15578
|
+
}
|
|
15579
|
+
const workspaces = new Map(verified.manifest.sourceWorkspaces.map((workspace) => [workspace.id, workspace]));
|
|
15580
|
+
const workspaceFacts = /* @__PURE__ */ new Map();
|
|
15495
15581
|
for (const session of verified.manifest.sessions) {
|
|
15496
15582
|
signal.throwIfAborted();
|
|
15497
|
-
|
|
15498
|
-
const
|
|
15499
|
-
const
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15583
|
+
if (omitted.has(session.id)) continue;
|
|
15584
|
+
const identity = byId.get(session.id) ?? fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15585
|
+
const workspace = workspaces.get(session.workspaceId) ?? fail("ARTIFACT_INVALID_MANIFEST");
|
|
15586
|
+
let facts = workspaceFacts.get(workspace.id);
|
|
15587
|
+
if (!facts) {
|
|
15588
|
+
const entry = archive.entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15589
|
+
const description = descriptions.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15590
|
+
const text = await readMetadata(entry, signal);
|
|
15591
|
+
if (Buffer.byteLength(text) !== description.byteLength || createHash("sha256").update(text).digest("hex") !== description.sha256) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15592
|
+
const { version: _, ...validated } = validateConfiguredSourceMetadata(strictJson(text, metadataLimitBytes), workspace);
|
|
15593
|
+
facts = validated;
|
|
15594
|
+
workspaceFacts.set(workspace.id, facts);
|
|
15595
|
+
}
|
|
15504
15596
|
const native = session.parts[0]?.native;
|
|
15505
15597
|
const nativeSessionId = native?.sessionId ?? session.sourceSessionId;
|
|
15506
15598
|
if (!nativeSessionId?.trim() && !identity.relativePath) fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15507
15599
|
const metadata = {
|
|
15508
|
-
workspace:
|
|
15600
|
+
workspace: {
|
|
15601
|
+
...facts,
|
|
15602
|
+
remoteHashes: [...facts.remoteHashes]
|
|
15603
|
+
},
|
|
15509
15604
|
sourceSessionId: nativeSessionId,
|
|
15510
15605
|
harness: session.harness,
|
|
15511
15606
|
lastAt: identity.lastAt,
|
|
15512
15607
|
parts: []
|
|
15513
15608
|
};
|
|
15514
|
-
const file = await sessionFile();
|
|
15609
|
+
const file = mode === "upload" ? await sessionFile() : null;
|
|
15515
15610
|
const sessionCleanup = createCleanup();
|
|
15516
15611
|
try {
|
|
15517
15612
|
let size = 0;
|
|
15518
|
-
const
|
|
15613
|
+
const limit = (bytes) => {
|
|
15519
15614
|
if (bytes > 5 * 1024 ** 3) fail("ARTIFACT_ARCHIVE_LIMIT");
|
|
15520
15615
|
size = bytes;
|
|
15521
|
-
}
|
|
15522
|
-
const
|
|
15616
|
+
};
|
|
15617
|
+
const digest = createHash("sha256");
|
|
15618
|
+
let checksum = 0;
|
|
15619
|
+
const writable = file ? fileWriter(file, signal, limit, false).writable : new WritableStream({ write(bytes) {
|
|
15620
|
+
signal.throwIfAborted();
|
|
15621
|
+
limit(size + bytes.byteLength);
|
|
15622
|
+
digest.update(bytes);
|
|
15623
|
+
checksum = crc32(bytes, checksum);
|
|
15624
|
+
} });
|
|
15625
|
+
const zip = new ZipWriter(writable, {
|
|
15523
15626
|
useWebWorkers: false,
|
|
15524
15627
|
useCompressionStream: true,
|
|
15525
15628
|
bufferedWrite: false,
|
|
@@ -15535,24 +15638,30 @@ async function* configuredSessionUploads(input, identities, signal) {
|
|
|
15535
15638
|
const partCleanup = createCleanup();
|
|
15536
15639
|
try {
|
|
15537
15640
|
const path = `p${String(index + 1).padStart(6, "0")}.jsonl`;
|
|
15538
|
-
await zip.add(path,
|
|
15641
|
+
await zip.add(path, prepared.reader, { signal });
|
|
15539
15642
|
metadata.parts.push({
|
|
15540
15643
|
path,
|
|
15541
15644
|
byteLength: expected.byteLength,
|
|
15542
15645
|
sha256: expected.sha256,
|
|
15543
|
-
crc32: prepared.crc32
|
|
15646
|
+
crc32: prepared.crc32,
|
|
15647
|
+
native: part.native
|
|
15544
15648
|
});
|
|
15545
15649
|
} catch (error) {
|
|
15546
15650
|
partCleanup.failed(error);
|
|
15547
15651
|
throw error;
|
|
15548
15652
|
} finally {
|
|
15549
|
-
|
|
15653
|
+
const { file } = prepared;
|
|
15654
|
+
if (file) await partCleanup.run(() => file.close());
|
|
15550
15655
|
}
|
|
15551
15656
|
}
|
|
15552
15657
|
await zip.close();
|
|
15553
15658
|
if (zip.warnings?.length) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15554
15659
|
if (size > 5 * 1024 ** 3) fail("ARTIFACT_ARCHIVE_LIMIT");
|
|
15555
|
-
const content = await sessionFileFacts(file, size, signal)
|
|
15660
|
+
const content = file ? await sessionFileFacts(file, size, signal) : {
|
|
15661
|
+
byteLength: size,
|
|
15662
|
+
sha256: digest.digest("hex"),
|
|
15663
|
+
crc32: checksum
|
|
15664
|
+
};
|
|
15556
15665
|
await archive.fence();
|
|
15557
15666
|
yield {
|
|
15558
15667
|
...content,
|
|
@@ -15562,13 +15671,13 @@ async function* configuredSessionUploads(input, identities, signal) {
|
|
|
15562
15671
|
relativePath: identity.relativePath,
|
|
15563
15672
|
harness: session.harness,
|
|
15564
15673
|
lastAt: identity.lastAt,
|
|
15565
|
-
stream: () => new FileReader(file, size, 262144, true, signal).createReadable()
|
|
15674
|
+
...file ? { stream: () => new FileReader(file, size, 262144, true, signal).createReadable() } : {}
|
|
15566
15675
|
};
|
|
15567
15676
|
} catch (error) {
|
|
15568
15677
|
sessionCleanup.failed(error);
|
|
15569
15678
|
throw error;
|
|
15570
15679
|
} finally {
|
|
15571
|
-
await sessionCleanup.run(() => file.close());
|
|
15680
|
+
if (file) await sessionCleanup.run(() => file.close());
|
|
15572
15681
|
}
|
|
15573
15682
|
}
|
|
15574
15683
|
} catch (error) {
|
|
@@ -16083,7 +16192,7 @@ async function scanPreparedSession(production, sessionId, directory, hooks, canc
|
|
|
16083
16192
|
workspaceId: selected.workspace.id,
|
|
16084
16193
|
sessionId,
|
|
16085
16194
|
...source ? { sourcePartId: source.source.id } : {}
|
|
16086
|
-
}), async () => {
|
|
16195
|
+
}, void 0, error), async () => {
|
|
16087
16196
|
if (result) await unlink(result.input.file.path);
|
|
16088
16197
|
});
|
|
16089
16198
|
throw classified;
|
|
@@ -16337,7 +16446,7 @@ const maxChunks = 8e4;
|
|
|
16337
16446
|
function batchLoad(body) {
|
|
16338
16447
|
return Math.max(body.chunks.length / maxChunks, (body.duplicates?.length ?? 0) / maxChunks, Buffer.byteLength(JSON.stringify(body)) / maxTransportBytes);
|
|
16339
16448
|
}
|
|
16340
|
-
function location(context, fieldId, part) {
|
|
16449
|
+
function location$1(context, fieldId, part) {
|
|
16341
16450
|
const source = context.locations.get(fieldId);
|
|
16342
16451
|
if (!source) throw new ApplicationError("CORRUPTED_STATE");
|
|
16343
16452
|
const native = reviewSource(source);
|
|
@@ -16376,7 +16485,7 @@ function reviewBatchBody(context, unit, ordinal) {
|
|
|
16376
16485
|
};
|
|
16377
16486
|
const chunks = unit.fragments.map((part) => ({
|
|
16378
16487
|
id: chunkId(part.fieldId, part),
|
|
16379
|
-
...location(context, part.fieldId, part),
|
|
16488
|
+
...location$1(context, part.fieldId, part),
|
|
16380
16489
|
core: part.core,
|
|
16381
16490
|
offset: part.utf16Start,
|
|
16382
16491
|
text: part.text,
|
|
@@ -16396,7 +16505,7 @@ function reviewBatchBody(context, unit, ordinal) {
|
|
|
16396
16505
|
utf16Start: part.utf16Start + shift.utf16,
|
|
16397
16506
|
utf16End: part.utf16End + shift.utf16
|
|
16398
16507
|
};
|
|
16399
|
-
const { displayMasks, ...own } = location(context, duplicate.fieldId, copy);
|
|
16508
|
+
const { displayMasks, ...own } = location$1(context, duplicate.fieldId, copy);
|
|
16400
16509
|
const hash = fieldHash(duplicate.fieldId);
|
|
16401
16510
|
return {
|
|
16402
16511
|
id: chunkId(duplicate.fieldId, copy),
|
|
@@ -16807,24 +16916,36 @@ function buildWorkScanBatches(context, sessionId, fields, pieces) {
|
|
|
16807
16916
|
/**
|
|
16808
16917
|
* Roots whose complete frozen main capture names an automation launch. Discovery normally
|
|
16809
16918
|
* keeps these out of classification; this catches a confirmed root it could not recognize.
|
|
16919
|
+
* A root whose capture the check cannot read fails like an admission refusal (issue #59), so
|
|
16920
|
+
* only that root leaves its Work (ADR 0188); an abort still escapes.
|
|
16810
16921
|
*/
|
|
16811
|
-
async function automatedRoots(rows, families, request, signal) {
|
|
16922
|
+
async function automatedRoots(rows, families, request, signal, onFailure) {
|
|
16812
16923
|
const roots = /* @__PURE__ */ new Set();
|
|
16813
16924
|
for (const row of rows) {
|
|
16814
16925
|
if (row.failure || families.owners.get(row.session.id)?.id !== row.session.id) continue;
|
|
16815
16926
|
const adapter = request.processing.adapters[row.session.harness];
|
|
16816
16927
|
for (const source of row.sources) {
|
|
16817
16928
|
if (source.native.role !== "main") continue;
|
|
16818
|
-
const
|
|
16819
|
-
|
|
16929
|
+
const capture = request.captures.get(source.source.path) ?? fail("ARTIFACT_SOURCE_CHANGED");
|
|
16930
|
+
let launch;
|
|
16820
16931
|
try {
|
|
16821
|
-
|
|
16932
|
+
const opened = await openSourceCapture(capture);
|
|
16933
|
+
const cleanup = createCleanup();
|
|
16934
|
+
try {
|
|
16935
|
+
launch = await capturedLaunch(source.source, opened, adapter, signal, request.processing.limits);
|
|
16936
|
+
} catch (error) {
|
|
16937
|
+
cleanup.failed(error);
|
|
16938
|
+
throw error;
|
|
16939
|
+
} finally {
|
|
16940
|
+
await cleanup.run(() => opened.close());
|
|
16941
|
+
}
|
|
16822
16942
|
} catch (error) {
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16943
|
+
row.failure = inspectionFailure(error, signal);
|
|
16944
|
+
onFailure(row.session, row.failure, source.source.id, error);
|
|
16945
|
+
reportInspectionFailure(request.processing.onInspectionFailure, "inspection-admission", error);
|
|
16946
|
+
break;
|
|
16827
16947
|
}
|
|
16948
|
+
if (launch === "automation") roots.add(row.session.id);
|
|
16828
16949
|
}
|
|
16829
16950
|
}
|
|
16830
16951
|
return roots;
|
|
@@ -16860,15 +16981,16 @@ async function prepareSessionScans(request, signal) {
|
|
|
16860
16981
|
});
|
|
16861
16982
|
};
|
|
16862
16983
|
const failures = [];
|
|
16984
|
+
const onFailure = (session, reason, sourcePartId, cause) => {
|
|
16985
|
+
failures.push({
|
|
16986
|
+
sessionId: session.id,
|
|
16987
|
+
reason,
|
|
16988
|
+
...sourcePartId === void 0 ? {} : { sourcePartId },
|
|
16989
|
+
...cause === void 0 ? {} : { cause }
|
|
16990
|
+
});
|
|
16991
|
+
};
|
|
16863
16992
|
const rows = await admitInspection(request.inventory, request.processing, signal, {
|
|
16864
|
-
onFailure
|
|
16865
|
-
failures.push({
|
|
16866
|
-
sessionId: session.id,
|
|
16867
|
-
reason,
|
|
16868
|
-
...sourcePartId === void 0 ? {} : { sourcePartId },
|
|
16869
|
-
...cause === void 0 ? {} : { cause }
|
|
16870
|
-
});
|
|
16871
|
-
},
|
|
16993
|
+
onFailure,
|
|
16872
16994
|
async inspectIdentity(part, adapter, currentSignal, limits) {
|
|
16873
16995
|
const opened = await openSourceCapture(request.captures.get(part.path) ?? fail("ARTIFACT_SOURCE_CHANGED"));
|
|
16874
16996
|
const cleanup = createCleanup();
|
|
@@ -16883,7 +17005,7 @@ async function prepareSessionScans(request, signal) {
|
|
|
16883
17005
|
},
|
|
16884
17006
|
onExclusion: exclude
|
|
16885
17007
|
});
|
|
16886
|
-
const automated = await automatedRoots(rows, families, request, signal);
|
|
17008
|
+
const automated = await automatedRoots(rows, families, request, signal, onFailure);
|
|
16887
17009
|
for (const row of rows) {
|
|
16888
17010
|
const root = families.owners.get(row.session.id)?.id;
|
|
16889
17011
|
if (row.failure || root === void 0 || !automated.has(root)) continue;
|
|
@@ -16974,4 +17096,277 @@ async function verifyPreparedSessionSources(prepared, input, signal) {
|
|
|
16974
17096
|
}
|
|
16975
17097
|
}
|
|
16976
17098
|
//#endregion
|
|
16977
|
-
|
|
17099
|
+
//#region packages/artifact/src/configured/output/session-mask-equivalence.ts
|
|
17100
|
+
const exactMarker = new RegExp("^(?:" + replacementMarkerPattern.source + ")$", "u");
|
|
17101
|
+
function sessionMaskProof(row) {
|
|
17102
|
+
const lineage = row.contributors.map((item) => {
|
|
17103
|
+
const { inputRange, context } = item.kind === "static" ? item.source.mask : item.source;
|
|
17104
|
+
const quote = context.text.slice(inputRange.start - context.start, inputRange.end - context.start);
|
|
17105
|
+
const basis = item.kind === "static" ? [
|
|
17106
|
+
item.source.sourceRecordIndex,
|
|
17107
|
+
item.source.mask.originalPointer,
|
|
17108
|
+
item.source.mask.sourceRange,
|
|
17109
|
+
item.source.mask.inputSha256,
|
|
17110
|
+
item.source.mask.stepId,
|
|
17111
|
+
item.source.mask.node.id,
|
|
17112
|
+
item.source.mask.node.version,
|
|
17113
|
+
item.source.mask.ruleId
|
|
17114
|
+
] : [item.source.pointer];
|
|
17115
|
+
return JSON.stringify([
|
|
17116
|
+
item.kind,
|
|
17117
|
+
item.category,
|
|
17118
|
+
basis,
|
|
17119
|
+
inputRange.start,
|
|
17120
|
+
inputRange.end,
|
|
17121
|
+
quote
|
|
17122
|
+
]);
|
|
17123
|
+
}).sort();
|
|
17124
|
+
const first = row.contributors[0];
|
|
17125
|
+
return {
|
|
17126
|
+
pointer: row.pointer,
|
|
17127
|
+
subject: row.subject,
|
|
17128
|
+
start: row.outputRange.start,
|
|
17129
|
+
end: row.outputRange.end,
|
|
17130
|
+
replacement: row.replacement,
|
|
17131
|
+
lineage: createHash("sha256").update(JSON.stringify([row.category, lineage])).digest("hex"),
|
|
17132
|
+
mayRename: row.subject === "value" && exactMarker.test(row.replacement) && row.contributors.length === 1 && first?.kind === "static" && first.source.sourceRecordIndex !== null && first.source.mask.sourceRange !== null && first.source.mask.originalPointer !== null && first.source.mask.outputPointer === row.pointer && first.source.mask.subject === row.subject && first.source.mask.replacement === row.replacement
|
|
17133
|
+
};
|
|
17134
|
+
}
|
|
17135
|
+
const location = (mask) => JSON.stringify([
|
|
17136
|
+
mask.pointer,
|
|
17137
|
+
mask.subject,
|
|
17138
|
+
mask.start,
|
|
17139
|
+
mask.end
|
|
17140
|
+
]);
|
|
17141
|
+
/** Both ledgers have already been independently joined to their own frozen output by the verifier. */
|
|
17142
|
+
function compareSessionRows(leftText, rightText, leftMasks, rightMasks) {
|
|
17143
|
+
if (leftMasks.length !== rightMasks.length) return null;
|
|
17144
|
+
const rightByLocation = new Map(rightMasks.map((mask) => [location(mask), mask]));
|
|
17145
|
+
if (rightByLocation.size !== rightMasks.length) return null;
|
|
17146
|
+
const changes = /* @__PURE__ */ new Map();
|
|
17147
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
17148
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
17149
|
+
for (const left of leftMasks) {
|
|
17150
|
+
const key = location(left);
|
|
17151
|
+
const right = rightByLocation.get(key);
|
|
17152
|
+
if (!right || left.lineage !== right.lineage) return null;
|
|
17153
|
+
rightByLocation.delete(key);
|
|
17154
|
+
if (left.replacement === right.replacement) continue;
|
|
17155
|
+
if (!left.mayRename || !right.mayRename || left.start < 0 || left.end - left.start !== left.replacement.length || right.replacement.length !== left.replacement.length) return null;
|
|
17156
|
+
const prior = aliases.get(left.replacement);
|
|
17157
|
+
const inverse = reverse.get(right.replacement);
|
|
17158
|
+
if (prior !== void 0 && prior !== right.replacement || inverse !== void 0 && inverse !== left.replacement) return null;
|
|
17159
|
+
aliases.set(left.replacement, right.replacement);
|
|
17160
|
+
reverse.set(right.replacement, left.replacement);
|
|
17161
|
+
const masks = changes.get(left.pointer) ?? [];
|
|
17162
|
+
masks.push(left);
|
|
17163
|
+
changes.set(left.pointer, masks);
|
|
17164
|
+
}
|
|
17165
|
+
if (!aliases.size) return leftText === rightText ? { aliases: [] } : null;
|
|
17166
|
+
const limits = {
|
|
17167
|
+
...defaultLimits,
|
|
17168
|
+
maxRecordBytes: maximumRecordBytes
|
|
17169
|
+
};
|
|
17170
|
+
let tree;
|
|
17171
|
+
try {
|
|
17172
|
+
tree = parseNativeRecord(leftText, limits, new AbortController().signal);
|
|
17173
|
+
} catch {
|
|
17174
|
+
return null;
|
|
17175
|
+
}
|
|
17176
|
+
const changedCount = [...changes.values()].reduce((sum, field) => sum + field.length, 0);
|
|
17177
|
+
function authenticOccurrences(root, destination) {
|
|
17178
|
+
let used = 0;
|
|
17179
|
+
const markers = destination ? reverse : aliases;
|
|
17180
|
+
function check(node, pointer) {
|
|
17181
|
+
if (node.kind === "array") return node.items.every((item, i) => check(item, pointer + "/" + i));
|
|
17182
|
+
if (node.kind === "object") return node.properties.every(({ key, value }) => {
|
|
17183
|
+
for (const found of key.value.matchAll(replacementMarkerPattern)) if (markers.has(found[0])) return false;
|
|
17184
|
+
return check(value, pointer + "/" + key.value.replaceAll("~", "~0").replaceAll("/", "~1"));
|
|
17185
|
+
});
|
|
17186
|
+
if (node.kind !== "string") return true;
|
|
17187
|
+
const expected = new Map((changes.get(pointer) ?? []).map((mask) => [mask.start, mask]));
|
|
17188
|
+
for (const found of node.value.matchAll(replacementMarkerPattern)) {
|
|
17189
|
+
if (!markers.has(found[0])) continue;
|
|
17190
|
+
const mask = expected.get(found.index);
|
|
17191
|
+
if (!mask || (destination ? aliases.get(mask.replacement) : mask.replacement) !== found[0]) return false;
|
|
17192
|
+
expected.delete(found.index);
|
|
17193
|
+
used++;
|
|
17194
|
+
}
|
|
17195
|
+
return expected.size === 0;
|
|
17196
|
+
}
|
|
17197
|
+
return check(root, "") && used === changedCount;
|
|
17198
|
+
}
|
|
17199
|
+
if (!authenticOccurrences(tree, false)) return null;
|
|
17200
|
+
for (const winner of aliases.values()) if (aliases.has(winner)) return null;
|
|
17201
|
+
let replaced = 0;
|
|
17202
|
+
const renamed = leftText.replace(replacementMarkerPattern, (marker) => {
|
|
17203
|
+
const mapped = aliases.get(marker);
|
|
17204
|
+
if (!mapped) return marker;
|
|
17205
|
+
replaced++;
|
|
17206
|
+
return mapped;
|
|
17207
|
+
});
|
|
17208
|
+
if (changedCount !== replaced || renamed !== rightText) return null;
|
|
17209
|
+
try {
|
|
17210
|
+
if (!authenticOccurrences(parseNativeRecord(rightText, limits, new AbortController().signal), true)) return null;
|
|
17211
|
+
} catch {
|
|
17212
|
+
return null;
|
|
17213
|
+
}
|
|
17214
|
+
return { aliases: [...aliases] };
|
|
17215
|
+
}
|
|
17216
|
+
//#endregion
|
|
17217
|
+
//#region packages/artifact/src/configured/output/session-source-prefix.ts
|
|
17218
|
+
/**
|
|
17219
|
+
* Both parts come from the verified frozen primary. The caller locates longerSource through
|
|
17220
|
+
* its base source binding. A copied log may have a different path or inode from its ancestor.
|
|
17221
|
+
*/
|
|
17222
|
+
async function sessionSourcePrefix(short, long, longerSource, signal) {
|
|
17223
|
+
checkAbort(signal);
|
|
17224
|
+
if (!short.native.sessionId?.trim() || !["main", "worker"].includes(short.native.role) || !isDeepStrictEqual(short.native, long.native) || short.source.representation !== long.source.representation || short.source.byteLength > long.source.byteLength || short.recordCount > long.recordCount || short.retainedRecordCount > long.retainedRecordCount) return false;
|
|
17225
|
+
if (short.source.byteLength === long.source.byteLength) return short.source.sha256 === long.source.sha256 && short.recordCount === long.recordCount;
|
|
17226
|
+
if (long.source.representation !== "jsonl" || !longerSource || longerSource.representation !== "jsonl" || longerSource.snapshot.size !== long.source.byteLength || short.source.byteLength === 0 || short.recordCount === long.recordCount) return false;
|
|
17227
|
+
try {
|
|
17228
|
+
checkNativeEvidence(longerSource, long.native);
|
|
17229
|
+
const input = await openConfiguredSource(longerSource, signal, void 0, "stable-prefix");
|
|
17230
|
+
try {
|
|
17231
|
+
const prefix = createHash("sha256");
|
|
17232
|
+
let remaining = short.source.byteLength;
|
|
17233
|
+
let endsAtRecord = false;
|
|
17234
|
+
for await (const chunk of input.chunks) {
|
|
17235
|
+
const take = Math.min(remaining, chunk.byteLength);
|
|
17236
|
+
if (take === 0) continue;
|
|
17237
|
+
prefix.update(chunk.subarray(0, take));
|
|
17238
|
+
remaining -= take;
|
|
17239
|
+
if (remaining === 0) endsAtRecord = chunk[take - 1] === 10;
|
|
17240
|
+
}
|
|
17241
|
+
const full = await input.finish();
|
|
17242
|
+
return remaining === 0 && endsAtRecord && prefix.digest("hex") === short.source.sha256 && full.sha256 === long.source.sha256 && full.byteLength === long.source.byteLength;
|
|
17243
|
+
} finally {
|
|
17244
|
+
await input.close();
|
|
17245
|
+
}
|
|
17246
|
+
} catch (error) {
|
|
17247
|
+
checkAbort(signal);
|
|
17248
|
+
if ([
|
|
17249
|
+
"ARTIFACT_SOURCE_CHANGED",
|
|
17250
|
+
"ARTIFACT_SOURCE_MISSING",
|
|
17251
|
+
"ARTIFACT_SOURCE_UNSAFE",
|
|
17252
|
+
"ARTIFACT_SOURCE_UNREADABLE",
|
|
17253
|
+
"ARTIFACT_SOURCE_TRUNCATED"
|
|
17254
|
+
].includes(safeError(error).message)) return false;
|
|
17255
|
+
throw error;
|
|
17256
|
+
}
|
|
17257
|
+
}
|
|
17258
|
+
//#endregion
|
|
17259
|
+
//#region packages/artifact/src/configured/output/session-extension.ts
|
|
17260
|
+
/** Choose an entire already-approved variant. No edited or reconstructed bytes enter transport. */
|
|
17261
|
+
async function sessionExtensions(input, signal) {
|
|
17262
|
+
const verified = await checkFrozenOutput(input.primary, signal);
|
|
17263
|
+
const { manifest } = verified;
|
|
17264
|
+
const sessions = new Map(manifest.sessions.map((session) => [session.id, session]));
|
|
17265
|
+
const groups = input.groups.map((group) => group.map((id) => sessions.get(id) ?? fail("ARTIFACT_IDENTITY_MISMATCH")));
|
|
17266
|
+
const paths = new Set(groups.flat().flatMap((session) => session.parts.map((part) => part.dataPath)));
|
|
17267
|
+
const masks = /* @__PURE__ */ new Map();
|
|
17268
|
+
for await (const row of readLogicalJourneyFinalMasks({
|
|
17269
|
+
ledger: input.ledger,
|
|
17270
|
+
primary: input.primary
|
|
17271
|
+
}, signal, paths)) {
|
|
17272
|
+
const entry = masks.get(row.entryPath) ?? /* @__PURE__ */ new Map();
|
|
17273
|
+
if (!masks.has(row.entryPath)) masks.set(row.entryPath, entry);
|
|
17274
|
+
const list = entry.get(row.recordIndex) ?? [];
|
|
17275
|
+
list.push(sessionMaskProof(row));
|
|
17276
|
+
entry.set(row.recordIndex, list);
|
|
17277
|
+
}
|
|
17278
|
+
const archive = await openCheckedOutput(input.primary, verified.checked, signal);
|
|
17279
|
+
const omitted = /* @__PURE__ */ new Set();
|
|
17280
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
17281
|
+
try {
|
|
17282
|
+
for (const group of groups) {
|
|
17283
|
+
const score = (s) => s.parts.reduce((sum, p) => sum + p.retainedRecordCount, 0);
|
|
17284
|
+
const sorted = group.toSorted((a, b) => score(b) - score(a) || Date.parse(input.lastAt(b.id)) - Date.parse(input.lastAt(a.id)) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
17285
|
+
const winner = sorted[0];
|
|
17286
|
+
if (!winner) continue;
|
|
17287
|
+
for (const shorter of sorted.slice(1)) {
|
|
17288
|
+
if (shorter.workspaceId !== winner.workspaceId || shorter.harness !== winner.harness || shorter.treatmentId !== winner.treatmentId || shorter.sourceSessionId !== winner.sourceSessionId || shorter.parts.length !== winner.parts.length || Date.parse(input.lastAt(shorter.id)) > Date.parse(input.lastAt(winner.id))) return null;
|
|
17289
|
+
for (const [index, part] of shorter.parts.entries()) {
|
|
17290
|
+
const long = winner.parts[index];
|
|
17291
|
+
if (!long || part.retainedRecordCount > long.retainedRecordCount || !await sessionSourcePrefix(part, long, input.sourceFor(winner.id, long.sourceId), signal)) return null;
|
|
17292
|
+
if (!await compareParts(archive, manifest, part, long, masks, aliases, signal)) return null;
|
|
17293
|
+
}
|
|
17294
|
+
omitted.add(shorter.id);
|
|
17295
|
+
}
|
|
17296
|
+
}
|
|
17297
|
+
for (const value of aliases.values()) if (aliases.has(value)) return null;
|
|
17298
|
+
await archive.fence();
|
|
17299
|
+
return {
|
|
17300
|
+
omitted,
|
|
17301
|
+
retired: new Set(aliases.keys())
|
|
17302
|
+
};
|
|
17303
|
+
} finally {
|
|
17304
|
+
await archive.close();
|
|
17305
|
+
}
|
|
17306
|
+
}
|
|
17307
|
+
async function compareParts(archive, manifest, short, long, masks, aliases, signal) {
|
|
17308
|
+
const cleanup = createCleanup();
|
|
17309
|
+
const spools = [];
|
|
17310
|
+
try {
|
|
17311
|
+
for (const part of [short, long]) {
|
|
17312
|
+
const entry = archive.entries.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17313
|
+
const expected = manifest.entries.find((d) => d.entryPath === part.dataPath) ?? fail("ARTIFACT_INVALID_MANIFEST");
|
|
17314
|
+
spools.push(await spoolFacts(entry, expected, signal));
|
|
17315
|
+
}
|
|
17316
|
+
const [a, b] = spools;
|
|
17317
|
+
if (!a || !b) return fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17318
|
+
let count = 0;
|
|
17319
|
+
for await (const row of a.lines) {
|
|
17320
|
+
const match = await b.lines.next();
|
|
17321
|
+
if (match.done) return false;
|
|
17322
|
+
const proof = compareSessionRows(row, match.value, masks.get(short.dataPath)?.get(count) ?? [], masks.get(long.dataPath)?.get(count) ?? []);
|
|
17323
|
+
if (!proof) return false;
|
|
17324
|
+
for (const [old, chosen] of proof.aliases) {
|
|
17325
|
+
if (aliases.has(old) && aliases.get(old) !== chosen) return false;
|
|
17326
|
+
aliases.set(old, chosen);
|
|
17327
|
+
}
|
|
17328
|
+
count++;
|
|
17329
|
+
}
|
|
17330
|
+
if (count !== short.retainedRecordCount) return false;
|
|
17331
|
+
for await (const _ of b.lines) count++;
|
|
17332
|
+
return count === long.retainedRecordCount;
|
|
17333
|
+
} catch (error) {
|
|
17334
|
+
cleanup.failed(error);
|
|
17335
|
+
throw error;
|
|
17336
|
+
} finally {
|
|
17337
|
+
await cleanup.run(...spools.flatMap((s) => [() => s.lines.return(void 0), () => s.close()]));
|
|
17338
|
+
}
|
|
17339
|
+
}
|
|
17340
|
+
/** Matches complete decoded marker spellings, including Unicode escape spellings in native JSON. */
|
|
17341
|
+
function refersToRetiredMarker(text, retired) {
|
|
17342
|
+
let candidate = text;
|
|
17343
|
+
for (let depth = 0; /\\u[\da-f]{4}/iu.test(candidate); depth++) {
|
|
17344
|
+
if (depth >= 8) return true;
|
|
17345
|
+
candidate = candidate.replace(/\\+u([\da-f]{4})/giu, (_, digits) => String.fromCharCode(Number.parseInt(digits, 16)));
|
|
17346
|
+
}
|
|
17347
|
+
for (const match of candidate.matchAll(replacementMarkerPattern)) if (retired.has(match[0])) return true;
|
|
17348
|
+
return false;
|
|
17349
|
+
}
|
|
17350
|
+
/** Search all kept uploaded fields of a confirmed Work before retiring an alias in another session. */
|
|
17351
|
+
async function hasRetiredSessionMarker(primary, omitted, retired, signal) {
|
|
17352
|
+
if (!retired.size) return false;
|
|
17353
|
+
const verified = await checkFrozenOutput(primary, signal);
|
|
17354
|
+
const archive = await openCheckedOutput(primary, verified.checked, signal);
|
|
17355
|
+
try {
|
|
17356
|
+
const entries = new Map(verified.manifest.entries.map((entry) => [entry.entryPath, entry]));
|
|
17357
|
+
for (const workspace of verified.manifest.sourceWorkspaces) if (refersToRetiredMarker(await readOutputJson(archive.entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE"), entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE"), signal), retired)) return true;
|
|
17358
|
+
for (const session of verified.manifest.sessions) {
|
|
17359
|
+
if (omitted.has(session.id)) continue;
|
|
17360
|
+
for (const part of session.parts) {
|
|
17361
|
+
const entry = archive.entries.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17362
|
+
const expected = entries.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17363
|
+
for await (const row of entryLines(entry, expected, signal)) if (refersToRetiredMarker(row, retired)) return true;
|
|
17364
|
+
}
|
|
17365
|
+
}
|
|
17366
|
+
return false;
|
|
17367
|
+
} finally {
|
|
17368
|
+
await archive.close();
|
|
17369
|
+
}
|
|
17370
|
+
}
|
|
17371
|
+
//#endregion
|
|
17372
|
+
export { decodeZstd as $, captureLogicalJourneySources as A, defaultParallelism as B, writePrivateReviewPayload as C, createCollectionArtifacts as D, readConfiguredSearchFields as E, parseCollectionWorkspaceSummary as F, readLogicalJourneyFinalMasks as G, parallelismLimits as H, createSharedSessionPool as I, staticMaskCategory as J, readConfiguredOutputInfo as K, SessionWorkerError as L, renderJobDigest as M, runConfiguredSessionJob as N, checkReusableBundle as O, readCollectionIndex as P, createInspectionProcessor as Q, sessionWorkerFailure as R, writeLogicalJourneyBase as S, readOriginalSearchFields as T, writeLogicalJourneyOutput as U, gitSeedsProvider as V, privateJourneyDirectory as W, listAgentSetup as X, readWorkspacePair as Y, createConfiguredPreviewStream as Z, captureConfiguredSessionJob as _, prepareSessionScans as a, makePrivateDirectory as at, readStaticSessionMasks as b, createWorkPieces as c, windowsOwnerOnly as ct, scanPreparedSession as d, createTemporary as et, runConfiguredScanJob as f, openConfiguredUpload as g, configuredSessionUploads as h, verifyPreparedSessionSources as i, exclusiveLock as it, capturedJourneyScope as j, prepareCollectionProduction as k, readSessionScanFields as l, isWindowsAclFailure as lt, writeOutputShard as m, sessionExtensions as n, createCleanup as nt, buildWorkScanBatches as o, openPrivateFile as ot, verifyOutputShard as p, processJourneyMetadataFields as q, preparedScanConfiguration as r, safeError as rt, scanReviewFields as s, restrictToOwner as st, hasRetiredSessionMarker as t, removeNamedTemporarySpools as tt, readSessionScanRecords as u, windowsAclCodes as ut, readCapturedOriginalRows as v, readPrivateReviewPayload as w, staticSessionJobs as x, processJourneyMetadata as y, privateCollectionDirectory as z };
|