sortie-dogs 0.12.23 → 0.12.24
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/dist/asset-version.d.ts +1 -1
- package/dist/asset-version.js +1 -1
- package/dist/plugin/declared-artifacts.d.ts +4 -1
- package/dist/plugin/declared-artifacts.js +23 -3
- package/dist/plugin/mission-review.d.ts +1 -0
- package/dist/plugin/mission-review.js +17 -6
- package/dist/plugin/profiled.js +6 -3
- package/package.json +1 -1
package/dist/asset-version.d.ts
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export declare const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export declare const V010_RUNTIME_ASSET_VERSION = "0.12.
|
|
6
|
+
export declare const V010_RUNTIME_ASSET_VERSION = "0.12.24-review-evidence-recovery-v1";
|
|
7
7
|
export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION;
|
package/dist/asset-version.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export const V010_RUNTIME_ASSET_VERSION = "0.12.
|
|
6
|
+
export const V010_RUNTIME_ASSET_VERSION = "0.12.24-review-evidence-recovery-v1";
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/** Explicit external artifacts are filesystem inputs, not Git pathspecs. Stream complete bytes;
|
|
2
2
|
* previews are bounded independently. Follow package links only inside a declared physical root.
|
|
3
3
|
*/
|
|
4
|
-
export declare function declaredArtifacts(paths: readonly string[], previewLimit?: number
|
|
4
|
+
export declare function declaredArtifacts(paths: readonly string[], previewLimit?: number, options?: {
|
|
5
|
+
reportUnreadableDirectories?: boolean;
|
|
6
|
+
}): Promise<{
|
|
5
7
|
entries: (readonly [string, string, (string | undefined)?])[];
|
|
6
8
|
excerpt: string;
|
|
7
9
|
truncated: boolean;
|
|
10
|
+
unreadable: string[];
|
|
8
11
|
}>;
|
|
@@ -9,7 +9,7 @@ const within = (root, path) => {
|
|
|
9
9
|
/** Explicit external artifacts are filesystem inputs, not Git pathspecs. Stream complete bytes;
|
|
10
10
|
* previews are bounded independently. Follow package links only inside a declared physical root.
|
|
11
11
|
*/
|
|
12
|
-
export async function declaredArtifacts(paths, previewLimit = 0) {
|
|
12
|
+
export async function declaredArtifacts(paths, previewLimit = 0, options = {}) {
|
|
13
13
|
const roots = [...new Set(paths.map(path => resolve(path)))].sort();
|
|
14
14
|
const physical = await Promise.all(roots.map(path => realpath(path).catch((error) => {
|
|
15
15
|
if (error.code === "ENOENT")
|
|
@@ -18,6 +18,7 @@ export async function declaredArtifacts(paths, previewLimit = 0) {
|
|
|
18
18
|
})));
|
|
19
19
|
const entries = [];
|
|
20
20
|
const excerpts = [];
|
|
21
|
+
const unreadable = [];
|
|
21
22
|
let remaining = previewLimit, truncated = false;
|
|
22
23
|
const visited = new Set();
|
|
23
24
|
const visit = async (path, ancestors) => {
|
|
@@ -47,7 +48,26 @@ export async function declaredArtifacts(paths, previewLimit = 0) {
|
|
|
47
48
|
if (metadata.isDirectory()) {
|
|
48
49
|
entries.push([label, "directory", canonical]);
|
|
49
50
|
const next = new Set([...ancestors, canonical]);
|
|
50
|
-
|
|
51
|
+
let children;
|
|
52
|
+
try {
|
|
53
|
+
children = await readdir(path);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (!options.reportUnreadableDirectories || !["EACCES", "EPERM"].includes(error.code ?? ""))
|
|
57
|
+
throw error;
|
|
58
|
+
entries.push([label, `unreadable:${error.code}`, canonical]);
|
|
59
|
+
unreadable.push(label);
|
|
60
|
+
const notice = `\n--- external directory: ${label} ---\n[not inspected: permission denied; select specific result files as review evidence]\n`;
|
|
61
|
+
const bytes = Buffer.from(notice), bounded = bytes.subarray(0, remaining);
|
|
62
|
+
if (bounded.length) {
|
|
63
|
+
excerpts.push(bounded.toString("utf8"));
|
|
64
|
+
remaining -= bounded.length;
|
|
65
|
+
}
|
|
66
|
+
if (bounded.length < bytes.length)
|
|
67
|
+
truncated = true;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const child of children.sort())
|
|
51
71
|
await visit(join(path, child), next);
|
|
52
72
|
return;
|
|
53
73
|
}
|
|
@@ -76,5 +96,5 @@ export async function declaredArtifacts(paths, previewLimit = 0) {
|
|
|
76
96
|
};
|
|
77
97
|
for (const path of roots)
|
|
78
98
|
await visit(path, new Set());
|
|
79
|
-
return { entries, excerpt: excerpts.join(""), truncated };
|
|
99
|
+
return { entries, excerpt: excerpts.join(""), truncated, unreadable };
|
|
80
100
|
}
|
|
@@ -13,4 +13,5 @@ export declare function completedMissionReviewPrompts(mission: OperatorMission |
|
|
|
13
13
|
export declare function missionReviewSource(directory: string, run: OperatorState, evidence?: readonly MissionEvidenceExcerpt[], baseline?: string, priorScope?: MissionReviewScope): Promise<{
|
|
14
14
|
fingerprint: string;
|
|
15
15
|
excerpt: string;
|
|
16
|
+
truncatedEvidence: string[];
|
|
16
17
|
}>;
|
|
@@ -214,9 +214,11 @@ export async function missionReviewSource(directory, run, evidence = [], baselin
|
|
|
214
214
|
if (needsNotice[index])
|
|
215
215
|
selected += truncated(item.entry);
|
|
216
216
|
}
|
|
217
|
+
const truncatedEvidence = focused.flatMap(({ entry }, index) => needsNotice[index] ? [`${entry.path}:${entry.offset}`] : []);
|
|
217
218
|
if (writes.length === 0)
|
|
218
219
|
return { fingerprint: `sha256:${hash.digest("hex")}`,
|
|
219
|
-
excerpt: selected + "[Read-only units: no declared output files. Review the supplied observations, traces and validation evidence.]"
|
|
220
|
+
excerpt: selected + "[Read-only units: no declared output files. Review the supplied observations, traces and validation evidence.]",
|
|
221
|
+
truncatedEvidence };
|
|
220
222
|
// The shared dependency environment is local tooling, never reviewed or pinned source.
|
|
221
223
|
const external = [], local = [];
|
|
222
224
|
for (const path of writes) {
|
|
@@ -230,12 +232,15 @@ export async function missionReviewSource(directory, run, evidence = [], baselin
|
|
|
230
232
|
const git = async (args) => (await exec("git", args, { cwd: directory, maxBuffer: 8 * 1024 * 1024 })).stdout;
|
|
231
233
|
const names = local.length ? await git(["ls-files", "-z", "--cached", "--others", "--exclude-standard", "--", ...scopes]) : "";
|
|
232
234
|
const untracked = new Set((local.length ? await git(["ls-files", "-z", "--others", "--exclude-standard", "--", ...scopes]) : "").split("\0").filter(Boolean));
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
|
|
235
|
+
// Go's ignored in-project caches may be writable during validation but are not candidate
|
|
236
|
+
// output. Keep every other ignored declared output visible and fingerprinted, including
|
|
237
|
+
// directories of generated artifacts; focused references can still pin a cache file.
|
|
238
|
+
const ignored = local.length ? await git(["ls-files", "-z", "--others", "--ignored", "--exclude-standard", "--",
|
|
239
|
+
...scopes, ...[".gocache", ".gomodcache", ".gopath"].map(path => `:(exclude)${path}`)]) : "";
|
|
236
240
|
for (const path of ignored.split("\0").filter(Boolean))
|
|
237
241
|
untracked.add(path);
|
|
238
242
|
const omitted = [];
|
|
243
|
+
const unreadable = [];
|
|
239
244
|
let diff = "";
|
|
240
245
|
if (local.length && baseline) {
|
|
241
246
|
// HEAD-only diffs are empty once the Worker commits. Show bounded changes from the
|
|
@@ -305,13 +310,19 @@ export async function missionReviewSource(directory, run, evidence = [], baselin
|
|
|
305
310
|
}
|
|
306
311
|
}
|
|
307
312
|
if (external.length) {
|
|
308
|
-
|
|
313
|
+
// A declared write scope can also be a host-managed runtime directory (e.g. Docker's data root).
|
|
314
|
+
// Do not make review depend on listing it; record the missing coverage instead. Protected
|
|
315
|
+
// validation still requires readable outputs and does not use this review-only option.
|
|
316
|
+
const artifacts = await declaredArtifacts(external, Math.max(1, 24_000 - Buffer.byteLength(excerpt)), { reportUnreadableDirectories: true });
|
|
309
317
|
hash.update(JSON.stringify(artifacts.entries));
|
|
310
318
|
excerpt += artifacts.excerpt;
|
|
311
319
|
if (artifacts.truncated)
|
|
312
320
|
omitted.push("external artifacts");
|
|
321
|
+
unreadable.push(...artifacts.unreadable);
|
|
313
322
|
}
|
|
314
323
|
const bytes = Buffer.from(excerpt);
|
|
315
324
|
return { fingerprint: `sha256:${hash.digest("hex")}`, excerpt: (bytes.length > 24_000 ? bytes.subarray(0, 24_000).toString("utf8") : excerpt) +
|
|
316
|
-
(bytes.length > 24_000 || omitted.length ? `\n[EXCERPT TRUNCATED: ${omitted.slice(0, 20).join(", ")}; supply focused traces for missing sections, not another implementation unit]` : "")
|
|
325
|
+
(bytes.length > 24_000 || omitted.length ? `\n[EXCERPT TRUNCATED: ${omitted.slice(0, 20).join(", ")}; supply focused traces for missing sections, not another implementation unit]` : "") +
|
|
326
|
+
(unreadable.length ? `\n[UNINSPECTED EXTERNAL DIRECTORIES: ${unreadable.slice(0, 20).join(", ")}; select specific result files as review evidence]` : ""),
|
|
327
|
+
truncatedEvidence };
|
|
317
328
|
}
|
package/dist/plugin/profiled.js
CHANGED
|
@@ -666,7 +666,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
666
666
|
if (mission.phase === "submitted" && mission.submission?.status === "blocked" &&
|
|
667
667
|
run?.units.some(unit => unit.status === "running")) {
|
|
668
668
|
return { ...packet, next_action: `If the native Worker Task is still active, wait for it; do not start a duplicate. ` +
|
|
669
|
-
`If
|
|
669
|
+
`If the parent Coordinator Task has finished or was interrupted, and the user chose to stop/replan, Operator root (not Coordinator): ` +
|
|
670
670
|
`call ${profile.toolPrefix}cancel_operator with reason=plain to stop owned children, then ` +
|
|
671
671
|
`${profile.toolPrefix}start_mission with intent=replace and the saved requirements. ` +
|
|
672
672
|
`Use the returned Coordinator Task; the previous Mission is archived and cumulative spend is retained.` };
|
|
@@ -1825,7 +1825,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
1825
1825
|
return declareMissionUnits(root, context.sessionID, mission, units, args.reason);
|
|
1826
1826
|
});
|
|
1827
1827
|
} };
|
|
1828
|
-
tools[reviewMission] = { description: "Coordinator: prepare the independent Reviewer task from current source, requirements and observed checks. Supply risk_tags (empty only for genuinely low risk) and concise criterion-level changed-code/test traces. Host supplies diff, IDs, manifest, mappings and evidence;
|
|
1828
|
+
tools[reviewMission] = { description: "Coordinator: prepare the independent Reviewer task from current source, requirements and observed checks. Supply risk_tags (empty only for genuinely low risk) and concise criterion-level changed-code/test traces. Host supplies diff, IDs, manifest, mappings and evidence; if truncated_evidence is returned, narrow those ranges before dispatching the Reviewer. Keep candidate lineage across corrections. A low-risk skip is recorded, never inferred from a missing review.",
|
|
1829
1829
|
args: { risk_tags: { type: "array", items: { type: "string", enum: SOURCE_REVIEW_RISK_TAGS } },
|
|
1830
1830
|
evidence: { type: "array", maxItems: 6, items: { type: "object", additionalProperties: false,
|
|
1831
1831
|
properties: { path: { type: "string" }, offset: { type: "integer", minimum: 1 }, limit: { type: "integer", minimum: 1, maximum: 200 } },
|
|
@@ -1881,7 +1881,10 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
1881
1881
|
...(initialPrompt ? { initialPrompt } : {}),
|
|
1882
1882
|
...(mission.review?.evidenceGapReviews ? { evidenceGapReviews: mission.review.evidenceGapReviews } : {}) };
|
|
1883
1883
|
});
|
|
1884
|
-
return JSON.stringify(task ? { status: "review-required", task: missionReviewTask(reviewed)
|
|
1884
|
+
return JSON.stringify(task ? { status: "review-required", task: missionReviewTask(reviewed),
|
|
1885
|
+
...(source.truncatedEvidence.length ? { truncated_evidence: source.truncatedEvidence,
|
|
1886
|
+
next_action: "Narrow these focused evidence ranges with review_mission before dispatching the Reviewer; no Worker or new validation is needed." } : {}) }
|
|
1887
|
+
: { status: "skipped-low-risk" });
|
|
1885
1888
|
} };
|
|
1886
1889
|
async function assertMissionReview(root, mission) {
|
|
1887
1890
|
const run = await operators.required(root), review = mission.review;
|